OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::InterlockingGenerator Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp>

Collaboration diagram for Slic3r::InterlockingGenerator:

Static Public Member Functions

static void generate_interlocking_structure (PrintObject *print_object, const std::function< void()> &throw_on_cancel)

Private Member Functions

void generateInterlockingStructure () const
 InterlockingGenerator (PrintObject &print_object, const size_t region_a_index, const size_t region_b_index, const coord_t beam_width, const coord_t boundary_avoidance, const float rotation, const Vec3crd &cell_size, const coord_t beam_layer_count, const DilationKernel &interface_dilation, const DilationKernel &air_dilation, const bool air_filtering, const std::function< void()> &throw_on_cancel)
std::pair< ExPolygons, ExPolygons > growBorderAreasPerpendicular (const ExPolygons &a, const ExPolygons &b, const coord_t &detect) const
void handleThinAreas (const std::unordered_set< GridPoint3 > &has_all_meshes) const
std::vector< std::unordered_set< GridPoint3 > > getShellVoxels (const DilationKernel &kernel) const
void addBoundaryCells (const std::vector< ExPolygons > &layers, const DilationKernel &kernel, std::unordered_set< GridPoint3 > &cells) const
std::vector< ExPolygons > computeUnionedVolumeRegions () const
std::vector< std::vector< ExPolygons > > generateMicrostructure () const
void applyMicrostructureToOutlines (const std::unordered_set< GridPoint3 > &cells, const std::vector< ExPolygons > &layer_regions) const

Private Attributes

PrintObject & print_object
const size_t region_a_index
const size_t region_b_index
const coord_t beam_width
const coord_t boundary_avoidance
const VoxelUtils vu
const float rotation
const Vec3crd cell_size
const coord_t beam_layer_count
const DilationKernel interface_dilation
const DilationKernel air_dilation
const bool air_filtering
const std::function< void()> & throw_on_cancel

Static Private Attributes

static const coord_t ignored_gap_ = 100u
 Distance between models to be considered next to each other so that an interlocking structure will be generated there.

Detailed Description

Class for generating an interlocking structure between two adjacent models of a different extruder.

The structure consists of horizontal beams of the two materials interlaced. In the z direction the direction of these beams is alternated with 90*.

Example with two materials # and O Even beams: Odd beams:

##OO##OO

OOOOOO ##OO##OO

##OO##OO

OOOOOO ##OO##OO

One material of a single cell of the structure looks like this: .-*-. .-* -. |-. -. | *-. *-. .- -. *-. *-. .- -. *-. .-| .-* .-* -. *-.- | |*-. .-* .-* -. | .- | -.- .-* -|- -. | .- -|-

We set up a voxel grid of (2*beam_w,2*beam_w,2*beam_h) and mark all the voxels which contain both meshes. We then remove all voxels which also contain air, so that the interlocking pattern will not be visible from the outside. We then generate and combine the polygons for each voxel and apply those areas to the outlines ofthe meshes.

Constructor & Destructor Documentation

◆ InterlockingGenerator()

Slic3r::InterlockingGenerator::InterlockingGenerator ( PrintObject & print_object,
const size_t region_a_index,
const size_t region_b_index,
const coord_t beam_width,
const coord_t boundary_avoidance,
const float rotation,
const Vec3crd & cell_size,
const coord_t beam_layer_count,
const DilationKernel & interface_dilation,
const DilationKernel & air_dilation,
const bool air_filtering,
const std::function< void()> & throw_on_cancel )
inlineprivate

Private class for storing some variables used in the computation of the interlocking structure between two meshes.

