@@ -71,7 +71,7 @@ SkirtBrim::SkirtBrim(SliceDataStorage& storage)
7171 }
7272}
7373
74- std::vector<SkirtBrim::Offset> SkirtBrim::generateBrimOffsetPlan (std::vector<Shape >& starting_outlines)
74+ std::vector<SkirtBrim::Offset> SkirtBrim::generateBrimOffsetPlan (std::vector<Outline >& starting_outlines)
7575{
7676 std::vector<Offset> all_brim_offsets;
7777
@@ -96,24 +96,42 @@ std::vector<SkirtBrim::Offset> SkirtBrim::generateBrimOffsetPlan(std::vector<Sha
9696 const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr];
9797 const coord_t semi_line_width = extruder_config.line_width_ / 2 ;
9898
99- if (! extruder_config.extruder_is_used_ || (skirt_brim_extruder_nr_ >= 0 && extruder_nr != skirt_brim_extruder_nr_) || starting_outlines[extruder_nr].empty ())
99+ if (! extruder_config.extruder_is_used_ || (skirt_brim_extruder_nr_ >= 0 && extruder_nr != skirt_brim_extruder_nr_)
100+ || (starting_outlines[extruder_nr].gapped .empty () && starting_outlines[extruder_nr].touching .empty ()))
100101 {
101102 continue ; // only include offsets for brim extruder
102103 }
103104
104105 for (int line_idx = 0 ; line_idx < extruder_config.line_count_ ; line_idx++)
105106 {
106107 const bool is_last = line_idx == extruder_config.line_count_ - 1 ;
107- coord_t offset = extruder_config.gap_ + semi_line_width + extruder_config.line_width_ * line_idx;
108+ const coord_t offset_touching = semi_line_width + extruder_config.line_width_ * line_idx;
109+ const coord_t offset_gapped = offset_touching + extruder_config.gap_ ;
108110 if (line_idx == 0 )
109111 {
110- all_brim_offsets
111- .emplace_back (&starting_outlines[extruder_nr], extruder_config.outside_polys_ , extruder_config.inside_polys_ , offset, offset, line_idx, extruder_nr, is_last);
112+ all_brim_offsets.emplace_back (
113+ &starting_outlines[extruder_nr],
114+ extruder_config.outside_polys_ ,
115+ extruder_config.inside_polys_ ,
116+ offset_gapped,
117+ offset_touching,
118+ offset_gapped,
119+ line_idx,
120+ extruder_nr,
121+ is_last);
112122 }
113123 else
114124 {
115- all_brim_offsets
116- .emplace_back (line_idx - 1 , extruder_config.outside_polys_ , extruder_config.inside_polys_ , extruder_config.line_width_ , offset, line_idx, extruder_nr, is_last);
125+ all_brim_offsets.emplace_back (
126+ line_idx - 1 ,
127+ extruder_config.outside_polys_ ,
128+ extruder_config.inside_polys_ ,
129+ extruder_config.line_width_ ,
130+ extruder_config.line_width_ ,
131+ offset_gapped,
132+ line_idx,
133+ extruder_nr,
134+ is_last);
117135 }
118136 }
119137 }
@@ -124,7 +142,7 @@ std::vector<SkirtBrim::Offset> SkirtBrim::generateBrimOffsetPlan(std::vector<Sha
124142
125143void SkirtBrim::generate ()
126144{
127- std::vector<Shape > starting_outlines (extruder_count_);
145+ std::vector<Outline > starting_outlines (extruder_count_);
128146 std::vector<Offset> all_brim_offsets = generateBrimOffsetPlan (starting_outlines);
129147 std::vector<Shape> allowed_areas_per_extruder = generateAllowedAreas (starting_outlines);
130148
@@ -205,6 +223,7 @@ std::vector<coord_t> SkirtBrim::generatePrimaryBrim(std::vector<Offset>& all_bri
205223 extruder_config.inside_polys_ ,
206224 extruder_config.line_width_ ,
207225 offset.total_offset_ + extruder_config.line_width_ ,
226+ offset.total_offset_ + extruder_config.line_width_ ,
208227 offset.inset_idx_ + 1 ,
209228 offset.extruder_nr_ ,
210229 is_last);
@@ -220,20 +239,23 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std
220239 Shape brim;
221240 const ExtruderConfig& extruder_config = extruders_configs_[offset.extruder_nr_ ];
222241
223- if (std::holds_alternative<Shape *>(offset.reference_outline_or_index_ ))
242+ if (std::holds_alternative<Outline *>(offset.reference_outline_or_index_ ))
224243 {
225- Shape * reference_outline = std::get<Shape *>(offset.reference_outline_or_index_ );
226- const coord_t offset_value = offset. offset_value_ ;
227- for ( const Polygon& polygon : * reference_outline)
244+ Outline * reference_outline = std::get<Outline *>(offset.reference_outline_or_index_ );
245+ for ( const auto & [shape, offset_value] :
246+ { std::make_tuple (reference_outline-> gapped , offset. offset_value_gapped_ ), std::make_tuple ( reference_outline-> touching , offset. offset_value_touching_ ) } )
228247 {
229- const double area = polygon.area ();
230- if (area > 0 && offset.outside_ )
231- {
232- brim.push_back (polygon.offset (offset_value, ClipperLib::jtRound));
233- }
234- else if (area < 0 && offset.inside_ )
248+ for (const Polygon& polygon : shape)
235249 {
236- brim.push_back (polygon.offset (-offset_value, ClipperLib::jtRound));
250+ const double area = polygon.area ();
251+ if (area > 0 && offset.outside_ )
252+ {
253+ brim.push_back (polygon.offset (offset_value, ClipperLib::jtRound));
254+ }
255+ else if (area < 0 && offset.inside_ )
256+ {
257+ brim.push_back (polygon.offset (-offset_value, ClipperLib::jtRound));
258+ }
237259 }
238260 }
239261 }
@@ -284,9 +306,9 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std
284306 return length_added;
285307}
286308
287- Shape SkirtBrim::getFirstLayerOutline (const int extruder_nr /* = -1 */ )
309+ SkirtBrim::Outline SkirtBrim::getFirstLayerOutline (const int extruder_nr /* = -1 */ )
288310{
289- Shape first_layer_outline;
311+ Outline first_layer_outline;
290312 Settings& global_settings = Application::getInstance ().current_slice_ ->scene .current_mesh_group ->settings ;
291313 int reference_extruder_nr = skirt_brim_extruder_nr_;
292314 assert (! (reference_extruder_nr == -1 && extruder_nr == -1 ) && " We should only request the outlines of all layers when the brim is being generated for only one material" );
@@ -299,7 +321,6 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
299321 const LayerIndex layer_nr = 0 ;
300322 if (adhesion_type_ == EPlatformAdhesion::SKIRT)
301323 {
302- first_layer_outline = Shape ();
303324 int skirt_height = 0 ;
304325 for (const auto & extruder : Application::getInstance ().current_slice_ ->scene .extruders )
305326 {
@@ -314,7 +335,7 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
314335 {
315336 constexpr bool include_support = true ;
316337 constexpr bool include_prime_tower = true ;
317- first_layer_outline = first_layer_outline.unionPolygons (storage_.getLayerOutlines (i_layer, include_support, include_prime_tower, true ));
338+ first_layer_outline. gapped = first_layer_outline. gapped .unionPolygons (storage_.getLayerOutlines (i_layer, include_support, include_prime_tower, true ));
318339 }
319340
320341 Shape shields;
@@ -326,22 +347,25 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
326347 {
327348 shields = shields.unionPolygons (storage_.draft_protection_shield );
328349 }
329- first_layer_outline = first_layer_outline.unionPolygons (shields.offset (
350+ first_layer_outline. gapped = first_layer_outline. gapped .unionPolygons (shields.offset (
330351 reference_extruder_config.line_width_ / 2 // because the shield is printed *on* the stored polygons; not inside hteir area
331352 - reference_extruder_config.gap_ )); // so that when we apply the gap we will end up right next to the shield
332353 // NOTE: offsetting by -gap here and by +gap in the main brim algorithm effectively performs a morphological close,
333354 // so in some cases with a large skirt gap and small models and small shield distance
334355 // the skirt lines can cross the shield lines.
335356 // This shouldn't be a big problem, since the skirt lines are far away from the model.
336- first_layer_outline = first_layer_outline.approxConvexHull ();
357+ first_layer_outline. gapped = first_layer_outline. gapped .approxConvexHull ();
337358 }
338359 else
339360 { // add brim underneath support by removing support where there's brim around the model
340- constexpr bool include_support = false ; // Don't include the supports yet because we need to reduce them before
341- constexpr bool include_prime_tower = false ; // Not included, has its own brim
342- constexpr bool external_polys_only = false ; // Gather all polygons and treat them separately.
343- first_layer_outline = storage_.getLayerOutlines (layer_nr, include_support, include_prime_tower, external_polys_only, extruder_nr);
344- first_layer_outline = first_layer_outline.unionPolygons (); // To guard against overlapping outlines, which would produce holes according to the even-odd rule.
361+ {
362+ constexpr bool include_support = false ; // Don't include the supports yet because we need to reduce them before
363+ constexpr bool include_prime_tower = false ; // Not included, has its own brim
364+ constexpr bool external_polys_only = false ; // Gather all polygons and treat them separately.
365+ first_layer_outline.gapped = storage_.getLayerOutlines (layer_nr, include_support, include_prime_tower, external_polys_only, extruder_nr);
366+ first_layer_outline.gapped
367+ = first_layer_outline.gapped .unionPolygons (); // To guard against overlapping outlines, which would produce holes according to the even-odd rule.
368+ }
345369
346370 if (storage_.support .generated && primary_line_count > 0 && ! storage_.support .supportLayers .empty ()
347371 && (extruder_nr == -1 || extruder_nr == global_settings.get <int >(" support_infill_extruder_nr" )))
@@ -363,7 +387,7 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
363387 // always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides
364388 const coord_t offset = primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2 );
365389
366- for (const Polygon& polygon : first_layer_outline)
390+ for (const Polygon& polygon : first_layer_outline. gapped )
367391 {
368392 // Compute the fringe that the brim is going to cover around the model
369393 Shape outset;
@@ -394,20 +418,20 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */)
394418
395419 for (const SupportInfillPart& support_infill_part : support_layer.support_infill_parts )
396420 {
397- first_layer_outline.push_back (support_infill_part.outline_ );
421+ first_layer_outline.touching . push_back (support_infill_part.outline_ );
398422 }
399- first_layer_outline.push_back (support_layer.support_bottom );
400- first_layer_outline.push_back (support_layer.support_roof );
423+ first_layer_outline.touching . push_back (support_layer.support_bottom );
424+ first_layer_outline.touching . push_back (support_layer.support_roof );
401425 }
402426 }
403- constexpr coord_t join_distance = 20 ;
404- first_layer_outline = first_layer_outline.offset (join_distance).offset (-join_distance); // merge adjacent models into single polygon
405- constexpr coord_t smallest_line_length = 200 ;
406- constexpr coord_t largest_error_of_removed_point = 50 ;
407- first_layer_outline = Simplify (smallest_line_length, largest_error_of_removed_point, 0 ).polygon (first_layer_outline);
408- if (first_layer_outline.empty ())
427+
428+ for (Shape& outline : std::array{ first_layer_outline.gapped , first_layer_outline.touching })
409429 {
410- spdlog::warn (" Couldn't generate skirt / brim! No polygons on first layer for extruder {}." , extruder_nr);
430+ constexpr coord_t join_distance = 20 ;
431+ outline = outline.offset (join_distance).offset (-join_distance); // merge adjacent models into single polygon
432+ constexpr coord_t smallest_line_length = 200 ;
433+ constexpr coord_t largest_error_of_removed_point = 50 ;
434+ outline = Simplify (smallest_line_length, largest_error_of_removed_point, 0 ).polygon (outline);
411435 }
412436 return first_layer_outline;
413437}
@@ -492,7 +516,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Shape& covered_area, std::vector<Shap
492516 for (int extruder_nr = 0 ; extruder_nr < extruder_count_; extruder_nr++)
493517 {
494518 bool first = true ;
495- Shape reference_outline = covered_area;
519+ Outline reference_outline{ . touching = covered_area } ;
496520 const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr];
497521 while (total_length[extruder_nr] < extruder_config.skirt_brim_minimal_length_ )
498522 {
@@ -516,6 +540,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Shape& covered_area, std::vector<Shap
516540 inside_polys,
517541 offset_from_reference,
518542 bogus_total_offset,
543+ bogus_total_offset,
519544 storage_.skirt_brim [extruder_nr].size (),
520545 extruder_nr,
521546 is_last);
@@ -537,7 +562,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Shape& covered_area, std::vector<Shap
537562 }
538563}
539564
540- std::vector<Shape> SkirtBrim::generateAllowedAreas (const std::vector<Shape >& starting_outlines) const
565+ std::vector<Shape> SkirtBrim::generateAllowedAreas (const std::vector<Outline >& starting_outlines) const
541566{
542567 constexpr LayerIndex layer_nr = 0 ;
543568
@@ -635,7 +660,8 @@ std::vector<Shape> SkirtBrim::generateAllowedAreas(const std::vector<Shape>& sta
635660 }
636661
637662 // Anyway, don't allow a brim/skirt to grow inside itself, which may happen e.g. with ooze shield+skirt
638- allowed_areas = allowed_areas.difference (starting_outlines[extruder_nr].offset (extruder_config.gap_ - 50 , ClipperLib::jtRound));
663+ allowed_areas = allowed_areas.difference (starting_outlines[extruder_nr].gapped .offset (extruder_config.gap_ - 50 , ClipperLib::jtRound));
664+ allowed_areas = allowed_areas.difference (starting_outlines[extruder_nr].touching .offset (-50 , ClipperLib::jtRound));
639665 }
640666
641667 return allowed_areas_per_extruder;
0 commit comments