mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 09:46:09 +08:00
Separate extrusion order utilities to a file.
This commit is contained in:
parent
09453c3a1e
commit
02c615999b
@ -213,6 +213,8 @@ set(SLIC3R_SOURCES
|
|||||||
GCode/AvoidCrossingPerimeters.hpp
|
GCode/AvoidCrossingPerimeters.hpp
|
||||||
GCode/Travels.cpp
|
GCode/Travels.cpp
|
||||||
GCode/Travels.hpp
|
GCode/Travels.hpp
|
||||||
|
GCode/ExtrusionOrder.cpp
|
||||||
|
GCode/ExtrusionOrder.hpp
|
||||||
GCode.cpp
|
GCode.cpp
|
||||||
GCode.hpp
|
GCode.hpp
|
||||||
GCodeReader.cpp
|
GCodeReader.cpp
|
||||||
|
@ -1961,7 +1961,7 @@ void GCodeGenerator::_print_first_layer_extruder_temperatures(GCodeOutputStream
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<InstanceToPrint> GCodeGenerator::sort_print_object_instances(
|
std::vector<GCode::InstanceToPrint> GCodeGenerator::sort_print_object_instances(
|
||||||
const std::vector<ObjectLayerToPrint> &object_layers,
|
const std::vector<ObjectLayerToPrint> &object_layers,
|
||||||
// Ordering must be defined for normal (non-sequential print).
|
// Ordering must be defined for normal (non-sequential print).
|
||||||
const std::vector<const PrintInstance*> *ordering,
|
const std::vector<const PrintInstance*> *ordering,
|
||||||
@ -2283,558 +2283,6 @@ std::string GCodeGenerator::generate_ramping_layer_change_gcode(
|
|||||||
return travel_gcode;
|
return travel_gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace GCode {
|
|
||||||
|
|
||||||
bool is_overriden(const ExtrusionEntityCollection &eec, const LayerTools &layer_tools, const std::size_t instance_id) {
|
|
||||||
return layer_tools.wiping_extrusions().get_extruder_override(&eec, instance_id) > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_extruder_id(
|
|
||||||
const ExtrusionEntityCollection &eec,
|
|
||||||
const LayerTools &layer_tools,
|
|
||||||
const PrintRegion ®ion,
|
|
||||||
const std::size_t instance_id
|
|
||||||
) {
|
|
||||||
if (is_overriden(eec, layer_tools, instance_id)) {
|
|
||||||
return layer_tools.wiping_extrusions().get_extruder_override(&eec, instance_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int extruder_id = layer_tools.extruder(eec, region);
|
|
||||||
if (! layer_tools.has_extruder(extruder_id)) {
|
|
||||||
// Extruder is not in layer_tools - we'll print it by last extruder on this layer (could
|
|
||||||
// happen e.g. when a wiping object is taller than others - dontcare extruders are
|
|
||||||
// eradicated from layer_tools)
|
|
||||||
return layer_tools.extruders.back();
|
|
||||||
}
|
|
||||||
return extruder_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
using ExtractEntityPredicate = std::function<bool(const ExtrusionEntityCollection&, const PrintRegion&)>;
|
|
||||||
|
|
||||||
ExtrusionEntitiesPtr extract_infill_extrusions(
|
|
||||||
const Layer *layer,
|
|
||||||
const PrintRegion ®ion,
|
|
||||||
const ExtrusionEntityCollection &fills,
|
|
||||||
LayerExtrusionRanges::const_iterator begin,
|
|
||||||
LayerExtrusionRanges::const_iterator end,
|
|
||||||
const ExtractEntityPredicate &predicate
|
|
||||||
) {
|
|
||||||
ExtrusionEntitiesPtr result;
|
|
||||||
for (auto it = begin; it != end; ++ it) {
|
|
||||||
assert(it->region() == begin->region());
|
|
||||||
const LayerExtrusionRange &range{*it};
|
|
||||||
for (uint32_t fill_id : range) {
|
|
||||||
assert(dynamic_cast<ExtrusionEntityCollection*>(fills.entities[fill_id]));
|
|
||||||
|
|
||||||
auto *eec{static_cast<ExtrusionEntityCollection*>(fills.entities[fill_id])};
|
|
||||||
if (eec == nullptr || eec->empty() || !predicate(*eec, region)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eec->can_reverse()) {
|
|
||||||
// Flatten the infill collection for better path planning.
|
|
||||||
for (auto *ee : eec->entities) {
|
|
||||||
result.emplace_back(ee);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.emplace_back(eec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ExtrusionEntity *> extract_perimeter_extrusions(
|
|
||||||
const Print &print,
|
|
||||||
const Layer *layer,
|
|
||||||
const LayerIsland &island,
|
|
||||||
const ExtractEntityPredicate &predicate
|
|
||||||
) {
|
|
||||||
std::vector<ExtrusionEntity *> result;
|
|
||||||
|
|
||||||
const LayerRegion &layerm = *layer->get_region(island.perimeters.region());
|
|
||||||
const PrintRegion ®ion = print.get_print_region(layerm.region().print_region_id());
|
|
||||||
|
|
||||||
for (uint32_t perimeter_id : island.perimeters) {
|
|
||||||
// Extrusions inside islands are expected to be ordered already.
|
|
||||||
// Don't reorder them.
|
|
||||||
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm.perimeters().entities[perimeter_id]));
|
|
||||||
auto *eec = static_cast<ExtrusionEntityCollection*>(layerm.perimeters().entities[perimeter_id]);
|
|
||||||
if (eec == nullptr || eec->empty() || !predicate(*eec, region)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ExtrusionEntity *ee : *eec) {
|
|
||||||
result.push_back(ee);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ExtrusionEntityReference> sort_fill_extrusions(const ExtrusionEntitiesPtr &fills, const Point* start_near) {
|
|
||||||
if (fills.empty()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
std::vector<ExtrusionEntityReference> sorted_extrusions;
|
|
||||||
|
|
||||||
for (const ExtrusionEntityReference &fill : chain_extrusion_references(fills, start_near)) {
|
|
||||||
if (auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(&fill.extrusion_entity()); eec) {
|
|
||||||
for (const ExtrusionEntityReference &ee : chain_extrusion_references(*eec, start_near, fill.flipped())) {
|
|
||||||
sorted_extrusions.push_back(ee);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sorted_extrusions.push_back(fill);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sorted_extrusions;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<InfillRange> extract_infill_ranges(
|
|
||||||
const Print &print,
|
|
||||||
const Layer *layer,
|
|
||||||
const LayerIsland island,
|
|
||||||
std::optional<Point> previous_position,
|
|
||||||
const ExtractEntityPredicate &predicate
|
|
||||||
) {
|
|
||||||
std::vector<InfillRange> result;
|
|
||||||
for (auto it = island.fills.begin(); it != island.fills.end();) {
|
|
||||||
// Gather range of fill ranges with the same region.
|
|
||||||
auto it_end = it;
|
|
||||||
for (++ it_end; it_end != island.fills.end() && it->region() == it_end->region(); ++ it_end) ;
|
|
||||||
const LayerRegion &layerm = *layer->get_region(it->region());
|
|
||||||
// PrintObjects own the PrintRegions, thus the pointer to PrintRegion would be unique to a PrintObject, they would not
|
|
||||||
// identify the content of PrintRegion accross the whole print uniquely. Translate to a Print specific PrintRegion.
|
|
||||||
const PrintRegion ®ion = print.get_print_region(layerm.region().print_region_id());
|
|
||||||
|
|
||||||
const Point* start_near = previous_position ? &(*(previous_position)) : nullptr;
|
|
||||||
|
|
||||||
ExtrusionEntitiesPtr extrusions{extract_infill_extrusions(
|
|
||||||
layer,
|
|
||||||
region,
|
|
||||||
layerm.fills(),
|
|
||||||
it,
|
|
||||||
it_end,
|
|
||||||
predicate
|
|
||||||
)};
|
|
||||||
|
|
||||||
const std::vector<ExtrusionEntityReference> sorted_extrusions{sort_fill_extrusions(extrusions, start_near)};
|
|
||||||
|
|
||||||
if (! sorted_extrusions.empty()) {
|
|
||||||
result.push_back({sorted_extrusions, ®ion});
|
|
||||||
previous_position = sorted_extrusions.back().flipped() ?
|
|
||||||
sorted_extrusions.back().extrusion_entity().first_point() :
|
|
||||||
sorted_extrusions.back().extrusion_entity().last_point();
|
|
||||||
}
|
|
||||||
it = it_end;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} // namespace GCode
|
|
||||||
|
|
||||||
void place_seams(
|
|
||||||
const Layer *layer, const Seams::Placer &seam_placer, const std::vector<ExtrusionEntity *> &perimeters, std::optional<Point> previous_position, const bool spiral_vase
|
|
||||||
) {
|
|
||||||
std::vector<const ExtrusionEntity *> result;
|
|
||||||
result.reserve(perimeters.size());
|
|
||||||
|
|
||||||
for (ExtrusionEntity* perimeter : perimeters) {
|
|
||||||
auto loop{static_cast<ExtrusionLoop *>(perimeter)};
|
|
||||||
|
|
||||||
Point seam_point{previous_position ? *previous_position : Point::Zero()};
|
|
||||||
if (!spiral_vase && loop != nullptr) {
|
|
||||||
assert(m_layer != nullptr);
|
|
||||||
seam_point = seam_placer.place_seam(layer, *loop, seam_point);
|
|
||||||
loop->seam = seam_point;
|
|
||||||
}
|
|
||||||
previous_position = seam_point;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GCodeGenerator::extrude_infill_range(
|
|
||||||
const std::vector<ExtrusionEntityReference> &sorted_extrusions,
|
|
||||||
const PrintRegion ®ion,
|
|
||||||
const std::string &extrusion_name,
|
|
||||||
const GCode::SmoothPathCache &smooth_path_cache
|
|
||||||
) {
|
|
||||||
std::string gcode{};
|
|
||||||
if (!sorted_extrusions.empty()) {
|
|
||||||
this->m_config.apply(region.config());
|
|
||||||
|
|
||||||
for (const ExtrusionEntityReference &ee : sorted_extrusions) {
|
|
||||||
gcode += this->extrude_entity(ee, smooth_path_cache, extrusion_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gcode;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string GCodeGenerator::extrude_infill_ranges(
|
|
||||||
const std::vector<GCode::InfillRange> &infill_ranges,
|
|
||||||
const std::string &comment,
|
|
||||||
const GCode::SmoothPathCache &smooth_path_cache
|
|
||||||
) {
|
|
||||||
std::string gcode{};
|
|
||||||
for (const GCode::InfillRange &infill_range : infill_ranges) {
|
|
||||||
gcode += this->extrude_infill_range(
|
|
||||||
infill_range.items, *infill_range.region, comment, smooth_path_cache
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return gcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const auto comment_perimeter = "perimeter"sv;
|
|
||||||
// Comparing string_view pointer & length for speed.
|
|
||||||
static inline bool comment_is_perimeter(const std::string_view comment) {
|
|
||||||
return comment.data() == comment_perimeter.data() && comment.size() == comment_perimeter.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GCodeGenerator::extrude_perimeters(
|
|
||||||
const Print &print,
|
|
||||||
const PrintRegion ®ion,
|
|
||||||
const std::vector<ExtrusionEntity *> &perimeters,
|
|
||||||
const InstanceToPrint &print_instance,
|
|
||||||
const GCode::SmoothPathCache &smooth_path_cache
|
|
||||||
) {
|
|
||||||
if (!perimeters.empty()) {
|
|
||||||
m_config.apply(region.config());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string gcode{};
|
|
||||||
|
|
||||||
for (const ExtrusionEntity *ee : perimeters) {
|
|
||||||
// Don't reorder, don't flip.
|
|
||||||
gcode += this->extrude_entity(
|
|
||||||
{*ee, false}, smooth_path_cache, comment_perimeter, -1.
|
|
||||||
);
|
|
||||||
this->m_travel_obstacle_tracker.mark_extruded(
|
|
||||||
ee, print_instance.object_layer_to_print_id, print_instance.instance_id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return gcode;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IslandExtrusions {
|
|
||||||
const PrintRegion *region;
|
|
||||||
std::vector<ExtrusionEntity *> perimeters;
|
|
||||||
std::vector<GCode::InfillRange> infill_ranges;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SliceExtrusions {
|
|
||||||
std::vector<IslandExtrusions> common_extrusions;
|
|
||||||
std::vector<GCode::InfillRange> ironing_extrusions;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::optional<Point> get_last_position(const std::vector<GCode::InfillRange> &infill_ranges) {
|
|
||||||
if (!infill_ranges.empty() && !infill_ranges.back().items.empty()) {
|
|
||||||
const ExtrusionEntityReference &last_infill{infill_ranges.back().items.back()};
|
|
||||||
return last_infill.flipped() ? last_infill.extrusion_entity().first_point() :
|
|
||||||
last_infill.extrusion_entity().last_point();
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Point> get_last_position(const ExtrusionEntityReferences &extrusions) {
|
|
||||||
if (!extrusions.empty()) {
|
|
||||||
const ExtrusionEntityReference &last_extrusion{extrusions.back()};
|
|
||||||
return last_extrusion.flipped() ? last_extrusion.extrusion_entity().first_point() :
|
|
||||||
last_extrusion.extrusion_entity().last_point();
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Point> get_last_position(const std::vector<ExtrusionEntity *> &perimeters){
|
|
||||||
if (!perimeters.empty()) {
|
|
||||||
auto last_perimeter{static_cast<const ExtrusionLoop *>(perimeters.back())};
|
|
||||||
if (last_perimeter != nullptr) {
|
|
||||||
return last_perimeter->seam;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Point> get_last_position(const std::vector<SliceExtrusions> &slice_extrusions, const bool infill_first) {
|
|
||||||
if (slice_extrusions.empty()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const SliceExtrusions &last_slice{slice_extrusions.back()};
|
|
||||||
if (!last_slice.ironing_extrusions.empty()) {
|
|
||||||
return get_last_position(slice_extrusions.back().ironing_extrusions);
|
|
||||||
}
|
|
||||||
if (last_slice.common_extrusions.empty()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const IslandExtrusions last_island{last_slice.common_extrusions.back()};
|
|
||||||
if (infill_first) {
|
|
||||||
if (!last_island.perimeters.empty()) {
|
|
||||||
return get_last_position(last_island.perimeters);
|
|
||||||
}
|
|
||||||
return get_last_position(last_island.infill_ranges);
|
|
||||||
} else {
|
|
||||||
if (!last_island.infill_ranges.empty()) {
|
|
||||||
return get_last_position(last_island.infill_ranges);
|
|
||||||
}
|
|
||||||
return get_last_position(last_island.perimeters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<IslandExtrusions> extract_island_extrusions(
|
|
||||||
const LayerSlice &lslice,
|
|
||||||
const Print &print,
|
|
||||||
const Layer *layer,
|
|
||||||
const Seams::Placer &seam_placer,
|
|
||||||
const bool spiral_vase,
|
|
||||||
const GCode::ExtractEntityPredicate &predicate,
|
|
||||||
std::optional<Point> &previous_position
|
|
||||||
) {
|
|
||||||
std::vector<IslandExtrusions> result;
|
|
||||||
for (const LayerIsland &island : lslice.islands) {
|
|
||||||
const LayerRegion &layerm = *layer->get_region(island.perimeters.region());
|
|
||||||
// PrintObjects own the PrintRegions, thus the pointer to PrintRegion would be
|
|
||||||
// unique to a PrintObject, they would not identify the content of PrintRegion
|
|
||||||
// accross the whole print uniquely. Translate to a Print specific PrintRegion.
|
|
||||||
const PrintRegion ®ion = print.get_print_region(layerm.region().print_region_id());
|
|
||||||
|
|
||||||
const auto infill_predicate = [&](const auto &eec, const auto ®ion) {
|
|
||||||
return predicate(eec, region) && eec.role() != ExtrusionRole::Ironing;
|
|
||||||
};
|
|
||||||
|
|
||||||
result.push_back(IslandExtrusions{®ion});
|
|
||||||
IslandExtrusions &island_extrusions{result.back()};
|
|
||||||
|
|
||||||
island_extrusions.perimeters = GCode::extract_perimeter_extrusions(print, layer, island, predicate);
|
|
||||||
|
|
||||||
if (print.config().infill_first) {
|
|
||||||
island_extrusions.infill_ranges = GCode::extract_infill_ranges(
|
|
||||||
print, layer, island, previous_position, infill_predicate
|
|
||||||
);
|
|
||||||
if (const auto last_position = get_last_position(island_extrusions.infill_ranges)) {
|
|
||||||
previous_position = last_position;
|
|
||||||
}
|
|
||||||
|
|
||||||
place_seams(layer, seam_placer, island_extrusions.perimeters, previous_position, spiral_vase);
|
|
||||||
|
|
||||||
if (const auto last_position = get_last_position(island_extrusions.perimeters)) {
|
|
||||||
previous_position = last_position;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
place_seams(layer, seam_placer, island_extrusions.perimeters, previous_position, spiral_vase);
|
|
||||||
|
|
||||||
if (const auto last_position = get_last_position(island_extrusions.perimeters)) {
|
|
||||||
previous_position = last_position;
|
|
||||||
}
|
|
||||||
island_extrusions.infill_ranges = {GCode::extract_infill_ranges(
|
|
||||||
print, layer, island, previous_position, infill_predicate
|
|
||||||
)};
|
|
||||||
if (const auto last_position = get_last_position(island_extrusions.infill_ranges)) {
|
|
||||||
previous_position = last_position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<GCode::InfillRange> extract_ironing_extrusions(
|
|
||||||
const LayerSlice &lslice,
|
|
||||||
const Print &print,
|
|
||||||
const Layer *layer,
|
|
||||||
const GCode::ExtractEntityPredicate &predicate,
|
|
||||||
std::optional<Point> &previous_position
|
|
||||||
) {
|
|
||||||
std::vector<GCode::InfillRange> result;
|
|
||||||
|
|
||||||
for (const LayerIsland &island : lslice.islands) {
|
|
||||||
const auto ironing_predicate = [&](const auto &eec, const auto ®ion) {
|
|
||||||
return predicate(eec, region) && eec.role() == ExtrusionRole::Ironing;
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<GCode::InfillRange> ironing_ranges{GCode::extract_infill_ranges(
|
|
||||||
print, layer, island, previous_position, ironing_predicate
|
|
||||||
)};
|
|
||||||
result.insert(
|
|
||||||
result.end(), ironing_ranges.begin(), ironing_ranges.end()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (const auto last_position = get_last_position(ironing_ranges)) {
|
|
||||||
previous_position = last_position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<SliceExtrusions> get_slices_extrusions(
|
|
||||||
const Print &print,
|
|
||||||
const Layer *layer,
|
|
||||||
const Seams::Placer &seam_placer,
|
|
||||||
std::optional<Point> previous_position,
|
|
||||||
const bool spiral_vase,
|
|
||||||
const GCode::ExtractEntityPredicate &predicate
|
|
||||||
) {
|
|
||||||
// Note: ironing.
|
|
||||||
// FIXME move ironing into the loop above over LayerIslands?
|
|
||||||
// First Ironing changes extrusion rate quickly, second single ironing may be done over
|
|
||||||
// multiple perimeter regions. Ironing in a second phase is safer, but it may be less
|
|
||||||
// efficient.
|
|
||||||
|
|
||||||
std::vector<SliceExtrusions> result;
|
|
||||||
|
|
||||||
for (size_t idx : layer->lslice_indices_sorted_by_print_order) {
|
|
||||||
const LayerSlice &lslice = layer->lslices_ex[idx];
|
|
||||||
result.emplace_back(SliceExtrusions{
|
|
||||||
extract_island_extrusions(
|
|
||||||
lslice, print, layer, seam_placer, spiral_vase, predicate, previous_position
|
|
||||||
),
|
|
||||||
extract_ironing_extrusions(lslice, print, layer, predicate, previous_position)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned translate_support_extruder(
|
|
||||||
const int configured_extruder,
|
|
||||||
const LayerTools &layer_tools,
|
|
||||||
const ConfigOptionBools &is_soluable
|
|
||||||
) {
|
|
||||||
if (configured_extruder <= 0) {
|
|
||||||
// Some support will be printed with "don't care" material, preferably non-soluble.
|
|
||||||
// Is the current extruder assigned a soluble filament?
|
|
||||||
auto it_nonsoluble = std::find_if(layer_tools.extruders.begin(), layer_tools.extruders.end(),
|
|
||||||
[&is_soluable](unsigned int extruder_id) { return ! is_soluable.get_at(extruder_id); });
|
|
||||||
// There should be a non-soluble extruder available.
|
|
||||||
assert(it_nonsoluble != layer_tools.extruders.end());
|
|
||||||
return it_nonsoluble == layer_tools.extruders.end() ? layer_tools.extruders.front() : *it_nonsoluble;
|
|
||||||
} else {
|
|
||||||
return configured_extruder - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtrusionEntityReferences get_support_extrusions(
|
|
||||||
const unsigned int extruder_id,
|
|
||||||
const GCode::ObjectLayerToPrint &layer_to_print,
|
|
||||||
unsigned int support_extruder,
|
|
||||||
unsigned int interface_extruder
|
|
||||||
) {
|
|
||||||
if (const SupportLayer &support_layer = *layer_to_print.support_layer;
|
|
||||||
!support_layer.support_fills.entities.empty()) {
|
|
||||||
ExtrusionRole role = support_layer.support_fills.role();
|
|
||||||
bool has_support = role.is_mixed() || role.is_support_base();
|
|
||||||
bool has_interface = role.is_mixed() || role.is_support_interface();
|
|
||||||
|
|
||||||
bool extrude_support = has_support && support_extruder == extruder_id;
|
|
||||||
bool extrude_interface = has_interface && interface_extruder == extruder_id;
|
|
||||||
|
|
||||||
if (extrude_support || extrude_interface) {
|
|
||||||
ExtrusionEntitiesPtr entities_cache;
|
|
||||||
const ExtrusionEntitiesPtr &entities = extrude_support && extrude_interface ?
|
|
||||||
support_layer.support_fills.entities :
|
|
||||||
entities_cache;
|
|
||||||
if (!extrude_support || !extrude_interface) {
|
|
||||||
auto role = extrude_support ? ExtrusionRole::SupportMaterial :
|
|
||||||
ExtrusionRole::SupportMaterialInterface;
|
|
||||||
entities_cache.reserve(support_layer.support_fills.entities.size());
|
|
||||||
for (ExtrusionEntity *ee : support_layer.support_fills.entities)
|
|
||||||
if (ee->role() == role)
|
|
||||||
entities_cache.emplace_back(ee);
|
|
||||||
}
|
|
||||||
return chain_extrusion_references(entities);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::vector<SliceExtrusions>> get_overriden_extrusions(
|
|
||||||
const Print &print,
|
|
||||||
const GCode::ObjectsLayerToPrint &layers,
|
|
||||||
const LayerTools &layer_tools,
|
|
||||||
const std::vector<InstanceToPrint> &instances_to_print,
|
|
||||||
const Seams::Placer &seam_placer,
|
|
||||||
const bool spiral_vase,
|
|
||||||
const unsigned int extruder_id,
|
|
||||||
std::optional<Point> &previous_position
|
|
||||||
) {
|
|
||||||
std::vector<std::vector<SliceExtrusions>> result;
|
|
||||||
|
|
||||||
for (const InstanceToPrint &instance : instances_to_print) {
|
|
||||||
if (const Layer *layer = layers[instance.object_layer_to_print_id].object_layer; layer) {
|
|
||||||
const auto predicate = [&](const ExtrusionEntityCollection &entity_collection,
|
|
||||||
const PrintRegion ®ion) {
|
|
||||||
if (!GCode::is_overriden(entity_collection, layer_tools, instance.instance_id)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GCode::get_extruder_id(
|
|
||||||
entity_collection, layer_tools, region, instance.instance_id
|
|
||||||
) != extruder_id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
result.emplace_back(get_slices_extrusions(
|
|
||||||
print, layer, seam_placer, previous_position, spiral_vase, predicate
|
|
||||||
));
|
|
||||||
previous_position = get_last_position(result.back(), print.config().infill_first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NormalExtrusions {
|
|
||||||
ExtrusionEntityReferences support_extrusions;
|
|
||||||
std::vector<SliceExtrusions> slices_extrusions;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<NormalExtrusions> get_normal_extrusions(
|
|
||||||
const Print &print,
|
|
||||||
const GCode::ObjectsLayerToPrint &layers,
|
|
||||||
const LayerTools &layer_tools,
|
|
||||||
const std::vector<InstanceToPrint> &instances_to_print,
|
|
||||||
const Seams::Placer &seam_placer,
|
|
||||||
const bool spiral_vase,
|
|
||||||
const unsigned int extruder_id,
|
|
||||||
std::optional<Point> &previous_position
|
|
||||||
) {
|
|
||||||
std::vector<NormalExtrusions> result;
|
|
||||||
|
|
||||||
for (std::size_t i{0}; i < instances_to_print.size(); ++i) {
|
|
||||||
const InstanceToPrint &instance{instances_to_print[i]};
|
|
||||||
result.emplace_back();
|
|
||||||
|
|
||||||
if (layers[instance.object_layer_to_print_id].support_layer != nullptr) {
|
|
||||||
result.back().support_extrusions = get_support_extrusions(
|
|
||||||
extruder_id,
|
|
||||||
layers[instance.object_layer_to_print_id],
|
|
||||||
translate_support_extruder(instance.print_object.config().support_material_extruder.value, layer_tools, print.config().filament_soluble),
|
|
||||||
translate_support_extruder(instance.print_object.config().support_material_interface_extruder.value, layer_tools, print.config().filament_soluble)
|
|
||||||
);
|
|
||||||
previous_position = get_last_position(result.back().support_extrusions);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const Layer *layer = layers[instance.object_layer_to_print_id].object_layer; layer) {
|
|
||||||
const auto predicate = [&](const ExtrusionEntityCollection &entity_collection, const PrintRegion ®ion){
|
|
||||||
if (GCode::is_overriden(entity_collection, layer_tools, instance.instance_id)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GCode::get_extruder_id(entity_collection, layer_tools, region, instance.instance_id) != extruder_id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
result.back().slices_extrusions = get_slices_extrusions(
|
|
||||||
print,
|
|
||||||
layer,
|
|
||||||
seam_placer,
|
|
||||||
previous_position,
|
|
||||||
spiral_vase,
|
|
||||||
predicate
|
|
||||||
);
|
|
||||||
previous_position = get_last_position(result.back().slices_extrusions, print.config().infill_first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In sequential mode, process_layer is called once per each object and its copy,
|
// In sequential mode, process_layer is called once per each object and its copy,
|
||||||
// therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object.
|
// therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object.
|
||||||
// In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
|
// In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
|
||||||
@ -3041,12 +2489,15 @@ LayerResult GCodeGenerator::process_layer(
|
|||||||
skirt.emplace_back(i, print.skirt().entities[i]);
|
skirt.emplace_back(i, print.skirt().entities[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using GCode::ExtrusionOrder::get_last_position;
|
||||||
ExtrusionEntitiesPtr brim;
|
ExtrusionEntitiesPtr brim;
|
||||||
if (!m_brim_done) {
|
if (!m_brim_done) {
|
||||||
brim = print.brim().entities;
|
brim = print.brim().entities;
|
||||||
previous_position = get_last_position(brim);
|
previous_position = get_last_position(brim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using GCode::ExtrusionOrder::get_overriden_extrusions;
|
||||||
bool is_anything_overridden = layer_tools.wiping_extrusions().is_anything_overridden();
|
bool is_anything_overridden = layer_tools.wiping_extrusions().is_anything_overridden();
|
||||||
std::vector<std::vector<SliceExtrusions>> overriden_extrusions;
|
std::vector<std::vector<SliceExtrusions>> overriden_extrusions;
|
||||||
if (is_anything_overridden) {
|
if (is_anything_overridden) {
|
||||||
@ -3056,6 +2507,8 @@ LayerResult GCodeGenerator::process_layer(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using GCode::ExtrusionOrder::get_normal_extrusions;
|
||||||
|
using GCode::ExtrusionOrder::NormalExtrusions;
|
||||||
const std::vector<NormalExtrusions> normal_extrusions{get_normal_extrusions(
|
const std::vector<NormalExtrusions> normal_extrusions{get_normal_extrusions(
|
||||||
print, layers, layer_tools, instances_to_print, this->m_seam_placer,
|
print, layers, layer_tools, instances_to_print, this->m_seam_placer,
|
||||||
this->m_config.spiral_vase, extruder_id, previous_position
|
this->m_config.spiral_vase, extruder_id, previous_position
|
||||||
@ -3212,6 +2665,12 @@ LayerResult GCodeGenerator::process_layer(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const auto comment_perimeter = "perimeter"sv;
|
||||||
|
// Comparing string_view pointer & length for speed.
|
||||||
|
static inline bool comment_is_perimeter(const std::string_view comment) {
|
||||||
|
return comment.data() == comment_perimeter.data() && comment.size() == comment_perimeter.size();
|
||||||
|
}
|
||||||
|
|
||||||
void GCodeGenerator::process_layer_single_object(
|
void GCodeGenerator::process_layer_single_object(
|
||||||
std::string &gcode,
|
std::string &gcode,
|
||||||
const InstanceToPrint &print_instance,
|
const InstanceToPrint &print_instance,
|
||||||
@ -3510,6 +2969,62 @@ std::string GCodeGenerator::extrude_skirt(
|
|||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GCodeGenerator::extrude_infill_range(
|
||||||
|
const std::vector<ExtrusionEntityReference> &sorted_extrusions,
|
||||||
|
const PrintRegion ®ion,
|
||||||
|
const std::string &extrusion_name,
|
||||||
|
const GCode::SmoothPathCache &smooth_path_cache
|
||||||
|
) {
|
||||||
|
std::string gcode{};
|
||||||
|
if (!sorted_extrusions.empty()) {
|
||||||
|
this->m_config.apply(region.config());
|
||||||
|
|
||||||
|
for (const ExtrusionEntityReference &ee : sorted_extrusions) {
|
||||||
|
gcode += this->extrude_entity(ee, smooth_path_cache, extrusion_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gcode;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string GCodeGenerator::extrude_infill_ranges(
|
||||||
|
const std::vector<InfillRange> &infill_ranges,
|
||||||
|
const std::string &comment,
|
||||||
|
const GCode::SmoothPathCache &smooth_path_cache
|
||||||
|
) {
|
||||||
|
std::string gcode{};
|
||||||
|
for (const InfillRange &infill_range : infill_ranges) {
|
||||||
|
gcode += this->extrude_infill_range(
|
||||||
|
infill_range.items, *infill_range.region, comment, smooth_path_cache
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return gcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GCodeGenerator::extrude_perimeters(
|
||||||
|
const Print &print,
|
||||||
|
const PrintRegion ®ion,
|
||||||
|
const std::vector<ExtrusionEntity *> &perimeters,
|
||||||
|
const InstanceToPrint &print_instance,
|
||||||
|
const GCode::SmoothPathCache &smooth_path_cache
|
||||||
|
) {
|
||||||
|
if (!perimeters.empty()) {
|
||||||
|
m_config.apply(region.config());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gcode{};
|
||||||
|
|
||||||
|
for (const ExtrusionEntity *ee : perimeters) {
|
||||||
|
// Don't reorder, don't flip.
|
||||||
|
gcode += this->extrude_entity(
|
||||||
|
{*ee, false}, smooth_path_cache, comment_perimeter, -1.
|
||||||
|
);
|
||||||
|
this->m_travel_obstacle_tracker.mark_extruded(
|
||||||
|
ee, print_instance.object_layer_to_print_id, print_instance.instance_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return gcode;
|
||||||
|
};
|
||||||
|
|
||||||
std::string GCodeGenerator::extrude_multi_path(const ExtrusionMultiPath &multipath, bool reverse, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed)
|
std::string GCodeGenerator::extrude_multi_path(const ExtrusionMultiPath &multipath, bool reverse, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#ifndef slic3r_GCode_hpp_
|
#ifndef slic3r_GCode_hpp_
|
||||||
#define slic3r_GCode_hpp_
|
#define slic3r_GCode_hpp_
|
||||||
|
|
||||||
|
#include "libslic3r/GCode/ExtrusionOrder.hpp"
|
||||||
#include "libslic3r/GCode/ExtrusionProcessor.hpp"
|
#include "libslic3r/GCode/ExtrusionProcessor.hpp"
|
||||||
#include "JumpPointSearch.hpp"
|
#include "JumpPointSearch.hpp"
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
@ -54,7 +55,6 @@ namespace Slic3r {
|
|||||||
// Forward declarations.
|
// Forward declarations.
|
||||||
class GCodeGenerator;
|
class GCodeGenerator;
|
||||||
struct WipeTowerData;
|
struct WipeTowerData;
|
||||||
struct SliceExtrusions;
|
|
||||||
|
|
||||||
namespace { struct Item; }
|
namespace { struct Item; }
|
||||||
struct PrintInstance;
|
struct PrintInstance;
|
||||||
@ -93,18 +93,6 @@ struct LayerResult {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace GCode {
|
namespace GCode {
|
||||||
// Object and support extrusions of the same PrintObject at the same print_z.
|
|
||||||
// public, so that it could be accessed by free helper functions from GCode.cpp
|
|
||||||
struct ObjectLayerToPrint
|
|
||||||
{
|
|
||||||
ObjectLayerToPrint() : object_layer(nullptr), support_layer(nullptr) {}
|
|
||||||
const Layer* object_layer;
|
|
||||||
const SupportLayer* support_layer;
|
|
||||||
const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
|
|
||||||
const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
|
|
||||||
coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PrintObjectInstance
|
struct PrintObjectInstance
|
||||||
{
|
{
|
||||||
const PrintObject *print_object = nullptr;
|
const PrintObject *print_object = nullptr;
|
||||||
@ -114,25 +102,8 @@ struct PrintObjectInstance
|
|||||||
bool operator!=(const PrintObjectInstance &other) const { return !(*this == other); }
|
bool operator!=(const PrintObjectInstance &other) const { return !(*this == other); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InfillRange {
|
|
||||||
std::vector<ExtrusionEntityReference> items;
|
|
||||||
const PrintRegion *region;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace GCode
|
} // namespace GCode
|
||||||
|
|
||||||
struct InstanceToPrint
|
|
||||||
{
|
|
||||||
InstanceToPrint(size_t object_layer_to_print_id, const PrintObject &print_object, size_t instance_id) :
|
|
||||||
object_layer_to_print_id(object_layer_to_print_id), print_object(print_object), instance_id(instance_id) {}
|
|
||||||
|
|
||||||
// Index into std::vector<ObjectLayerToPrint>, which contains Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances.
|
|
||||||
const size_t object_layer_to_print_id;
|
|
||||||
const PrintObject &print_object;
|
|
||||||
// Instance idx of the copy of a print object.
|
|
||||||
const size_t instance_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GCodeGenerator {
|
class GCodeGenerator {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -196,11 +167,16 @@ public:
|
|||||||
static void encode_full_config(const Print& print, std::vector<std::pair<std::string, std::string>>& config);
|
static void encode_full_config(const Print& print, std::vector<std::pair<std::string, std::string>>& config);
|
||||||
|
|
||||||
using ObjectLayerToPrint = GCode::ObjectLayerToPrint;
|
using ObjectLayerToPrint = GCode::ObjectLayerToPrint;
|
||||||
using ObjectsLayerToPrint = std::vector<GCode::ObjectLayerToPrint>;
|
using ObjectsLayerToPrint = GCode::ObjectsLayerToPrint;
|
||||||
|
|
||||||
std::optional<Point> last_position;
|
std::optional<Point> last_position;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using InstanceToPrint = GCode::InstanceToPrint;
|
||||||
|
using InfillRange = GCode::ExtrusionOrder::InfillRange;
|
||||||
|
using SliceExtrusions = GCode::ExtrusionOrder::SliceExtrusions;
|
||||||
|
using IslandExtrusions = GCode::ExtrusionOrder::IslandExtrusions;
|
||||||
|
|
||||||
class GCodeOutputStream {
|
class GCodeOutputStream {
|
||||||
public:
|
public:
|
||||||
GCodeOutputStream(FILE *f, GCodeProcessor &processor) : f(f), m_processor(processor) {}
|
GCodeOutputStream(FILE *f, GCodeProcessor &processor) : f(f), m_processor(processor) {}
|
||||||
@ -327,7 +303,7 @@ private:
|
|||||||
);
|
);
|
||||||
|
|
||||||
std::string extrude_infill_ranges(
|
std::string extrude_infill_ranges(
|
||||||
const std::vector<GCode::InfillRange> &infill_ranges,
|
const std::vector<InfillRange> &infill_ranges,
|
||||||
const std::string &commment,
|
const std::string &commment,
|
||||||
const GCode::SmoothPathCache &smooth_path_cache
|
const GCode::SmoothPathCache &smooth_path_cache
|
||||||
);
|
);
|
||||||
|
474
src/libslic3r/GCode/ExtrusionOrder.cpp
Normal file
474
src/libslic3r/GCode/ExtrusionOrder.cpp
Normal file
@ -0,0 +1,474 @@
|
|||||||
|
#include "ExtrusionOrder.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r::GCode::ExtrusionOrder {
|
||||||
|
|
||||||
|
bool is_overriden(const ExtrusionEntityCollection &eec, const LayerTools &layer_tools, const std::size_t instance_id) {
|
||||||
|
return layer_tools.wiping_extrusions().get_extruder_override(&eec, instance_id) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_extruder_id(
|
||||||
|
const ExtrusionEntityCollection &eec,
|
||||||
|
const LayerTools &layer_tools,
|
||||||
|
const PrintRegion ®ion,
|
||||||
|
const std::size_t instance_id
|
||||||
|
) {
|
||||||
|
if (is_overriden(eec, layer_tools, instance_id)) {
|
||||||
|
return layer_tools.wiping_extrusions().get_extruder_override(&eec, instance_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int extruder_id = layer_tools.extruder(eec, region);
|
||||||
|
if (! layer_tools.has_extruder(extruder_id)) {
|
||||||
|
// Extruder is not in layer_tools - we'll print it by last extruder on this layer (could
|
||||||
|
// happen e.g. when a wiping object is taller than others - dontcare extruders are
|
||||||
|
// eradicated from layer_tools)
|
||||||
|
return layer_tools.extruders.back();
|
||||||
|
}
|
||||||
|
return extruder_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtrusionEntitiesPtr extract_infill_extrusions(
|
||||||
|
const Layer *layer,
|
||||||
|
const PrintRegion ®ion,
|
||||||
|
const ExtrusionEntityCollection &fills,
|
||||||
|
LayerExtrusionRanges::const_iterator begin,
|
||||||
|
LayerExtrusionRanges::const_iterator end,
|
||||||
|
const ExtractEntityPredicate &predicate
|
||||||
|
) {
|
||||||
|
ExtrusionEntitiesPtr result;
|
||||||
|
for (auto it = begin; it != end; ++ it) {
|
||||||
|
assert(it->region() == begin->region());
|
||||||
|
const LayerExtrusionRange &range{*it};
|
||||||
|
for (uint32_t fill_id : range) {
|
||||||
|
assert(dynamic_cast<ExtrusionEntityCollection*>(fills.entities[fill_id]));
|
||||||
|
|
||||||
|
auto *eec{static_cast<ExtrusionEntityCollection*>(fills.entities[fill_id])};
|
||||||
|
if (eec == nullptr || eec->empty() || !predicate(*eec, region)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eec->can_reverse()) {
|
||||||
|
// Flatten the infill collection for better path planning.
|
||||||
|
for (auto *ee : eec->entities) {
|
||||||
|
result.emplace_back(ee);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.emplace_back(eec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ExtrusionEntity *> extract_perimeter_extrusions(
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const LayerIsland &island,
|
||||||
|
const ExtractEntityPredicate &predicate
|
||||||
|
) {
|
||||||
|
std::vector<ExtrusionEntity *> result;
|
||||||
|
|
||||||
|
const LayerRegion &layerm = *layer->get_region(island.perimeters.region());
|
||||||
|
const PrintRegion ®ion = print.get_print_region(layerm.region().print_region_id());
|
||||||
|
|
||||||
|
for (uint32_t perimeter_id : island.perimeters) {
|
||||||
|
// Extrusions inside islands are expected to be ordered already.
|
||||||
|
// Don't reorder them.
|
||||||
|
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm.perimeters().entities[perimeter_id]));
|
||||||
|
auto *eec = static_cast<ExtrusionEntityCollection*>(layerm.perimeters().entities[perimeter_id]);
|
||||||
|
if (eec == nullptr || eec->empty() || !predicate(*eec, region)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ExtrusionEntity *ee : *eec) {
|
||||||
|
result.push_back(ee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ExtrusionEntityReference> sort_fill_extrusions(const ExtrusionEntitiesPtr &fills, const Point* start_near) {
|
||||||
|
if (fills.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::vector<ExtrusionEntityReference> sorted_extrusions;
|
||||||
|
|
||||||
|
for (const ExtrusionEntityReference &fill : chain_extrusion_references(fills, start_near)) {
|
||||||
|
if (auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(&fill.extrusion_entity()); eec) {
|
||||||
|
for (const ExtrusionEntityReference &ee : chain_extrusion_references(*eec, start_near, fill.flipped())) {
|
||||||
|
sorted_extrusions.push_back(ee);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sorted_extrusions.push_back(fill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sorted_extrusions;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<InfillRange> extract_infill_ranges(
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const LayerIsland island,
|
||||||
|
std::optional<Point> previous_position,
|
||||||
|
const ExtractEntityPredicate &predicate
|
||||||
|
) {
|
||||||
|
std::vector<InfillRange> result;
|
||||||
|
for (auto it = island.fills.begin(); it != island.fills.end();) {
|
||||||
|
// Gather range of fill ranges with the same region.
|
||||||
|
auto it_end = it;
|
||||||
|
for (++ it_end; it_end != island.fills.end() && it->region() == it_end->region(); ++ it_end) ;
|
||||||
|
const LayerRegion &layerm = *layer->get_region(it->region());
|
||||||
|
// PrintObjects own the PrintRegions, thus the pointer to PrintRegion would be unique to a PrintObject, they would not
|
||||||
|
// identify the content of PrintRegion accross the whole print uniquely. Translate to a Print specific PrintRegion.
|
||||||
|
const PrintRegion ®ion = print.get_print_region(layerm.region().print_region_id());
|
||||||
|
|
||||||
|
const Point* start_near = previous_position ? &(*(previous_position)) : nullptr;
|
||||||
|
|
||||||
|
ExtrusionEntitiesPtr extrusions{extract_infill_extrusions(
|
||||||
|
layer,
|
||||||
|
region,
|
||||||
|
layerm.fills(),
|
||||||
|
it,
|
||||||
|
it_end,
|
||||||
|
predicate
|
||||||
|
)};
|
||||||
|
|
||||||
|
const std::vector<ExtrusionEntityReference> sorted_extrusions{sort_fill_extrusions(extrusions, start_near)};
|
||||||
|
|
||||||
|
if (! sorted_extrusions.empty()) {
|
||||||
|
result.push_back({sorted_extrusions, ®ion});
|
||||||
|
previous_position = sorted_extrusions.back().flipped() ?
|
||||||
|
sorted_extrusions.back().extrusion_entity().first_point() :
|
||||||
|
sorted_extrusions.back().extrusion_entity().last_point();
|
||||||
|
}
|
||||||
|
it = it_end;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void place_seams(
|
||||||
|
const Layer *layer, const Seams::Placer &seam_placer, const std::vector<ExtrusionEntity *> &perimeters, std::optional<Point> previous_position, const bool spiral_vase
|
||||||
|
) {
|
||||||
|
std::vector<const ExtrusionEntity *> result;
|
||||||
|
result.reserve(perimeters.size());
|
||||||
|
|
||||||
|
for (ExtrusionEntity* perimeter : perimeters) {
|
||||||
|
auto loop{static_cast<ExtrusionLoop *>(perimeter)};
|
||||||
|
|
||||||
|
Point seam_point{previous_position ? *previous_position : Point::Zero()};
|
||||||
|
if (!spiral_vase && loop != nullptr) {
|
||||||
|
assert(m_layer != nullptr);
|
||||||
|
seam_point = seam_placer.place_seam(layer, *loop, seam_point);
|
||||||
|
loop->seam = seam_point;
|
||||||
|
}
|
||||||
|
previous_position = seam_point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Point> get_last_position(const std::vector<InfillRange> &infill_ranges) {
|
||||||
|
if (!infill_ranges.empty() && !infill_ranges.back().items.empty()) {
|
||||||
|
const ExtrusionEntityReference &last_infill{infill_ranges.back().items.back()};
|
||||||
|
return last_infill.flipped() ? last_infill.extrusion_entity().first_point() :
|
||||||
|
last_infill.extrusion_entity().last_point();
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Point> get_last_position(const ExtrusionEntityReferences &extrusions) {
|
||||||
|
if (!extrusions.empty()) {
|
||||||
|
const ExtrusionEntityReference &last_extrusion{extrusions.back()};
|
||||||
|
return last_extrusion.flipped() ? last_extrusion.extrusion_entity().first_point() :
|
||||||
|
last_extrusion.extrusion_entity().last_point();
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Point> get_last_position(const std::vector<ExtrusionEntity *> &perimeters){
|
||||||
|
if (!perimeters.empty()) {
|
||||||
|
auto last_perimeter{static_cast<const ExtrusionLoop *>(perimeters.back())};
|
||||||
|
if (last_perimeter != nullptr) {
|
||||||
|
return last_perimeter->seam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Point> get_last_position(const std::vector<SliceExtrusions> &slice_extrusions, const bool infill_first) {
|
||||||
|
if (slice_extrusions.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const SliceExtrusions &last_slice{slice_extrusions.back()};
|
||||||
|
if (!last_slice.ironing_extrusions.empty()) {
|
||||||
|
return get_last_position(slice_extrusions.back().ironing_extrusions);
|
||||||
|
}
|
||||||
|
if (last_slice.common_extrusions.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const IslandExtrusions last_island{last_slice.common_extrusions.back()};
|
||||||
|
if (infill_first) {
|
||||||
|
if (!last_island.perimeters.empty()) {
|
||||||
|
return get_last_position(last_island.perimeters);
|
||||||
|
}
|
||||||
|
return get_last_position(last_island.infill_ranges);
|
||||||
|
} else {
|
||||||
|
if (!last_island.infill_ranges.empty()) {
|
||||||
|
return get_last_position(last_island.infill_ranges);
|
||||||
|
}
|
||||||
|
return get_last_position(last_island.perimeters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<IslandExtrusions> extract_island_extrusions(
|
||||||
|
const LayerSlice &lslice,
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const Seams::Placer &seam_placer,
|
||||||
|
const bool spiral_vase,
|
||||||
|
const ExtractEntityPredicate &predicate,
|
||||||
|
std::optional<Point> &previous_position
|
||||||
|
) {
|
||||||
|
std::vector<IslandExtrusions> result;
|
||||||
|
for (const LayerIsland &island : lslice.islands) {
|
||||||
|
const LayerRegion &layerm = *layer->get_region(island.perimeters.region());
|
||||||
|
// PrintObjects own the PrintRegions, thus the pointer to PrintRegion would be
|
||||||
|
// unique to a PrintObject, they would not identify the content of PrintRegion
|
||||||
|
// accross the whole print uniquely. Translate to a Print specific PrintRegion.
|
||||||
|
const PrintRegion ®ion = print.get_print_region(layerm.region().print_region_id());
|
||||||
|
|
||||||
|
const auto infill_predicate = [&](const auto &eec, const auto ®ion) {
|
||||||
|
return predicate(eec, region) && eec.role() != ExtrusionRole::Ironing;
|
||||||
|
};
|
||||||
|
|
||||||
|
result.push_back(IslandExtrusions{®ion});
|
||||||
|
IslandExtrusions &island_extrusions{result.back()};
|
||||||
|
|
||||||
|
island_extrusions.perimeters = extract_perimeter_extrusions(print, layer, island, predicate);
|
||||||
|
|
||||||
|
if (print.config().infill_first) {
|
||||||
|
island_extrusions.infill_ranges = extract_infill_ranges(
|
||||||
|
print, layer, island, previous_position, infill_predicate
|
||||||
|
);
|
||||||
|
if (const auto last_position = get_last_position(island_extrusions.infill_ranges)) {
|
||||||
|
previous_position = last_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
place_seams(layer, seam_placer, island_extrusions.perimeters, previous_position, spiral_vase);
|
||||||
|
|
||||||
|
if (const auto last_position = get_last_position(island_extrusions.perimeters)) {
|
||||||
|
previous_position = last_position;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
place_seams(layer, seam_placer, island_extrusions.perimeters, previous_position, spiral_vase);
|
||||||
|
|
||||||
|
if (const auto last_position = get_last_position(island_extrusions.perimeters)) {
|
||||||
|
previous_position = last_position;
|
||||||
|
}
|
||||||
|
island_extrusions.infill_ranges = {extract_infill_ranges(
|
||||||
|
print, layer, island, previous_position, infill_predicate
|
||||||
|
)};
|
||||||
|
if (const auto last_position = get_last_position(island_extrusions.infill_ranges)) {
|
||||||
|
previous_position = last_position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<InfillRange> extract_ironing_extrusions(
|
||||||
|
const LayerSlice &lslice,
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const ExtractEntityPredicate &predicate,
|
||||||
|
std::optional<Point> &previous_position
|
||||||
|
) {
|
||||||
|
std::vector<InfillRange> result;
|
||||||
|
|
||||||
|
for (const LayerIsland &island : lslice.islands) {
|
||||||
|
const auto ironing_predicate = [&](const auto &eec, const auto ®ion) {
|
||||||
|
return predicate(eec, region) && eec.role() == ExtrusionRole::Ironing;
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<InfillRange> ironing_ranges{extract_infill_ranges(
|
||||||
|
print, layer, island, previous_position, ironing_predicate
|
||||||
|
)};
|
||||||
|
result.insert(
|
||||||
|
result.end(), ironing_ranges.begin(), ironing_ranges.end()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (const auto last_position = get_last_position(ironing_ranges)) {
|
||||||
|
previous_position = last_position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SliceExtrusions> get_slices_extrusions(
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const Seams::Placer &seam_placer,
|
||||||
|
std::optional<Point> previous_position,
|
||||||
|
const bool spiral_vase,
|
||||||
|
const ExtractEntityPredicate &predicate
|
||||||
|
) {
|
||||||
|
// Note: ironing.
|
||||||
|
// FIXME move ironing into the loop above over LayerIslands?
|
||||||
|
// First Ironing changes extrusion rate quickly, second single ironing may be done over
|
||||||
|
// multiple perimeter regions. Ironing in a second phase is safer, but it may be less
|
||||||
|
// efficient.
|
||||||
|
|
||||||
|
std::vector<SliceExtrusions> result;
|
||||||
|
|
||||||
|
for (size_t idx : layer->lslice_indices_sorted_by_print_order) {
|
||||||
|
const LayerSlice &lslice = layer->lslices_ex[idx];
|
||||||
|
result.emplace_back(SliceExtrusions{
|
||||||
|
extract_island_extrusions(
|
||||||
|
lslice, print, layer, seam_placer, spiral_vase, predicate, previous_position
|
||||||
|
),
|
||||||
|
extract_ironing_extrusions(lslice, print, layer, predicate, previous_position)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned translate_support_extruder(
|
||||||
|
const int configured_extruder,
|
||||||
|
const LayerTools &layer_tools,
|
||||||
|
const ConfigOptionBools &is_soluable
|
||||||
|
) {
|
||||||
|
if (configured_extruder <= 0) {
|
||||||
|
// Some support will be printed with "don't care" material, preferably non-soluble.
|
||||||
|
// Is the current extruder assigned a soluble filament?
|
||||||
|
auto it_nonsoluble = std::find_if(layer_tools.extruders.begin(), layer_tools.extruders.end(),
|
||||||
|
[&is_soluable](unsigned int extruder_id) { return ! is_soluable.get_at(extruder_id); });
|
||||||
|
// There should be a non-soluble extruder available.
|
||||||
|
assert(it_nonsoluble != layer_tools.extruders.end());
|
||||||
|
return it_nonsoluble == layer_tools.extruders.end() ? layer_tools.extruders.front() : *it_nonsoluble;
|
||||||
|
} else {
|
||||||
|
return configured_extruder - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtrusionEntityReferences get_support_extrusions(
|
||||||
|
const unsigned int extruder_id,
|
||||||
|
const GCode::ObjectLayerToPrint &layer_to_print,
|
||||||
|
unsigned int support_extruder,
|
||||||
|
unsigned int interface_extruder
|
||||||
|
) {
|
||||||
|
if (const SupportLayer &support_layer = *layer_to_print.support_layer;
|
||||||
|
!support_layer.support_fills.entities.empty()) {
|
||||||
|
ExtrusionRole role = support_layer.support_fills.role();
|
||||||
|
bool has_support = role.is_mixed() || role.is_support_base();
|
||||||
|
bool has_interface = role.is_mixed() || role.is_support_interface();
|
||||||
|
|
||||||
|
bool extrude_support = has_support && support_extruder == extruder_id;
|
||||||
|
bool extrude_interface = has_interface && interface_extruder == extruder_id;
|
||||||
|
|
||||||
|
if (extrude_support || extrude_interface) {
|
||||||
|
ExtrusionEntitiesPtr entities_cache;
|
||||||
|
const ExtrusionEntitiesPtr &entities = extrude_support && extrude_interface ?
|
||||||
|
support_layer.support_fills.entities :
|
||||||
|
entities_cache;
|
||||||
|
if (!extrude_support || !extrude_interface) {
|
||||||
|
auto role = extrude_support ? ExtrusionRole::SupportMaterial :
|
||||||
|
ExtrusionRole::SupportMaterialInterface;
|
||||||
|
entities_cache.reserve(support_layer.support_fills.entities.size());
|
||||||
|
for (ExtrusionEntity *ee : support_layer.support_fills.entities)
|
||||||
|
if (ee->role() == role)
|
||||||
|
entities_cache.emplace_back(ee);
|
||||||
|
}
|
||||||
|
return chain_extrusion_references(entities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<SliceExtrusions>> get_overriden_extrusions(
|
||||||
|
const Print &print,
|
||||||
|
const GCode::ObjectsLayerToPrint &layers,
|
||||||
|
const LayerTools &layer_tools,
|
||||||
|
const std::vector<InstanceToPrint> &instances_to_print,
|
||||||
|
const Seams::Placer &seam_placer,
|
||||||
|
const bool spiral_vase,
|
||||||
|
const unsigned int extruder_id,
|
||||||
|
std::optional<Point> &previous_position
|
||||||
|
) {
|
||||||
|
std::vector<std::vector<SliceExtrusions>> result;
|
||||||
|
|
||||||
|
for (const InstanceToPrint &instance : instances_to_print) {
|
||||||
|
if (const Layer *layer = layers[instance.object_layer_to_print_id].object_layer; layer) {
|
||||||
|
const auto predicate = [&](const ExtrusionEntityCollection &entity_collection,
|
||||||
|
const PrintRegion ®ion) {
|
||||||
|
if (!is_overriden(entity_collection, layer_tools, instance.instance_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_extruder_id(
|
||||||
|
entity_collection, layer_tools, region, instance.instance_id
|
||||||
|
) != extruder_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
result.emplace_back(get_slices_extrusions(
|
||||||
|
print, layer, seam_placer, previous_position, spiral_vase, predicate
|
||||||
|
));
|
||||||
|
previous_position = get_last_position(result.back(), print.config().infill_first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<NormalExtrusions> get_normal_extrusions(
|
||||||
|
const Print &print,
|
||||||
|
const GCode::ObjectsLayerToPrint &layers,
|
||||||
|
const LayerTools &layer_tools,
|
||||||
|
const std::vector<InstanceToPrint> &instances_to_print,
|
||||||
|
const Seams::Placer &seam_placer,
|
||||||
|
const bool spiral_vase,
|
||||||
|
const unsigned int extruder_id,
|
||||||
|
std::optional<Point> &previous_position
|
||||||
|
) {
|
||||||
|
std::vector<NormalExtrusions> result;
|
||||||
|
|
||||||
|
for (std::size_t i{0}; i < instances_to_print.size(); ++i) {
|
||||||
|
const InstanceToPrint &instance{instances_to_print[i]};
|
||||||
|
result.emplace_back();
|
||||||
|
|
||||||
|
if (layers[instance.object_layer_to_print_id].support_layer != nullptr) {
|
||||||
|
result.back().support_extrusions = get_support_extrusions(
|
||||||
|
extruder_id,
|
||||||
|
layers[instance.object_layer_to_print_id],
|
||||||
|
translate_support_extruder(instance.print_object.config().support_material_extruder.value, layer_tools, print.config().filament_soluble),
|
||||||
|
translate_support_extruder(instance.print_object.config().support_material_interface_extruder.value, layer_tools, print.config().filament_soluble)
|
||||||
|
);
|
||||||
|
previous_position = get_last_position(result.back().support_extrusions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const Layer *layer = layers[instance.object_layer_to_print_id].object_layer; layer) {
|
||||||
|
const auto predicate = [&](const ExtrusionEntityCollection &entity_collection, const PrintRegion ®ion){
|
||||||
|
if (is_overriden(entity_collection, layer_tools, instance.instance_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_extruder_id(entity_collection, layer_tools, region, instance.instance_id) != extruder_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
result.back().slices_extrusions = get_slices_extrusions(
|
||||||
|
print,
|
||||||
|
layer,
|
||||||
|
seam_placer,
|
||||||
|
previous_position,
|
||||||
|
spiral_vase,
|
||||||
|
predicate
|
||||||
|
);
|
||||||
|
previous_position = get_last_position(result.back().slices_extrusions, print.config().infill_first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
187
src/libslic3r/GCode/ExtrusionOrder.hpp
Normal file
187
src/libslic3r/GCode/ExtrusionOrder.hpp
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
#ifndef slic3r_GCode_ExtrusionOrder_hpp_
|
||||||
|
#define slic3r_GCode_ExtrusionOrder_hpp_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "libslic3r/ExtrusionEntity.hpp"
|
||||||
|
#include "libslic3r/GCode/SeamPlacer.hpp"
|
||||||
|
#include "libslic3r/Print.hpp"
|
||||||
|
#include "libslic3r/ShortestPath.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r::GCode {
|
||||||
|
// Object and support extrusions of the same PrintObject at the same print_z.
|
||||||
|
// public, so that it could be accessed by free helper functions from GCode.cpp
|
||||||
|
struct ObjectLayerToPrint
|
||||||
|
{
|
||||||
|
ObjectLayerToPrint() : object_layer(nullptr), support_layer(nullptr) {}
|
||||||
|
const Layer *object_layer;
|
||||||
|
const SupportLayer *support_layer;
|
||||||
|
const Layer *layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
|
||||||
|
const PrintObject *object() const {
|
||||||
|
return (this->layer() != nullptr) ? this->layer()->object() : nullptr;
|
||||||
|
}
|
||||||
|
coordf_t print_z() const {
|
||||||
|
return (object_layer != nullptr && support_layer != nullptr) ?
|
||||||
|
0.5 * (object_layer->print_z + support_layer->print_z) :
|
||||||
|
this->layer()->print_z;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using ObjectsLayerToPrint = std::vector<GCode::ObjectLayerToPrint>;
|
||||||
|
|
||||||
|
struct InstanceToPrint
|
||||||
|
{
|
||||||
|
InstanceToPrint(
|
||||||
|
size_t object_layer_to_print_id, const PrintObject &print_object, size_t instance_id
|
||||||
|
)
|
||||||
|
: object_layer_to_print_id(object_layer_to_print_id)
|
||||||
|
, print_object(print_object)
|
||||||
|
, instance_id(instance_id) {}
|
||||||
|
|
||||||
|
// Index into std::vector<ObjectLayerToPrint>, which contains Object and Support layers for the
|
||||||
|
// current print_z, collected for a single object, or for possibly multiple objects with
|
||||||
|
// multiple instances.
|
||||||
|
const size_t object_layer_to_print_id;
|
||||||
|
const PrintObject &print_object;
|
||||||
|
// Instance idx of the copy of a print object.
|
||||||
|
const size_t instance_id;
|
||||||
|
};
|
||||||
|
} // namespace Slic3r::GCode
|
||||||
|
|
||||||
|
namespace Slic3r::GCode::ExtrusionOrder {
|
||||||
|
|
||||||
|
struct InfillRange {
|
||||||
|
std::vector<ExtrusionEntityReference> items;
|
||||||
|
const PrintRegion *region;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IslandExtrusions {
|
||||||
|
const PrintRegion *region;
|
||||||
|
std::vector<ExtrusionEntity *> perimeters;
|
||||||
|
std::vector<InfillRange> infill_ranges;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SliceExtrusions {
|
||||||
|
std::vector<IslandExtrusions> common_extrusions;
|
||||||
|
std::vector<InfillRange> ironing_extrusions;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NormalExtrusions {
|
||||||
|
ExtrusionEntityReferences support_extrusions;
|
||||||
|
std::vector<SliceExtrusions> slices_extrusions;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool is_overriden(const ExtrusionEntityCollection &eec, const LayerTools &layer_tools, const std::size_t instance_id);
|
||||||
|
|
||||||
|
int get_extruder_id(
|
||||||
|
const ExtrusionEntityCollection &eec,
|
||||||
|
const LayerTools &layer_tools,
|
||||||
|
const PrintRegion ®ion,
|
||||||
|
const std::size_t instance_id
|
||||||
|
);
|
||||||
|
|
||||||
|
using ExtractEntityPredicate = std::function<bool(const ExtrusionEntityCollection&, const PrintRegion&)>;
|
||||||
|
|
||||||
|
ExtrusionEntitiesPtr extract_infill_extrusions(
|
||||||
|
const Layer *layer,
|
||||||
|
const PrintRegion ®ion,
|
||||||
|
const ExtrusionEntityCollection &fills,
|
||||||
|
LayerExtrusionRanges::const_iterator begin,
|
||||||
|
LayerExtrusionRanges::const_iterator end,
|
||||||
|
const ExtractEntityPredicate &predicate
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<ExtrusionEntity *> extract_perimeter_extrusions(
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const LayerIsland &island,
|
||||||
|
const ExtractEntityPredicate &predicate
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<ExtrusionEntityReference> sort_fill_extrusions(const ExtrusionEntitiesPtr &fills, const Point* start_near);
|
||||||
|
|
||||||
|
std::vector<InfillRange> extract_infill_ranges(
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const LayerIsland island,
|
||||||
|
std::optional<Point> previous_position,
|
||||||
|
const ExtractEntityPredicate &predicate
|
||||||
|
);
|
||||||
|
|
||||||
|
void place_seams(
|
||||||
|
const Layer *layer, const Seams::Placer &seam_placer, const std::vector<ExtrusionEntity *> &perimeters, std::optional<Point> previous_position, const bool spiral_vase
|
||||||
|
);
|
||||||
|
|
||||||
|
std::optional<Point> get_last_position(const std::vector<InfillRange> &infill_ranges);
|
||||||
|
|
||||||
|
std::optional<Point> get_last_position(const ExtrusionEntityReferences &extrusions);
|
||||||
|
|
||||||
|
std::optional<Point> get_last_position(const std::vector<ExtrusionEntity *> &perimeters);
|
||||||
|
|
||||||
|
std::optional<Point> get_last_position(const std::vector<SliceExtrusions> &slice_extrusions, const bool infill_first);
|
||||||
|
|
||||||
|
std::vector<IslandExtrusions> extract_island_extrusions(
|
||||||
|
const LayerSlice &lslice,
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const Seams::Placer &seam_placer,
|
||||||
|
const bool spiral_vase,
|
||||||
|
const ExtractEntityPredicate &predicate,
|
||||||
|
std::optional<Point> &previous_position
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<InfillRange> extract_ironing_extrusions(
|
||||||
|
const LayerSlice &lslice,
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const ExtractEntityPredicate &predicate,
|
||||||
|
std::optional<Point> &previous_position
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<SliceExtrusions> get_slices_extrusions(
|
||||||
|
const Print &print,
|
||||||
|
const Layer *layer,
|
||||||
|
const Seams::Placer &seam_placer,
|
||||||
|
std::optional<Point> previous_position,
|
||||||
|
const bool spiral_vase,
|
||||||
|
const ExtractEntityPredicate &predicate
|
||||||
|
);
|
||||||
|
|
||||||
|
unsigned translate_support_extruder(
|
||||||
|
const int configured_extruder,
|
||||||
|
const LayerTools &layer_tools,
|
||||||
|
const ConfigOptionBools &is_soluable
|
||||||
|
);
|
||||||
|
|
||||||
|
ExtrusionEntityReferences get_support_extrusions(
|
||||||
|
const unsigned int extruder_id,
|
||||||
|
const GCode::ObjectLayerToPrint &layer_to_print,
|
||||||
|
unsigned int support_extruder,
|
||||||
|
unsigned int interface_extruder
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<std::vector<SliceExtrusions>> get_overriden_extrusions(
|
||||||
|
const Print &print,
|
||||||
|
const GCode::ObjectsLayerToPrint &layers,
|
||||||
|
const LayerTools &layer_tools,
|
||||||
|
const std::vector<InstanceToPrint> &instances_to_print,
|
||||||
|
const Seams::Placer &seam_placer,
|
||||||
|
const bool spiral_vase,
|
||||||
|
const unsigned int extruder_id,
|
||||||
|
std::optional<Point> &previous_position
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<NormalExtrusions> get_normal_extrusions(
|
||||||
|
const Print &print,
|
||||||
|
const GCode::ObjectsLayerToPrint &layers,
|
||||||
|
const LayerTools &layer_tools,
|
||||||
|
const std::vector<InstanceToPrint> &instances_to_print,
|
||||||
|
const Seams::Placer &seam_placer,
|
||||||
|
const bool spiral_vase,
|
||||||
|
const unsigned int extruder_id,
|
||||||
|
std::optional<Point> &previous_position
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // slic3r_GCode_ExtrusionOrder_hpp_
|
Loading…
x
Reference in New Issue
Block a user