Parameters
region_a_indexThe first region
region_b_indexThe second region
rotationThe angle by which to rotate the interlocking pattern
cell_sizeThe size of a voxel cell in (coord_t, coord_t, layer_count)
beam_layer_countThe number of layers for the height of the beams
interface_dilationThe thicknening kernel for the interface
air_dilationThe thickening kernel applied to air so that cells near the outside of the model won't be generated
air_filteringWhether to fully remove all of the interlocking cells which would be visible on the outside (i.e. touching air). If no air filtering then those cells will be cut off in the middle of a beam.
94 , vu(cell_size)
102 {}
const DilationKernel air_dilation
Definition InterlockingGenerator.hpp:175
const size_t region_a_index
Definition InterlockingGenerator.hpp:164
const VoxelUtils vu
Definition InterlockingGenerator.hpp:169
const float rotation
Definition InterlockingGenerator.hpp:171
const Vec3crd cell_size
Definition InterlockingGenerator.hpp:172
const DilationKernel interface_dilation
Definition InterlockingGenerator.hpp:174
const size_t region_b_index
Definition InterlockingGenerator.hpp:165
const coord_t beam_width
Definition InterlockingGenerator.hpp:166
const coord_t boundary_avoidance
Definition InterlockingGenerator.hpp:167
const coord_t beam_layer_count
Definition InterlockingGenerator.hpp:173
const bool air_filtering
Definition InterlockingGenerator.hpp:178
const std::function< void()> & throw_on_cancel
Definition InterlockingGenerator.hpp:180
PrintObject & print_object
Definition InterlockingGenerator.hpp:163

References air_dilation, air_filtering, beam_layer_count, beam_width, boundary_avoidance, cell_size, interface_dilation, print_object, region_a_index, region_b_index, rotation, throw_on_cancel, and vu.

Referenced by generate_interlocking_structure().

Here is the caller graph for this function:

Member Function Documentation

◆ addBoundaryCells()

void Slic3r::InterlockingGenerator::addBoundaryCells ( const std::vector< ExPolygons > & layers,
const DilationKernel & kernel,
std::unordered_set< GridPoint3 > & cells ) const
private

Compute the voxels overlapping with the shell of some layers. This includes the walls, but also top/bottom skin.

