Skip to content

Commit cd6ecd1

Browse files
committed
Properly handle multi-extruder brim/skirt
CURA-12250
1 parent 1a49b2b commit cd6ecd1

File tree

4 files changed

+95
-58
lines changed

4 files changed

+95
-58
lines changed

include/feature_generation/SkirtBrimAppender.h

+17-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include "ExtruderNumber.h"
1010
#include "operation_transformation/PrintOperationTransformer.h"
1111
#include "print_operation/ContinuousExtruderMoveSequencePtr.h"
12-
#include "print_operation/ExtruderPlanPtr.h"
1312
#include "print_operation/LayerPlanPtr.h"
1413
#include "print_operation/PrintPlan.h"
1514

@@ -18,7 +17,6 @@ namespace cura
1817

1918
enum class EPlatformAdhesion;
2019
class Shape;
21-
class ExtrudersSet;
2220

2321
class SkirtBrimAppender : public PrintOperationTransformer<PrintPlan>
2422
{
@@ -47,30 +45,40 @@ class SkirtBrimAppender : public PrintOperationTransformer<PrintPlan>
4745
const SliceDataStorage& storage_;
4846

4947
private:
50-
static std::tuple<std::vector<ConstExtruderPlanPtr>, ExtrudersSet> generateUsedExtruders(const PrintPlan* print_plan);
48+
static std::vector<ExtruderNumber> generateUsedExtruders(const PrintPlan* print_plan);
5149

5250
static size_t calculateMaxHeight(const std::map<ExtruderNumber, ExtruderConfig>& extruders_configs, const EPlatformAdhesion adhesion_type);
5351

54-
static std::map<ExtruderNumber, ExtruderConfig> generateExtrudersConfigs(const ExtrudersSet& used_extruders, const EPlatformAdhesion adhesion_type);
52+
static std::map<ExtruderNumber, ExtruderConfig> generateExtrudersConfigs(std::vector<ExtruderNumber>& used_extruders, const EPlatformAdhesion adhesion_type);
5553

54+
/*!
55+
* Generates the outline for the first offset of each used extruder
56+
* @param print_plan The print plan, used to retrieve the extrusion feature on the first layers
57+
* @param brim_extruder_nr The brim specific extruder number, or nullopt if there is none
58+
* @param height The maximum height to be reached while generating the skirt/brim
59+
* @param adhesion_type The actual adhesion type
60+
* @param used_extruders The used extruders, in order of processing
61+
* @return In case the adhesion type is brim, a map containing the outlines of all the features per extruder
62+
* In case the adhesion type is skirt, a map containing a single element with fixed 0, which is a union of
63+
* all the outlines of all extruders on the first layers
64+
*/
5665
static std::map<ExtruderNumber, Shape> generateStartingOutlines(
5766
const PrintPlan* print_plan,
58-
const std::optional<ExtruderNumber> skirt_brim_extruder_nr,
67+
const std::optional<ExtruderNumber> brim_extruder_nr,
5968
const size_t height,
6069
const EPlatformAdhesion adhesion_type,
61-
const ExtrudersSet& used_extruders);
70+
std::vector<ExtruderNumber>& used_extruders);
6271

6372
std::map<ExtruderNumber, Shape> generateAllowedAreas(
6473
const std::map<ExtruderNumber, Shape>& starting_outlines,
6574
const EPlatformAdhesion adhesion_type,
66-
const ExtrudersSet& used_extruders,
75+
std::vector<ExtruderNumber>& used_extruders,
6776
const std::optional<ExtruderNumber> skirt_brim_extruder_nr,
6877
const std::map<ExtruderNumber, ExtruderConfig>& extruders_configs) const;
6978

