Skip to content

Commit 04c60bb

Browse files
authored
CURA-12474 set fixed 0 gap for brim support (#2213)
2 parents a460338 + 8fe8e76 commit 04c60bb

File tree

2 files changed

+90
-52
lines changed

2 files changed

+90
-52
lines changed

include/SkirtBrim.h

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,47 @@ constexpr coord_t min_brim_line_length = 3000u; //!< open polyline brim lines sm
2222
class SkirtBrim
2323
{
2424
private:
25+
/*!
26+
* Store the various outlines that we want to create a brim around
27+
*/
28+
struct Outline
29+
{
30+
Shape gapped; //!< Outlines for which we want to start a brim by applying the gap for easy detaching
31+
Shape touching; //!< Outlines for which we want the brim to touch, so that it has better adhesion
32+
};
33+
2534
/*!
2635
* A helper class to store an offset yet to be performed on either an outline polygon, or based on an earlier generated brim line.
2736
*/
2837
struct Offset
2938
{
3039
Offset(
31-
const std::variant<Shape*, int>& reference_outline_or_index,
40+
const std::variant<Outline*, int>& reference_outline_or_index,
3241
const bool outside,
3342
const bool inside,
34-
const coord_t offset_value,
43+
const coord_t offset_value_gapped,
44+
const coord_t offset_value_touching,
3545
const coord_t total_offset,
3646
const size_t inset_idx,
3747
const size_t extruder_nr,
3848
const bool is_last)
3949
: reference_outline_or_index_(reference_outline_or_index)
4050
, outside_(outside)
4151
, inside_(inside)
42-
, offset_value_(offset_value)
52+
, offset_value_gapped_(offset_value_gapped)
53+
, offset_value_touching_(offset_value_touching)
4354
, total_offset_(total_offset)
4455
, inset_idx_(inset_idx)
4556
, extruder_nr_(extruder_nr)
4657
, is_last_(is_last)
4758
{
4859
}
4960

50-
std::variant<Shape*, int> reference_outline_or_index_;
61+
std::variant<Outline*, int> reference_outline_or_index_;
5162
bool outside_; //!< Wether to offset outward from the reference polygons
5263
bool inside_; //!< Wether to offset inward from the reference polygons
53-
coord_t offset_value_; //!< Distance by which to offset from the reference
64+
coord_t offset_value_gapped_; //!< Distance by which to offset from the reference, for outlines with gap applied
65+
coord_t offset_value_touching_; //!< Distance by which to offset from the reference, for outlines with no gap applied
5466
coord_t total_offset_; //!< Total distance from the model
5567
int inset_idx_; //!< The outset index of this brimline
5668
size_t extruder_nr_; //!< The extruder by which to print this brim line
@@ -124,7 +136,7 @@ class SkirtBrim
124136
* \param[out] starting_outlines The first layer outlines from which to compute the offsets. Returned as output parameter because pointers need to stay valid.
125137
* \return An ordered list of offsets to perform in the order in which they are to be performed.
126138
*/
127-
std::vector<Offset> generateBrimOffsetPlan(std::vector<Shape>& starting_outlines);
139+
std::vector<Offset> generateBrimOffsetPlan(std::vector<Outline>& starting_outlines);
128140

129141
/*!
130142
* Generate the primary skirt/brim of the one skirt_brim_extruder or of all extruders simultaneously.
@@ -158,7 +170,7 @@ class SkirtBrim
158170
* \param extruder_nr The extruder for which to get the outlines. -1 to include outliens for all extruders
159171
* \return The resulting reference polygons
160172
*/
161-
Shape getFirstLayerOutline(const int extruder_nr = -1);
173+
Outline getFirstLayerOutline(const int extruder_nr = -1);
162174

163175
/*!
164176
* The disallowed area around the internal holes of parts with other parts inside which would get an external brim.
@@ -206,7 +218,7 @@ class SkirtBrim
206218
* \param[in] starting_outlines The previously generated starting outlines for each extruder
207219
* \return The list of allowed areas for each extruder
208220
*/
209-
std::vector<Shape> generateAllowedAreas(const std::vector<Shape>& starting_outlines) const;
221+
std::vector<Shape> generateAllowedAreas(const std::vector<Outline>& starting_outlines) const;
210222

211223
public:
212224
/*!

src/SkirtBrim.cpp

Lines changed: 70 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -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

125143
void 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
{
@@ -515,6 +539,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Shape& covered_area, std::vector<Shap
515539
outside_polys,
516540
inside_polys,
517541
offset_from_reference,
542+
offset_from_reference,
518543
bogus_total_offset,
519544
storage_.skirt_brim[extruder_nr].size(),
520545
extruder_nr,
@@ -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

Comments
 (0)