Parameters
layersThe layer outlines for which to compute the shell voxels
kernelThe dilation kernel to give the returned voxel shell more thickness
[out]cellsThe output cells which elong to the shell
224{
225 auto voxel_emplacer = [this, &cells](GridPoint3 p) {
226 this->throw_on_cancel();
227 if (p.z() < 0) {
228 return true;
229 }
230 cells.emplace(p);
231 return true;
232 };
233
234 for (size_t layer_nr = 0; layer_nr < layers.size(); layer_nr++) {
235 const coord_t z = static_cast<coord_t>(layer_nr);
236 vu.walkDilatedPolygons(layers[layer_nr], z, kernel, voxel_emplacer);
237 ExPolygons skin = layers[layer_nr];
238 if (layer_nr > 0) {
239 skin = xor_ex(skin, layers[layer_nr - 1]);
240 }
241 skin = opening_ex(skin, cell_size.x() / 2.f); // remove superfluous small areas, which would anyway be included because of walkPolygons
242 vu.walkDilatedAreas(skin, z, kernel, voxel_emplacer);
243 }
244}
int64_t coord_t
Definition libslic3r.h:48
Slic3r::ExPolygons opening_ex(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:447
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:20
Vec3crd GridPoint3
Definition VoxelUtils.hpp:20
Slic3r::ExPolygons xor_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:1029

References cell_size, Slic3r::opening_ex(), throw_on_cancel, vu, and Slic3r::xor_ex().

Referenced by generateInterlockingStructure(), and getShellVoxels().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ applyMicrostructureToOutlines()

void Slic3r::InterlockingGenerator::applyMicrostructureToOutlines ( const std::unordered_set< GridPoint3 > & cells,
const std::vector< ExPolygons > & layer_regions ) const
private

Change the outlines of the meshes with the computed interlocking structure.

Parameters
cellsThe cells where we want to apply the interlocking structure.
layer_regionsThe total volume of the two meshes combined (and small gaps closed)
296{
297 std::vector<std::vector<ExPolygons>> cell_area_per_mesh_per_layer = generateMicrostructure();
298
299 const float unapply_rotation = -rotation;
300 const size_t max_layer_count = print_object.layer_count();
301
302 std::vector<ExPolygons> structure_per_layer[2]; // for each mesh the structure on each layer
303
304 // Every `beam_layer_count` number of layers are combined to an interlocking beam layer
305 // to store these we need ceil(max_layer_count / beam_layer_count) of these layers
306 // the formula is rewritten as (max_layer_count + beam_layer_count - 1) / beam_layer_count, so it works for integer division
307 size_t num_interlocking_layers = (max_layer_count + static_cast<size_t>(beam_layer_count) - 1ul) /
308 static_cast<size_t>(beam_layer_count);
309 structure_per_layer[0].resize(num_interlocking_layers);
310 structure_per_layer[1].resize(num_interlocking_layers);
311
312 // Only compute cell structure for half the layers, because since our beams are two layers high, every odd layer of the structure will
313 // be the same as the layer below.
314 for (const GridPoint3& grid_loc : cells) {
315 Vec3crd bottom_corner = vu.toLowerCorner(grid_loc);
316 for (size_t mesh_idx = 0; mesh_idx < 2; mesh_idx++) {
317 for (size_t layer_nr = bottom_corner.z(); layer_nr < bottom_corner.z() + cell_size.z() && layer_nr < max_layer_count;
318 layer_nr += beam_layer_count) {
319 ExPolygons areas_here = cell_area_per_mesh_per_layer[static_cast<size_t>(layer_nr / beam_layer_count) %
320 cell_area_per_mesh_per_layer.size()][mesh_idx];
321 for (auto & here : areas_here) {
322 here.translate(bottom_corner.x(), bottom_corner.y());
323 }
324 expolygons_append(structure_per_layer[mesh_idx][static_cast<size_t>(layer_nr / beam_layer_count)], areas_here);
325 }
326 }
327 }
328
329 for (size_t mesh_idx = 0; mesh_idx < 2; mesh_idx++) {
330 for (size_t layer_nr = 0; layer_nr < structure_per_layer[mesh_idx].size(); layer_nr++) {
331 ExPolygons& layer_structure = structure_per_layer[mesh_idx][layer_nr];
332 layer_structure = union_ex(layer_structure);
333 expolygons_rotate(layer_structure, unapply_rotation);
334 }
335 }
336
337 for (size_t region_idx = 0; region_idx < 2; region_idx++) {
338 const size_t region = (region_idx == 0) ? region_a_index : region_b_index;
339 for (size_t layer_nr = 0; layer_nr < max_layer_count; layer_nr++) {
341 ExPolygons layer_outlines = layer_regions[layer_nr];
342 expolygons_rotate(layer_outlines, unapply_rotation);
343
344 const ExPolygons areas_here = intersection_ex(structure_per_layer[region_idx][layer_nr / static_cast<size_t>(beam_layer_count)], layer_outlines);
345 const ExPolygons& areas_other = structure_per_layer[!region_idx][layer_nr / static_cast<size_t>(beam_layer_count)];
346
347 auto layer = print_object.get_layer(layer_nr);
348 auto& slices = layer->get_region(region)->slices;
349 ExPolygons polys = to_expolygons(slices.surfaces);
350 slices.set(union_ex(diff_ex(polys, areas_other), // reduce layer areas inward with beams from other mesh
351 areas_here) // extend layer areas outward with newly added beams
352 , stInternal);
353 }
354 }
355}
std::vector< std::vector< ExPolygons > > generateMicrostructure() const
Definition InterlockingGenerator.cpp:264
void expolygons_rotate(ExPolygons &expolys, double angle)
Definition ExPolygon.hpp:463
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:831
ExPolygons to_expolygons(const Polygons &polys)
Definition ExPolygon.hpp:373
Eigen::Matrix< coord_t, 3, 1, Eigen::DontAlign > Vec3crd
Definition Point.hpp:53
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:878
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, PolyFillType fill_type)
Definition ClipperUtils.cpp:1011
@ stInternal
Definition Surface.hpp:26
void expolygons_append(ExPolygons &dst, const ExPolygons &src)
Definition ExPolygon.hpp:447