7079
static void generateSkirtBrim(
7180
const EPlatformAdhesion adhesion_type,
72-
const ExtrudersSet& used_extruders,
73-
const std::vector<ConstExtruderPlanPtr> first_extruder_plans,
81+
std::vector<ExtruderNumber>& used_extruders,
7482
const std::map<ExtruderNumber, Shape>& starting_outlines,
7583
std::map<ExtruderNumber, Shape> allowed_areas_per_extruder,
7684
const std::map<ExtruderNumber, ExtruderConfig>& extruders_configs,

include/print_operation/LayerPlan.h

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#pragma once
55

6+
#include "ExtruderNumber.h"
67
#include "ExtruderPlanPtr.h"
78
#include "print_operation/PrintOperationSequence.h"
89
#include "settings/types/LayerIndex.h"
@@ -33,6 +34,8 @@ class LayerPlan : public PrintOperationSequence
3334

3435
Point3LL getAbsolutePosition(const Point3LL& relative_position) const;
3536

37+
ExtruderPlanPtr findFirstExtruderPlan(const ExtruderNumber &extruder_nr) const;
38+
3639
private:
3740
const LayerIndex layer_index_;
3841
const coord_t z_;

src/feature_generation/SkirtBrimAppender.cpp

+66-49
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@ void SkirtBrimAppender::process(PrintPlan* print_plan)
5151
const std::optional<ExtruderNumber> skirt_brim_extruder_nr = skirt_brim_extruder_nr_setting >= 0 ? std::make_optional(skirt_brim_extruder_nr_setting) : std::nullopt;
5252

5353
// Get the first extruder plan for each extruder
54-
std::vector<ConstExtruderPlanPtr> first_extruder_plans;
55-
ExtrudersSet used_extruders;
56-
std::tie(first_extruder_plans, used_extruders) = generateUsedExtruders(print_plan);
54+
std::vector<ExtruderNumber> used_extruders = generateUsedExtruders(print_plan);
5755

5856
const std::map<ExtruderNumber, ExtruderConfig> extruders_configs = generateExtrudersConfigs(used_extruders, adhesion_type);
5957
const size_t height = calculateMaxHeight(extruders_configs, adhesion_type);
@@ -66,30 +64,28 @@ void SkirtBrimAppender::process(PrintPlan* print_plan)
6664
LayerPlanPtr layer_plan = print_plan->findLayerPlan(actual_height);
6765
if (layer_plan)
6866
{
69-
generateSkirtBrim(adhesion_type, used_extruders, first_extruder_plans, starting_outlines, allowed_areas_per_extruder, extruders_configs, layer_plan);
67+
generateSkirtBrim(adhesion_type, used_extruders, starting_outlines, allowed_areas_per_extruder, extruders_configs, layer_plan);
7068
}
7169
}
7270
}
7371

74-
std::tuple<std::vector<ConstExtruderPlanPtr>, ExtrudersSet> SkirtBrimAppender::generateUsedExtruders(const PrintPlan* print_plan)
72+
std::vector<ExtruderNumber> SkirtBrimAppender::generateUsedExtruders(const PrintPlan* print_plan)
7573
{
76-
std::vector<ConstExtruderPlanPtr> first_extruder_plans;
77-
ExtrudersSet used_extruders;
74+
std::vector<ExtruderNumber> used_extruders;
7875

7976
print_plan->applyOnOperationsByType<ExtruderPlan>(
80-
[&first_extruder_plans, &used_extruders](const ConstExtruderPlanPtr& extruder_plan)
77+
[&used_extruders](const ConstExtruderPlanPtr& extruder_plan)
8178
{
8279
const ExtruderNumber extruder_nr = extruder_plan->getExtruderNr();
83-
if (! used_extruders.contains(extruder_nr))
80+
if (! ranges::contains(used_extruders, extruder_nr))
8481
{
85-
first_extruder_plans.push_back(extruder_plan);
86-
used_extruders.set(extruder_nr);
82+
used_extruders.push_back(extruder_nr);
8783
}
8884
},
8985
PrintOperationSequence::SearchOrder::Forward,
9086
2);
9187

92-
return std::make_tuple(first_extruder_plans, used_extruders);
88+
return used_extruders;
9389
}
9490

9591
size_t SkirtBrimAppender::calculateMaxHeight(const std::map<ExtruderNumber, ExtruderConfig>& extruders_configs, const EPlatformAdhesion adhesion_type)
@@ -104,7 +100,7 @@ size_t SkirtBrimAppender::calculateMaxHeight(const std::map<ExtruderNumber, Extr
104100
return height;
105101
}
106102

