From 1f958d17f1f1fdcd44ba73649a6cf73435a5dfa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 12 Jul 2024 13:35:47 +0200 Subject: [PATCH] SPE-2387: Order islands to minimize travels between them. --- src/libslic3r/GCode/ExtrusionOrder.cpp | 43 ++++++++++++++------ src/libslic3r/ShortestPath.cpp | 56 +++++++++++++++++++++----- src/libslic3r/ShortestPath.hpp | 10 ++++- 3 files changed, 84 insertions(+), 25 deletions(-) diff --git a/src/libslic3r/GCode/ExtrusionOrder.cpp b/src/libslic3r/GCode/ExtrusionOrder.cpp index 1ae68b5cee..32e0426b6c 100644 --- a/src/libslic3r/GCode/ExtrusionOrder.cpp +++ b/src/libslic3r/GCode/ExtrusionOrder.cpp @@ -208,6 +208,20 @@ std::vector extract_infill_ranges( return result; } +// Returns LayerIslands ordered by the shortest distance. +std::vector> get_ordered_islands( + const LayerSlice &lslice, + const std::optional &previous_position +) { + std::vector> islands_to_order; + for (const LayerIsland &island : lslice.islands) { + islands_to_order.emplace_back(island); + } + + chain_and_reorder_layer_islands(islands_to_order, previous_position.has_value() ? std::addressof(*previous_position) : nullptr); + return islands_to_order; +} + std::vector extract_island_extrusions( const LayerSlice &lslice, const Print &print, @@ -218,18 +232,20 @@ std::vector extract_island_extrusions( const unsigned extruder_id, std::optional &previous_position ) { + const auto should_pick_infill = [&should_pick_extrusion](const ExtrusionEntityCollection &eec, const PrintRegion ®ion) { + return should_pick_extrusion(eec, region) && eec.role() != ExtrusionRole::Ironing; + }; + + std::vector> ordered_islands = get_ordered_islands(lslice, previous_position); + std::vector result; - for (const LayerIsland &island : lslice.islands) { + for (const LayerIsland &island : ordered_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 should_pick_infill = [&should_pick_extrusion](const ExtrusionEntityCollection &eec, const PrintRegion ®ion) { - return should_pick_extrusion(eec, region) && eec.role() != ExtrusionRole::Ironing; - }; - result.push_back(IslandExtrusions{®ion}); IslandExtrusions &island_extrusions{result.back()}; island_extrusions.infill_first = print.config().infill_first; @@ -243,9 +259,9 @@ std::vector extract_island_extrusions( } else { island_extrusions.perimeters = extract_perimeter_extrusions(print, layer, island, should_pick_extrusion, extruder_id, offset, previous_position, smooth_path); - island_extrusions.infill_ranges = {extract_infill_ranges( + island_extrusions.infill_ranges = extract_infill_ranges( print, layer, island, offset, previous_position, should_pick_infill, smooth_path, extruder_id - )}; + ); } } return result; @@ -261,13 +277,14 @@ std::vector extract_ironing_extrusions( const unsigned extruder_id, std::optional &previous_position ) { + const auto should_pick_ironing = [&should_pick_extrusion](const auto &eec, const auto ®ion) { + return should_pick_extrusion(eec, region) && eec.role() == ExtrusionRole::Ironing; + }; + + std::vector> ordered_islands = get_ordered_islands(lslice, previous_position); + std::vector result; - - for (const LayerIsland &island : lslice.islands) { - const auto should_pick_ironing = [&should_pick_extrusion](const auto &eec, const auto ®ion) { - return should_pick_extrusion(eec, region) && eec.role() == ExtrusionRole::Ironing; - }; - + for (const LayerIsland &island : ordered_islands) { const std::vector ironing_ranges{extract_infill_ranges( print, layer, island, offset, previous_position, should_pick_ironing, smooth_path, extruder_id )}; diff --git a/src/libslic3r/ShortestPath.cpp b/src/libslic3r/ShortestPath.cpp index a4441e6727..fed843c2c8 100644 --- a/src/libslic3r/ShortestPath.cpp +++ b/src/libslic3r/ShortestPath.cpp @@ -1110,23 +1110,30 @@ void chain_and_reorder_extrusion_paths(std::vector &extrusion_pat reorder_extrusion_paths(extrusion_paths, chain_extrusion_paths(extrusion_paths, start_near)); } -std::vector chain_points(const Points &points, Point *start_near) +std::vector chain_points(const Points &points, const Point *start_near) { - auto segment_end_point = [&points](size_t idx, bool /* first_point */) -> const Point& { return points[idx]; }; - std::vector> ordered = chain_segments_greedy(segment_end_point, points.size(), start_near); - std::vector out; - out.reserve(ordered.size()); - for (auto &segment_and_reversal : ordered) - out.emplace_back(segment_and_reversal.first); - return out; + auto segment_end_point = [&points](size_t idx, bool /* first_point */) -> const Point & { + return points[idx]; + }; + + std::vector> ordered = chain_segments_greedy(segment_end_point, points.size(), start_near); + std::vector out; + out.reserve(ordered.size()); + for (auto &segment_and_reversal : ordered) { + out.emplace_back(segment_and_reversal.first); + } + + return out; } -std::vector chain_expolygons(const ExPolygons &expolygons, Point *start_near) +std::vector chain_expolygons(const ExPolygons &expolygons) { Points ordering_points; ordering_points.reserve(expolygons.size()); - for (const ExPolygon &ex : expolygons) + for (const ExPolygon &ex : expolygons) { ordering_points.push_back(ex.contour.first_point()); + } + return chain_points(ordering_points); } @@ -2102,4 +2109,33 @@ Polylines chain_lines(const std::vector &lines, const double point_distanc return out; } +std::vector chain_layer_islands(const std::vector> &islands, const Point *start_near) +{ + Points ordering_points; + ordering_points.reserve(islands.size()); + for (const LayerIsland &island : islands) { + ordering_points.push_back(island.boundary.contour.first_point()); + } + + return chain_points(ordering_points, start_near); +} + +void reorder_layer_islands(std::vector> &islands, const std::vector &chain) +{ + assert(islands.size() == chain.size()); + std::vector> islands_out; + islands_out.reserve(islands.size()); + + for (size_t island_idx : chain) { + islands_out.emplace_back(islands[island_idx]); + } + + islands.swap(islands_out); +} + +void chain_and_reorder_layer_islands(std::vector> &islands, const Point *start_near) +{ + reorder_layer_islands(islands, chain_layer_islands(islands, start_near)); +} + } // namespace Slic3r diff --git a/src/libslic3r/ShortestPath.hpp b/src/libslic3r/ShortestPath.hpp index 644018bd14..c4a67db38c 100644 --- a/src/libslic3r/ShortestPath.hpp +++ b/src/libslic3r/ShortestPath.hpp @@ -27,13 +27,14 @@ class Line; } class ExPolygon; +struct LayerIsland; using ExPolygons = std::vector; // Used by chain_expolygons() -std::vector chain_points(const Points &points, Point *start_near = nullptr); +std::vector chain_points(const Points &points, const Point *start_near = nullptr); // Used to give layer islands a print order. -std::vector chain_expolygons(const ExPolygons &expolygons, Point *start_near = nullptr); +std::vector chain_expolygons(const ExPolygons &expolygons); // Chain extrusion entities by a shortest distance. Returns the ordered extrusions together with a "reverse" flag. // Set input "reversed" to true if the vector of "entities" is to be considered to be reversed once already. @@ -68,6 +69,11 @@ std::vector chain_print_object_instances(const Print &pr // Chain lines into polylines. Polylines chain_lines(const std::vector &lines, const double point_distance_epsilon); +// Chain and reorder layer islands by the shortest distance. +std::vector chain_layer_islands(const std::vector> &islands, const Point *start_near = nullptr); +void reorder_layer_islands(std::vector> &islands, const std::vector &chain); +void chain_and_reorder_layer_islands(std::vector> &islands, const Point *start_near = nullptr); + } // namespace Slic3r #endif /* slic3r_ShortestPath_hpp_ */