References beam_layer_count, cell_size, Slic3r::diff_ex(), Slic3r::expolygons_append(), Slic3r::expolygons_rotate(), generateMicrostructure(), Slic3r::intersection_ex(), print_object, region_a_index, region_b_index, rotation, Slic3r::stInternal, throw_on_cancel, Slic3r::to_expolygons(), Slic3r::union_ex(), and vu.

Referenced by generateInterlockingStructure().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ computeUnionedVolumeRegions()

std::vector< ExPolygons > Slic3r::InterlockingGenerator::computeUnionedVolumeRegions ( ) const
private

Compute the regions occupied by both models.

A morphological close is performed so that we don't register small gaps between the two models as being separate.

Returns
layer_regions The computed layer regions
247{
248 const size_t max_layer_count = print_object.layer_count() +
249 1; // introduce ghost layer on top for correct skin computation of topmost layer.
250 std::vector<ExPolygons> layer_regions(max_layer_count);
251
252 for (size_t layer_nr = 0; layer_nr < max_layer_count - 1; layer_nr++) {
253 auto& layer_region = layer_regions[static_cast<size_t>(layer_nr)];
254 for (size_t region_idx : {region_a_index, region_b_index}) {
255 auto layer = print_object.get_layer(layer_nr);
256 expolygons_append(layer_region, to_expolygons(layer->get_region(region_idx)->slices.surfaces));
257 }
258 layer_region = closing_ex(layer_region, ignored_gap_); // Morphological close to merge meshes into single volume
259 expolygons_rotate(layer_region, rotation);
260 }
261 return layer_regions;
262}
static const coord_t ignored_gap_
Distance between models to be considered next to each other so that an interlocking structure will be...
Definition InterlockingGenerator.hpp:161
Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:678

References Slic3r::closing_ex(), Slic3r::expolygons_append(), Slic3r::expolygons_rotate(), ignored_gap_, print_object, region_a_index, region_b_index, rotation, and Slic3r::to_expolygons().

Referenced by generateInterlockingStructure().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generate_interlocking_structure()

void Slic3r::InterlockingGenerator::generate_interlocking_structure ( PrintObject * print_object,
const std::function< void()> & throw_on_cancel )
static

Generate an interlocking structure between each two adjacent meshes.

45{
46 const auto& config = print_object->config();
47 // Check if interlocking is enabled, and avoid errors like division by zero due to invalid configuration.
48 if (!config.interlocking_beam || config.interlocking_beam_layer_count < 1 || config.interlocking_depth < 1 || config.interlocking_beam_width < EPSILON ) {
49 return;
50 }
51
52 const float rotation = Geometry::deg2rad(config.interlocking_orientation.value);
53 const coord_t beam_layer_count = config.interlocking_beam_layer_count;
54 const int interface_depth = config.interlocking_depth;
55 const int boundary_avoidance = config.interlocking_boundary_avoidance;
56 const coord_t beam_width = scaled(config.interlocking_beam_width.value);
57
58 const DilationKernel interface_dilation(GridPoint3(interface_depth, interface_depth, interface_depth), DilationKernel::Type::PRISM);
59
60 const bool air_filtering = boundary_avoidance > 0;
62
63 const coord_t cell_width = beam_width + beam_width;
64 const Vec3crd cell_size(cell_width, cell_width, 2 * beam_layer_count);
65
66 for (size_t region_a_index = 0; region_a_index < print_object->num_printing_regions(); region_a_index++) {
67 const PrintRegion& region_a = print_object->printing_region(region_a_index);
68 const auto extruder_nr_a = region_a.extruder(FlowRole::frExternalPerimeter);
69
70 for (size_t region_b_index = region_a_index + 1; region_b_index < print_object->num_printing_regions(); region_b_index++) {
71 const PrintRegion& region_b = print_object->printing_region(region_b_index);
72 const auto extruder_nr_b = region_b.extruder(FlowRole::frExternalPerimeter);
73 if (extruder_nr_a == extruder_nr_b) {
74 continue;
75 }
76
78
81 gen.generateInterlockingStructure();
82 }
83 }
84}
#define EPSILON
Definition ColorUtils.cpp:64
InterlockingGenerator(PrintObject &print_object, const size_t region_a_index, const size_t region_b_index, const coord_t beam_width, const coord_t boundary_avoidance, const float rotation, const Vec3crd &cell_size, const coord_t beam_layer_count, const DilationKernel &interface_dilation, const DilationKernel &air_dilation, const bool air_filtering, const std::function< void()> &throw_on_cancel)
Definition InterlockingGenerator.hpp:77
constexpr T deg2rad(const T angle)
Definition Geometry.hpp:312
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:284
@ frExternalPerimeter
Definition Flow.hpp:19
@ PRISM
Definition VoxelUtils.hpp:53