107-
std::map<ExtruderNumber, SkirtBrimAppender::ExtruderConfig> SkirtBrimAppender::generateExtrudersConfigs(const ExtrudersSet& used_extruders, const EPlatformAdhesion adhesion_type)
103+
std::map<ExtruderNumber, SkirtBrimAppender::ExtruderConfig> SkirtBrimAppender::generateExtrudersConfigs(std::vector<ExtruderNumber>& used_extruders, const EPlatformAdhesion adhesion_type)
108104
{
109105
std::map<ExtruderNumber, ExtruderConfig> extruders_configs;
110106

@@ -130,10 +126,10 @@ std::map<ExtruderNumber, SkirtBrimAppender::ExtruderConfig> SkirtBrimAppender::g
130126

131127
std::map<size_t, Shape> SkirtBrimAppender::generateStartingOutlines(
132128
const PrintPlan* print_plan,
133-
const std::optional<ExtruderNumber> skirt_brim_extruder_nr,
129+
const std::optional<ExtruderNumber> brim_extruder_nr,
134130
const size_t height,
135131
const EPlatformAdhesion adhesion_type,
136-
const ExtrudersSet& used_extruders)
132+
std::vector<ExtruderNumber>& used_extruders)
137133
{
138134
// Calculate the united footprints of all the extrusion features on the first layers
139135
std::map<ExtruderNumber, std::vector<Shape>> features_footprints;
@@ -143,7 +139,7 @@ std::map<size_t, Shape> SkirtBrimAppender::generateStartingOutlines(
143139
{
144140
for (const ConstExtruderPlanPtr &extruder_plan :layer_plan->getOperationsAs<ExtruderPlan>())
145141
{
146-
const ExtruderNumber target_extruder_nr = adhesion_type == EPlatformAdhesion::SKIRT ? 0 : skirt_brim_extruder_nr.value_or(extruder_plan->getExtruderNr());
142+
const ExtruderNumber target_extruder_nr = adhesion_type == EPlatformAdhesion::SKIRT ? 0 : brim_extruder_nr.value_or(extruder_plan->getExtruderNr());
147143
std::vector<Shape> &target_footprints = features_footprints[target_extruder_nr];
148144

149145
for (const ConstFeatureExtrusionPtr& feature_extrusion : extruder_plan->getOperationsAs<FeatureExtrusion>())
@@ -175,7 +171,7 @@ std::map<size_t, Shape> SkirtBrimAppender::generateStartingOutlines(
175171
std::map<ExtruderNumber, Shape> SkirtBrimAppender::generateAllowedAreas(
176172
const std::map<ExtruderNumber, Shape>& starting_outlines,
177173
const EPlatformAdhesion adhesion_type,
178-
const ExtrudersSet &used_extruders,
174+
std::vector<ExtruderNumber> &used_extruders,
179175
const std::optional<ExtruderNumber> skirt_brim_extruder_nr,
180176
const std::map<ExtruderNumber, ExtruderConfig>& extruders_configs) const
181177
{
@@ -214,14 +210,13 @@ std::map<ExtruderNumber, Shape> SkirtBrimAppender::generateAllowedAreas(
214210
std::map<ExtruderNumber, Shape> allowed_areas_per_extruder;
215211
for (const ExtruderNumber extruder_nr : used_extruders)
216212
{
217-
const ExtruderConfig& extruder_config = extruders_configs.at(extruder_nr);
218-
219213
// Initialize allowed area to full build plate, then remove disallowed areas
220214
Shape& allowed_areas = allowed_areas_per_extruder[extruder_nr];
221215
allowed_areas = storage_.getMachineBorder(extruder_nr);
222216

223217
if (adhesion_type == EPlatformAdhesion::BRIM)
224218
{
219+
const ExtruderConfig& extruder_config = extruders_configs.at(extruder_nr);
225220
const coord_t hole_brim_distance = extruder_config.brim_inside_margin_;
226221

227222
for (size_t other_extruder_nr = 0; other_extruder_nr < covered_area_by_extruder.size(); ++other_extruder_nr)
@@ -264,20 +259,24 @@ std::map<ExtruderNumber, Shape> SkirtBrimAppender::generateAllowedAreas(
264259
}
265260

266261
// Anyway, don't allow a brim/skirt to grow inside itself, which may happen e.g. with ooze shield+skirt
267-
const Shape starting_outline = starting_outlines.at(extruder_nr);
268-
allowed_areas = allowed_areas.difference(starting_outline.offset(extruder_config.gap_ - 50, ClipperLib::jtRound));
262+
const Shape starting_outline = starting_outlines.at(adhesion_type == EPlatformAdhesion::SKIRT ? 0 : extruder_nr);
263+
264+
// When using a skirt, the used gap will be the one of the first processed extruder
265+
const ExtruderNumber gap_extruder_nr = adhesion_type == EPlatformAdhesion::SKIRT ? used_extruders.front() : extruder_nr;
266+
const coord_t gap = extruders_configs.at(gap_extruder_nr).gap_;
267+
allowed_areas = allowed_areas.difference(starting_outline.offset(gap - 50, ClipperLib::jtRound));
269268
}
270269

271270
return allowed_areas_per_extruder;
272271
}
273272

274273
std::vector<ContinuousExtruderMoveSequencePtr> SkirtBrimAppender::generateOffset(
275-
const ExtruderNumber extruder_nr,
276-
const coord_t total_offset,
277-
Shape& covered_area,
278-
std::map<ExtruderNumber, Shape>& allowed_areas_per_extruder,
279-
const std::map<ExtruderNumber, ExtruderConfig>& extruders_configs,
280-
const LayerPlanPtr &layer_plan)
274+
const ExtruderNumber extruder_nr,
275+
const coord_t total_offset,
276+
Shape& covered_area,
277+
std::map<ExtruderNumber, Shape>& allowed_areas_per_extruder,
278+
const std::map<ExtruderNumber, ExtruderConfig>& extruders_configs,
279+
const LayerPlanPtr &layer_plan)
281280
{
282281
const ExtruderConfig &extruder_config = extruders_configs.at(extruder_nr);
283282

@@ -331,8 +330,7 @@ std::vector<ContinuousExtruderMoveSequencePtr> SkirtBrimAppender::generateOffset
331330

332331
void SkirtBrimAppender::generateSkirtBrim(
333332
const EPlatformAdhesion adhesion_type,
334-
const ExtrudersSet &used_extruders,
335-
const std::vector<ConstExtruderPlanPtr> first_extruder_plans,
333+
std::vector<ExtruderNumber>& used_extruders,
336334
const std::map<ExtruderNumber, Shape>& starting_outlines,
337335
std::map<ExtruderNumber, Shape> allowed_areas_per_extruder,
338336
const std::map<ExtruderNumber, ExtruderConfig>& extruders_configs,
@@ -341,62 +339,70 @@ void SkirtBrimAppender::generateSkirtBrim(
341339
struct ExtruderOffsetData
342340
{
343341
ExtruderNumber extruder_nr;
344-
coord_t next_offset;
345342
FeatureExtrusionPtr extrusion;
343+
coord_t total_offset{0};
346344
coord_t extruded_length{0};
347345
bool done{false};
348346
size_t processed_offsets{0};
349347
};
350348

351-
// Create a map containing the processing data for each extruder to be processed
349+
// Create a vector containing the processing data for each extruder to be processed,
350+
// ordered in actual processing order
352351
std::vector<ExtruderOffsetData> extruder_offset_datas;
353352
for (const ExtruderNumber extruder_nr : used_extruders)
354353
{
355354
const ExtruderConfig &extruder_config = extruders_configs.at(extruder_nr);
356355
if (extruder_config.skirt_height_ > layer_plan->getLayerIndex())
357356
{
358-
const coord_t first_offset = extruder_config.gap_ + (extruder_config.line_width_ / 2);
359357
extruder_offset_datas.push_back(ExtruderOffsetData{
360358
.extruder_nr = extruder_nr,
361-
.next_offset = first_offset,
362359
.extrusion = std::make_shared<FeatureExtrusion>(PrintFeatureType::SkirtBrim, extruder_config.line_width_)
363360
});
364361
}
365362
}
366363

367364
// Create a cache containing the extruders processing ordering, we are going to need it extensively
368-
const std::map<ExtruderNumber, size_t> extruder_ordering = [&first_extruder_plans]()
365+
const std::map<ExtruderNumber, size_t> extruder_ordering = [&used_extruders]()
369366
{
370-
size_t ordering = 0;
371367
std::map<ExtruderNumber, size_t> extruder_ordering;
372-
for (const ConstExtruderPlanPtr &extruder_plan : first_extruder_plans)
368+
369+
for (const auto& [index, extruder_number] : used_extruders | ranges::views::enumerate)
373370
{
374-
extruder_ordering[extruder_plan->getExtruderNr()] = ordering++;
371+
extruder_ordering[extruder_number] = index;
375372
}
373+
376374
return extruder_ordering;
377375
}();
378376

379377
std::map<ExtruderNumber, Shape> covered_areas = starting_outlines;
378+
bool first_offset = true;
380379

381380
while (!ranges::all_of(extruder_offset_datas, [](const ExtruderOffsetData &data) {return data.done;}))
382381
{
383-
auto iterator = ranges::min_element(extruder_offset_datas, [&extruder_ordering](const auto &offset1, const auto& offset2)
382+
auto iterator = ranges::min_element(extruder_offset_datas, [&extruder_ordering, &adhesion_type](const auto &offset1, const auto& offset2)
384383
{
385-
if (offset1.next_offset == offset2.next_offset)
384+
if (!offset1.done && !offset2.done)
386385
{
387-
return extruder_ordering.at(offset1.extruder_nr) < extruder_ordering.at(offset2.extruder_nr);
386+
if (adhesion_type == EPlatformAdhesion::SKIRT || offset1.total_offset == offset2.total_offset)
387+
{
388+
return extruder_ordering.at(offset1.extruder_nr) < extruder_ordering.at(offset2.extruder_nr);
389+
}
390+
return offset1.total_offset < offset2.total_offset;
388391
}
389-
return offset1.next_offset < offset2.next_offset;
392+
return !offset1.done;
390393
});
391394

392395
ExtruderOffsetData &extruder_offset_data = *iterator;
393-
extruder_offset_data.processed_offsets++;
394396
const ExtruderNumber extruder_nr = extruder_offset_data.extruder_nr;
395397
const ExtruderConfig &extruder_config = extruders_configs.at(extruder_nr);
398+
const bool add_gap = (adhesion_type == EPlatformAdhesion::SKIRT) ? first_offset : (extruder_offset_data.processed_offsets == 0);
399+
const coord_t offset = (extruder_config.line_width_ / 2) + (add_gap ? extruder_config.gap_ : 0);
400+
extruder_offset_data.processed_offsets++;
401+
extruder_offset_data.total_offset += offset;
396402
const std::vector<ContinuousExtruderMoveSequencePtr> offset_extrusions = generateOffset(
397403
extruder_nr,
398-
extruder_offset_data.next_offset,
399-
covered_areas.at(extruder_nr),
404+
offset,
405+
covered_areas.at(adhesion_type == EPlatformAdhesion::SKIRT ? 0 : extruder_nr),
400406
allowed_areas_per_extruder,
401407
extruders_configs,
402408
layer_plan);
@@ -407,20 +413,31 @@ void SkirtBrimAppender::generateSkirtBrim(
407413
extruder_offset_data.extruded_length += offset_extrusion->calculateLength();
408414
}
409415

410-
extruder_offset_data.next_offset = extruder_config.line_width_ / 2;
411-
412416
if (offset_extrusions.empty() ||
413417
layer_plan->getLayerIndex() > 0 ||
414418
(extruder_offset_data.processed_offsets >= extruder_config.line_count_ && extruder_offset_data.extruded_length >= extruder_config.skirt_brim_minimal_length_))
415419
{
416420
extruder_offset_data.done = true;
417421
}
422+
423+
first_offset = false;
418424
}
419425

420-
for (auto & extrusion : extruder_offset_datas)
426+
// Now add the generated feature to the proper extruder plans
427+
for (auto & extruder_offset_data : extruder_offset_datas)
421428
{
422-
const auto &feature = extrusion.extrusion;
423-
layer_plan->getOperationsAs<ExtruderPlan>().front()->appendFeatureExtrusion(feature);
429+
const auto &feature_extrusion = extruder_offset_data.extrusion;
430+
const ExtruderNumber extruder_nr = extruder_offset_data.extruder_nr;
431+
ExtruderPlanPtr extruder_plan = layer_plan->findFirstExtruderPlan(extruder_nr);
432+
if (!extruder_plan)
433+
{
434+
// FIXME: Find a way to easily create an extruder plan (maybe it should not contain the travel speeds)
435+
const SpeedDerivatives& travel_speed = layer_plan->getConfigsStorage()->travel_config_per_extruder[extruder_nr].speed_derivatives;
436+
extruder_plan = std::make_shared<ExtruderPlan>(extruder_nr, travel_speed);
437+
}
438+
439+
extruder_plan->appendFeatureExtrusion(feature_extrusion);
440+
layer_plan->appendExtruderPlan(extruder_plan);
424441
}
425442
}
426443

src/print_operation/LayerPlan.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,13 @@ Point3LL LayerPlan::getAbsolutePosition(const Point3LL& relative_position) const
6363
return absolute_position;
6464
}
6565

66+
ExtruderPlanPtr LayerPlan::findFirstExtruderPlan(const ExtruderNumber& extruder_nr) const
67+
{
68+
return findOperationByType<ExtruderPlan>(
69+
SearchOrder::Forward,
70+
SearchDepth::DirectChildren,
71+
[&extruder_nr](const ExtruderPlanPtr &extruder_plan) { return extruder_plan->getExtruderNr() == extruder_nr; }
72+
);
73+
}
74+
6675
} // namespace cura

0 commit comments

Comments
 (0)