diff --git a/src/libslic3r/Arachne/PerimeterOrder.cpp b/src/libslic3r/Arachne/PerimeterOrder.cpp index 554b4098dd..a117e39623 100644 --- a/src/libslic3r/Arachne/PerimeterOrder.cpp +++ b/src/libslic3r/Arachne/PerimeterOrder.cpp @@ -162,9 +162,14 @@ struct GroupedPerimeterExtrusions }; // Returns vector of indexes that represent the order of grouped extrusions in grouped_extrusions. -static std::vector order_of_grouped_perimeter_extrusions_to_minimize_distances(Point current_position, std::vector grouped_extrusions) { +static std::vector order_of_grouped_perimeter_extrusions_to_minimize_distances(const std::vector &grouped_extrusions, Point current_position) { + std::vector grouped_extrusions_sorted_indices(grouped_extrusions.size()); + std::iota(grouped_extrusions_sorted_indices.begin(), grouped_extrusions_sorted_indices.end(), 0); + // Ensure that holes will be placed before contour and open extrusions before the closed one. - std::sort(grouped_extrusions.begin(), grouped_extrusions.end(), [](const GroupedPerimeterExtrusions &l, const GroupedPerimeterExtrusions &r) -> bool { + std::sort(grouped_extrusions_sorted_indices.begin(), grouped_extrusions_sorted_indices.end(), [&grouped_extrusions = std::as_const(grouped_extrusions)](const size_t l_idx, const size_t r_idx) -> bool { + const GroupedPerimeterExtrusions &l = grouped_extrusions[l_idx]; + const GroupedPerimeterExtrusions &r = grouped_extrusions[r_idx]; return (l.external_perimeter_extrusion->is_contour() < r.external_perimeter_extrusion->is_contour()) || (l.external_perimeter_extrusion->is_contour() == r.external_perimeter_extrusion->is_contour() && l.external_perimeter_extrusion->is_closed() < r.external_perimeter_extrusion->is_closed()); }); @@ -181,8 +186,9 @@ static std::vector order_of_grouped_perimeter_extrusions_to_minimize_dis bool is_nearest_closed = false; // First we order all holes and then we start ordering contours. - const size_t grouped_extrusion_end = grouped_extrusions_order.size() < holes_cnt ? holes_cnt: grouped_extrusions.size(); - for (size_t grouped_extrusion_idx = 0; grouped_extrusion_idx < grouped_extrusion_end; ++grouped_extrusion_idx) { + const size_t grouped_extrusions_sorted_indices_end = (grouped_extrusions_order.size() < holes_cnt) ? holes_cnt : grouped_extrusions_sorted_indices.size(); + for (size_t grouped_extrusions_sorted_idx = 0; grouped_extrusions_sorted_idx < grouped_extrusions_sorted_indices_end; ++grouped_extrusions_sorted_idx) { + const size_t grouped_extrusion_idx = grouped_extrusions_sorted_indices[grouped_extrusions_sorted_idx]; if (already_selected[grouped_extrusion_idx]) continue; @@ -200,6 +206,7 @@ static std::vector order_of_grouped_perimeter_extrusions_to_minimize_dis grouped_extrusions_order.emplace_back(nearest_grouped_extrusions_idx); already_selected[nearest_grouped_extrusions_idx] = true; + const GroupedPerimeterExtrusions &nearest_grouped_extrusions = grouped_extrusions[nearest_grouped_extrusions_idx]; const ExtrusionLine &last_extrusion_line = nearest_grouped_extrusions.extrusions.back()->extrusion; current_position = get_end_position(last_extrusion_line); @@ -257,7 +264,7 @@ static PerimeterExtrusions extract_ordered_perimeter_extrusions(const PerimeterE std::reverse(grouped_extrusions.back().extrusions.begin(), grouped_extrusions.back().extrusions.end()); } - const std::vector grouped_extrusion_order = order_of_grouped_perimeter_extrusions_to_minimize_distances(Point::Zero(), grouped_extrusions); + const std::vector grouped_extrusion_order = order_of_grouped_perimeter_extrusions_to_minimize_distances(grouped_extrusions, Point::Zero()); PerimeterExtrusions ordered_extrusions; for (size_t order_idx : grouped_extrusion_order) { 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_ */