References InterlockingGenerator(), air_dilation, air_filtering, beam_layer_count, beam_width, boundary_avoidance, cell_size, Slic3r::Geometry::deg2rad(), EPSILON, Slic3r::PrintRegion::extruder(), Slic3r::frExternalPerimeter, generateInterlockingStructure(), interface_dilation, print_object, Slic3r::DilationKernel::PRISM, region_a_index, region_b_index, rotation, Slic3r::scaled(), and throw_on_cancel.

Referenced by Slic3r::PrintObject::slice_volumes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generateInterlockingStructure()

void Slic3r::InterlockingGenerator::generateInterlockingStructure ( ) const
private

Generate an interlocking structure between two meshes

170{
171 std::vector<std::unordered_set<GridPoint3>> voxels_per_mesh = getShellVoxels(interface_dilation);
172
173 std::unordered_set<GridPoint3>& has_any_mesh = voxels_per_mesh[0];
174 std::unordered_set<GridPoint3>& has_all_meshes = voxels_per_mesh[1];
175 has_any_mesh.merge(has_all_meshes); // perform union and intersection simultaneously. Cannibalizes voxels_per_mesh
176
177 if (has_all_meshes.empty()) {
178 return;
179 }
180
181 const std::vector<ExPolygons> layer_regions = computeUnionedVolumeRegions();
182
183 if (air_filtering) {
184 std::unordered_set<GridPoint3> air_cells;
185 addBoundaryCells(layer_regions, air_dilation, air_cells);
186
187 for (const GridPoint3& p : air_cells) {
188 has_all_meshes.erase(p);
189 }
190
191 handleThinAreas(has_all_meshes);
192 }
193
194 applyMicrostructureToOutlines(has_all_meshes, layer_regions);
195}
std::vector< std::unordered_set< GridPoint3 > > getShellVoxels(const DilationKernel &kernel) const
Definition InterlockingGenerator.cpp:197
std::vector< ExPolygons > computeUnionedVolumeRegions() const
Definition InterlockingGenerator.cpp:246
void handleThinAreas(const std::unordered_set< GridPoint3 > &has_all_meshes) const
Definition InterlockingGenerator.cpp:108
void addBoundaryCells(const std::vector< ExPolygons > &layers, const DilationKernel &kernel, std::unordered_set< GridPoint3 > &cells) const
Definition InterlockingGenerator.cpp:221
void applyMicrostructureToOutlines(const std::unordered_set< GridPoint3 > &cells, const std::vector< ExPolygons > &layer_regions) const
Definition InterlockingGenerator.cpp:294

References addBoundaryCells(), air_dilation, air_filtering, applyMicrostructureToOutlines(), computeUnionedVolumeRegions(), getShellVoxels(), handleThinAreas(), and interface_dilation.

Referenced by generate_interlocking_structure().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generateMicrostructure()

std::vector< std::vector< ExPolygons > > Slic3r::InterlockingGenerator::generateMicrostructure ( ) const
private

Generate the polygons for the beams of a single cell

Returns
cell_area_per_mesh_per_layer The output polygons for each beam
265{
266 std::vector<std::vector<ExPolygons>> cell_area_per_mesh_per_layer;
267 cell_area_per_mesh_per_layer.resize(2);
268 cell_area_per_mesh_per_layer[0].resize(2);
269 const coord_t beam_w_sum = beam_width + beam_width;
270 const coord_t middle = cell_size.x() * beam_width / beam_w_sum;
271 const coord_t width[2] = {middle, cell_size.x() - middle};
272 for (size_t mesh_idx : {0ul, 1ul}) {
273 Point offset(mesh_idx ? middle : 0, 0);
274 Point area_size(width[mesh_idx], cell_size.y());
275
277 poly.append(offset);
278 poly.append(offset + Point(area_size.x(), 0));
279 poly.append(offset + area_size);
280 poly.append(offset + Point(0, area_size.y()));
281 cell_area_per_mesh_per_layer[0][mesh_idx].emplace_back(poly);
282 }
283 cell_area_per_mesh_per_layer[1] = cell_area_per_mesh_per_layer[0];
284 for (ExPolygons& polys : cell_area_per_mesh_per_layer[1]) {
285 for (ExPolygon& poly : polys) {
286 for (Point& p : poly.contour) {
287 std::swap(p.x(), p.y());
288 }
289 }
290 }
291 return cell_area_per_mesh_per_layer;
292}
void poly(std::vector< std::pair< Vec2d, Vec2d > > &out, std::initializer_list< Vec2d > p)
Definition DesignSketchTool.cpp:7751
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
coord_t width(const BoundingBox &box)
Definition Arrange.cpp:1184
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
Slic3r::Polygon Polygon
Definition Emboss.cpp:101

References beam_width, cell_size, and Slic3r::offset().

Referenced by applyMicrostructureToOutlines().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getShellVoxels()

std::vector< std::unordered_set< GridPoint3 > > Slic3r::InterlockingGenerator::getShellVoxels ( const DilationKernel & kernel) const
private

Compute the voxels overlapping with the shell of both models. This includes the walls, but also top/bottom skin.

Parameters
kernelThe dilation kernel to give the returned voxel shell more thickness
Returns
The shell voxels for mesh a and those for mesh b
198{
199 std::vector<std::unordered_set<GridPoint3>> voxels_per_mesh(2);
200
201 // mark all cells which contain some boundary
202 for (size_t region_idx = 0; region_idx < 2; region_idx++)
203 {
204 const size_t region = (region_idx == 0) ? region_a_index : region_b_index;
205 std::unordered_set<GridPoint3>& mesh_voxels = voxels_per_mesh[region_idx];
206
207 std::vector<ExPolygons> rotated_polygons_per_layer(print_object.layer_count());
208 for (size_t layer_nr = 0; layer_nr < print_object.layer_count(); layer_nr++)
209 {
210 auto layer = print_object.get_layer(layer_nr);
211 rotated_polygons_per_layer[layer_nr] = to_expolygons(layer->get_region(region)->slices.surfaces);
212 expolygons_rotate(rotated_polygons_per_layer[layer_nr], rotation);
213 }
214
215 addBoundaryCells(rotated_polygons_per_layer, kernel, mesh_voxels);
216 }
217
218 return voxels_per_mesh;
219}

References addBoundaryCells(), Slic3r::expolygons_rotate(), print_object, region_a_index, region_b_index, rotation, and Slic3r::to_expolygons().

Referenced by generateInterlockingStructure().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ growBorderAreasPerpendicular()

std::pair< ExPolygons, ExPolygons > Slic3r::InterlockingGenerator::growBorderAreasPerpendicular ( const ExPolygons & a,
const ExPolygons & b,
const coord_t & detect ) const
private

Given two polygons, return the parts that border on air, and grow 'perpendicular' up to 'detect' distance.

Parameters
aThe first polygon.
bThe second polygon.
detecThe expand distance. (Not equal to offset, but a series of small offsets and differences).
Returns
A pair of polygons that repressent the 'borders' of a and b, but expanded 'perpendicularly'.
87{
88 const coord_t min_line =
89 std::min(print_object.printing_region(region_a_index).flow(print_object, frExternalPerimeter, 0.1).scaled_width(),
90 print_object.printing_region(region_b_index).flow(print_object, frExternalPerimeter, 0.1).scaled_width());
91
92 const ExPolygons total_shrunk = offset_ex(union_ex(offset_ex(a, min_line), offset_ex(b, min_line)), 2 * -min_line);
93
94 ExPolygons from_border_a = diff_ex(a, total_shrunk);
95 ExPolygons from_border_b = diff_ex(b, total_shrunk);
96
97 ExPolygons temp_a, temp_b;
98 for (coord_t i = 0; i < (detect / min_line) + 2; ++i) {
99 temp_a = offset_ex(from_border_a, min_line);
100 temp_b = offset_ex(from_border_b, min_line);
101 from_border_a = diff_ex(temp_a, temp_b);
102 from_border_b = diff_ex(temp_b, temp_a);
103 }
104
105 return {from_border_a, from_border_b};
106}
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:605

References Slic3r::diff_ex(), Slic3r::frExternalPerimeter, Slic3r::offset_ex(), print_object, region_a_index, region_b_index, and Slic3r::union_ex().

Referenced by handleThinAreas().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handleThinAreas()

void Slic3r::InterlockingGenerator::handleThinAreas ( const std::unordered_set< GridPoint3 > & has_all_meshes) const
private

Special handling for thin strips of material.

Expand the meshes into each other where they need it, namely when a thin strip of material needs to be attached.

Parameters
has_all_meshesOnly do this special handling if there's actually microstructure nearby that needs to be adhered to.
109{
110 const coord_t number_of_beams_detect = boundary_avoidance;
111 const coord_t number_of_beams_expand = boundary_avoidance - 1;
112 constexpr coord_t rounding_errors = 5;
113
114 const coord_t max_beam_width = beam_width;
115 const coord_t detect = (max_beam_width * number_of_beams_detect) + rounding_errors;
116 const coord_t expand = (max_beam_width * number_of_beams_expand) + rounding_errors;
117 const coord_t close_gaps =
118 std::min(print_object.printing_region(region_a_index).flow(print_object, frExternalPerimeter, 0.1).scaled_width(),
119 print_object.printing_region(region_b_index).flow(print_object, frExternalPerimeter, 0.1).scaled_width()) / 4;
120
121 // Make an inclusionary polygon, to only actually handle thin areas near actual microstructures (so not in skin for example).
122 std::vector<Polygons> near_interlock_per_layer;
123 near_interlock_per_layer.assign(print_object.layer_count(), Polygons());
124 for (const auto& cell : has_all_meshes) {
125 const auto bottom_corner = vu.toLowerCorner(cell);
126 for (coord_t layer_nr = bottom_corner.z();
127 layer_nr < bottom_corner.z() + cell_size.z() && layer_nr < static_cast<coord_t>(near_interlock_per_layer.size()); ++layer_nr) {
128 near_interlock_per_layer[static_cast<size_t>(layer_nr)].push_back(vu.toPolygon(cell));
129 }
130 }
131 for (auto& near_interlock : near_interlock_per_layer) {
133 near_interlock = offset(union_(closing(near_interlock, rounding_errors)), detect);
134 polygons_rotate(near_interlock, rotation);
135 }
136
137 // Only alter layers when they are present in both meshes, zip should take care if that.
138 for (size_t layer_nr = 0; layer_nr < print_object.layer_count(); layer_nr++){
140 auto layer = print_object.get_layer(layer_nr);
141 ExPolygons polys_a = to_expolygons(layer->get_region(region_a_index)->slices.surfaces);
142 ExPolygons polys_b = to_expolygons(layer->get_region(region_b_index)->slices.surfaces);
143
144 const auto [from_border_a, from_border_b] = growBorderAreasPerpendicular(polys_a, polys_b, detect);
145
146 // Get the areas of each mesh that are _not_ thin (large), by performing a morphological open.
147 const ExPolygons large_a = opening_ex(polys_a, detect);
148 const ExPolygons large_b = opening_ex(polys_b, detect);
149
150 // Derive the area that the thin areas need to expand into (so the added areas to the thin strips) from the information we already have.
151 const ExPolygons thin_expansion_a =
153 near_interlock_per_layer[layer_nr]),
154 from_border_a),
155 rounding_errors);
156 const ExPolygons thin_expansion_b =
158 near_interlock_per_layer[layer_nr]),
159 from_border_b),
160 rounding_errors);
161
162 // Expanded thin areas of the opposing polygon should 'eat into' the larger areas of the polygon,
163 // and conversely, add the expansions to their own thin areas.
164 layer->get_region(region_a_index)->slices.set(closing_ex(diff_ex(union_ex(polys_a, thin_expansion_a), thin_expansion_b), close_gaps), stInternal);
165 layer->get_region(region_b_index)->slices.set(closing_ex(diff_ex(union_ex(polys_b, thin_expansion_b), thin_expansion_a), close_gaps), stInternal);
166 }
167}
std::pair< ExPolygons, ExPolygons > growBorderAreasPerpendicular(const ExPolygons &a, const ExPolygons &b, const coord_t &detect) const
Definition InterlockingGenerator.cpp:86
Slic3r::Polygons union_(const Slic3r::Polygons &subject)
Definition ClipperUtils.cpp:801
Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:397
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:22
Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:670
void polygons_rotate(Polygons &polys, double angle)
Definition Polygon.hpp:169

References beam_width, boundary_avoidance, cell_size, Slic3r::closing(), Slic3r::closing_ex(), Slic3r::diff_ex(), Slic3r::expand(), Slic3r::frExternalPerimeter, growBorderAreasPerpendicular(), Slic3r::intersection_ex(), Slic3r::offset(), Slic3r::offset_ex(), Slic3r::opening_ex(), Slic3r::polygons_rotate(), print_object, region_a_index, region_b_index, rotation, Slic3r::stInternal, throw_on_cancel, Slic3r::to_expolygons(), Slic3r::union_(), Slic3r::union_ex(), and vu.

Referenced by generateInterlockingStructure().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ air_dilation

const DilationKernel Slic3r::InterlockingGenerator::air_dilation
private

◆ air_filtering

const bool Slic3r::InterlockingGenerator::air_filtering
private

◆ beam_layer_count

const coord_t Slic3r::InterlockingGenerator::beam_layer_count
private

◆ beam_width

const coord_t Slic3r::InterlockingGenerator::beam_width
private

◆ boundary_avoidance

const coord_t Slic3r::InterlockingGenerator::boundary_avoidance
private

◆ cell_size

◆ ignored_gap_

const coord_t Slic3r::InterlockingGenerator::ignored_gap_ = 100u
staticprivate

Distance between models to be considered next to each other so that an interlocking structure will be generated there.

Referenced by computeUnionedVolumeRegions().

◆ interface_dilation

const DilationKernel Slic3r::InterlockingGenerator::interface_dilation
private

◆ print_object

◆ region_a_index

◆ region_b_index

◆ rotation

◆ throw_on_cancel

const std::function<void()>& Slic3r::InterlockingGenerator::throw_on_cancel
private

◆ vu

const VoxelUtils Slic3r::InterlockingGenerator::vu
private

The documentation for this class was generated from the following files: