From 10875082de537793f6e62ce719b3e4defd57cfa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 11 Apr 2024 10:58:50 +0200 Subject: [PATCH 1/2] SPE-1963: Improve ordering of perimeters with Arachne perimeter generator Especially in cases when the object is composed only of 2 external perimeters and 1 or 2 internal perimeters, the order of perimeters wasn't optimal and differed from the Classic perimeter generator. That caused unnecessary long travels before the external contour was printed. The ordering of perimeters is slightly inspired by the latest changes in CuraEngine. --- src/libslic3r/Arachne/PerimeterOrder.cpp | 276 ++++++++++++++++++ src/libslic3r/Arachne/PerimeterOrder.hpp | 47 +++ src/libslic3r/Arachne/WallToolPaths.cpp | 95 ------ src/libslic3r/Arachne/WallToolPaths.hpp | 9 - src/libslic3r/Arachne/utils/ExtrusionLine.cpp | 23 +- src/libslic3r/Arachne/utils/ExtrusionLine.hpp | 26 +- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/PerimeterGenerator.cpp | 165 ++--------- 8 files changed, 383 insertions(+), 260 deletions(-) create mode 100644 src/libslic3r/Arachne/PerimeterOrder.cpp create mode 100644 src/libslic3r/Arachne/PerimeterOrder.hpp diff --git a/src/libslic3r/Arachne/PerimeterOrder.cpp b/src/libslic3r/Arachne/PerimeterOrder.cpp new file mode 100644 index 0000000000..01d50feb1e --- /dev/null +++ b/src/libslic3r/Arachne/PerimeterOrder.cpp @@ -0,0 +1,276 @@ +#include "PerimeterOrder.hpp" + +namespace Slic3r::Arachne::PerimeterOrder { + +using namespace Arachne; + +static size_t get_extrusion_lines_count(const Perimeters &perimeters) { + size_t extrusion_lines_count = 0; + for (const Perimeter &perimeter : perimeters) + extrusion_lines_count += perimeter.size(); + + return extrusion_lines_count; +} + +static PerimeterExtrusions get_sorted_perimeter_extrusions_by_area(const Perimeters &perimeters) { + PerimeterExtrusions sorted_perimeter_extrusions; + sorted_perimeter_extrusions.reserve(get_extrusion_lines_count(perimeters)); + + for (const Perimeter &perimeter : perimeters) { + for (const ExtrusionLine &extrusion_line : perimeter) { + if (extrusion_line.empty()) + continue; // This shouldn't ever happen. + + const BoundingBox bbox = get_extents(extrusion_line); + // Be aware that Arachne produces contours with clockwise orientation and holes with counterclockwise orientation. + const double area = std::abs(extrusion_line.area()); + const Polygon polygon = extrusion_line.is_closed ? to_polygon(extrusion_line) : Polygon{}; + + sorted_perimeter_extrusions.emplace_back(extrusion_line, area, polygon, bbox); + } + } + + // Open extrusions have an area equal to zero, so sorting based on the area ensures that open extrusions will always be before closed ones. + std::sort(sorted_perimeter_extrusions.begin(), sorted_perimeter_extrusions.end(), + [](const PerimeterExtrusion &l, const PerimeterExtrusion &r) { return l.area < r.area; }); + + return sorted_perimeter_extrusions; +} + +// Functions fill adjacent_perimeter_extrusions field for every PerimeterExtrusion by pointers to PerimeterExtrusions that contain or are inside this PerimeterExtrusion. +static void construct_perimeter_extrusions_adjacency_graph(PerimeterExtrusions &sorted_perimeter_extrusions) { + // Construct a graph (defined using adjacent_perimeter_extrusions field) where two PerimeterExtrusion are adjacent when one is inside the other. + std::vector root_candidates(sorted_perimeter_extrusions.size(), false); + for (PerimeterExtrusion &perimeter_extrusion : sorted_perimeter_extrusions) { + const size_t perimeter_extrusion_idx = &perimeter_extrusion - sorted_perimeter_extrusions.data(); + + if (!perimeter_extrusion.is_closed()) { + root_candidates[perimeter_extrusion_idx] = true; + continue; + } + + for (PerimeterExtrusion &root_candidate : sorted_perimeter_extrusions) { + const size_t root_candidate_idx = &root_candidate - sorted_perimeter_extrusions.data(); + + if (!root_candidates[root_candidate_idx]) + continue; + + if (perimeter_extrusion.bbox.contains(root_candidate.bbox) && perimeter_extrusion.polygon.contains(root_candidate.extrusion.junctions.front().p)) { + perimeter_extrusion.adjacent_perimeter_extrusions.emplace_back(&root_candidate); + root_candidate.adjacent_perimeter_extrusions.emplace_back(&perimeter_extrusion); + root_candidates[root_candidate_idx] = false; + } + } + + root_candidates[perimeter_extrusion_idx] = true; + } +} + +// Perform the depth-first search to assign the nearest external perimeter for every PerimeterExtrusion. +// When some PerimeterExtrusion is achievable from more than one external perimeter, then we choose the +// one that comes from a contour. +static void assign_nearest_external_perimeter(PerimeterExtrusions &sorted_perimeter_extrusions) { + std::stack stack; + for (PerimeterExtrusion &perimeter_extrusion : sorted_perimeter_extrusions) { + if (perimeter_extrusion.is_external_perimeter()) { + perimeter_extrusion.depth = 0; + perimeter_extrusion.nearest_external_perimeter = &perimeter_extrusion; + stack.push(&perimeter_extrusion); + } + } + + while (!stack.empty()) { + PerimeterExtrusion *current_extrusion = stack.top(); + stack.pop(); + + for (PerimeterExtrusion *adjacent_extrusion : current_extrusion->adjacent_perimeter_extrusions) { + const size_t adjacent_extrusion_depth = current_extrusion->depth + 1; + // Update depth when the new depth is smaller or when we can achieve the same depth from a contour. + // This will ensure that the internal perimeter will be extruded before the outer external perimeter + // when there are two external perimeters and one internal. + if (adjacent_extrusion_depth < adjacent_extrusion->depth) { + adjacent_extrusion->nearest_external_perimeter = current_extrusion->nearest_external_perimeter; + adjacent_extrusion->depth = adjacent_extrusion_depth; + stack.push(adjacent_extrusion); + } else if (adjacent_extrusion_depth == adjacent_extrusion->depth && !adjacent_extrusion->nearest_external_perimeter->is_contour() && current_extrusion->is_contour()) { + adjacent_extrusion->nearest_external_perimeter = current_extrusion->nearest_external_perimeter; + stack.push(adjacent_extrusion); + } + } + } +} + +inline Point get_end_position(const ExtrusionLine &extrusion) { + if (extrusion.is_closed) + return extrusion.junctions[0].p; // We ended where we started. + else + return extrusion.junctions.back().p; // Pick the other end from where we started. +} + +// Returns ordered extrusions. +static std::vector ordered_perimeter_extrusions_to_minimize_distances(Point current_position, std::vector extrusions) { + // Ensure that open extrusions will be placed before the closed one. + std::sort(extrusions.begin(), extrusions.end(), + [](const PerimeterExtrusion *l, const PerimeterExtrusion *r) -> bool { return l->is_closed() < r->is_closed(); }); + + std::vector ordered_extrusions; + std::vector already_selected(extrusions.size(), false); + while (ordered_extrusions.size() < extrusions.size()) { + double nearest_distance_sqr = std::numeric_limits::max(); + size_t nearest_extrusion_idx = 0; + bool is_nearest_closed = false; + + for (size_t extrusion_idx = 0; extrusion_idx < extrusions.size(); ++extrusion_idx) { + if (already_selected[extrusion_idx]) + continue; + + const ExtrusionLine &extrusion_line = extrusions[extrusion_idx]->extrusion; + const Point &extrusion_start_position = extrusion_line.junctions.front().p; + const double distance_sqr = (current_position - extrusion_start_position).cast().squaredNorm(); + if (distance_sqr < nearest_distance_sqr) { + if (extrusion_line.is_closed || (!extrusion_line.is_closed && nearest_distance_sqr != std::numeric_limits::max()) || (!extrusion_line.is_closed && !is_nearest_closed)) { + nearest_extrusion_idx = extrusion_idx; + nearest_distance_sqr = distance_sqr; + is_nearest_closed = extrusion_line.is_closed; + } + } + } + + already_selected[nearest_extrusion_idx] = true; + const PerimeterExtrusion *nearest_extrusion = extrusions[nearest_extrusion_idx]; + current_position = get_end_position(nearest_extrusion->extrusion); + ordered_extrusions.emplace_back(nearest_extrusion); + } + + return ordered_extrusions; +} + +struct GroupedPerimeterExtrusions +{ + GroupedPerimeterExtrusions() = delete; + explicit GroupedPerimeterExtrusions(const PerimeterExtrusion *external_perimeter_extrusion) + : external_perimeter_extrusion(external_perimeter_extrusion) {} + + std::vector extrusions; + const PerimeterExtrusion *external_perimeter_extrusion = nullptr; +}; + +// 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) { + // 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 { + 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()); + }); + + const size_t holes_cnt = std::count_if(grouped_extrusions.begin(), grouped_extrusions.end(), [](const GroupedPerimeterExtrusions &grouped_extrusions) { + return !grouped_extrusions.external_perimeter_extrusion->is_contour(); + }); + + std::vector grouped_extrusions_order; + std::vector already_selected(grouped_extrusions.size(), false); + while (grouped_extrusions_order.size() < grouped_extrusions.size()) { + double nearest_distance_sqr = std::numeric_limits::max(); + size_t nearest_grouped_extrusions_idx = 0; + 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) { + if (already_selected[grouped_extrusion_idx]) + continue; + + const ExtrusionLine &external_perimeter_extrusion_line = grouped_extrusions[grouped_extrusion_idx].external_perimeter_extrusion->extrusion; + const Point &extrusion_start_position = external_perimeter_extrusion_line.junctions.front().p; + const double distance_sqr = (current_position - extrusion_start_position).cast().squaredNorm(); + if (distance_sqr < nearest_distance_sqr) { + if (external_perimeter_extrusion_line.is_closed || (!external_perimeter_extrusion_line.is_closed && nearest_distance_sqr != std::numeric_limits::max()) || (!external_perimeter_extrusion_line.is_closed && !is_nearest_closed)) { + nearest_grouped_extrusions_idx = grouped_extrusion_idx; + nearest_distance_sqr = distance_sqr; + is_nearest_closed = external_perimeter_extrusion_line.is_closed; + } + } + } + + 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); + } + + return grouped_extrusions_order; +} + +static PerimeterExtrusions extract_ordered_perimeter_extrusions(const PerimeterExtrusions &sorted_perimeter_extrusions, const bool external_perimeters_first) { + // Extrusions are ordered inside each group. + std::vector grouped_extrusions; + + std::stack stack; + std::vector visited(sorted_perimeter_extrusions.size(), false); + for (const PerimeterExtrusion &perimeter_extrusion : sorted_perimeter_extrusions) { + if (!perimeter_extrusion.is_external_perimeter()) + continue; + + stack.push(&perimeter_extrusion); + visited.assign(sorted_perimeter_extrusions.size(), false); + + grouped_extrusions.emplace_back(&perimeter_extrusion); + while (!stack.empty()) { + const PerimeterExtrusion *current_extrusion = stack.top(); + const size_t current_extrusion_idx = current_extrusion - sorted_perimeter_extrusions.data(); + stack.pop(); + + if (visited[current_extrusion_idx]) + continue; + + if (current_extrusion->nearest_external_perimeter == &perimeter_extrusion) + grouped_extrusions.back().extrusions.emplace_back(current_extrusion); + + if (current_extrusion->adjacent_perimeter_extrusions.size() == 1) { + const PerimeterExtrusion *adjacent_extrusion = current_extrusion->adjacent_perimeter_extrusions.front(); + stack.push(adjacent_extrusion); + } else if (current_extrusion->adjacent_perimeter_extrusions.size() > 1) { + // When there is more than one available candidate, then order candidates to minimize distances between + // candidates and also to minimize the distance from the current_position. + std::vector available_candidates; + for (const PerimeterExtrusion *adjacent_extrusion : current_extrusion->adjacent_perimeter_extrusions) { + if (const size_t adjacent_extrusion_idx = adjacent_extrusion - sorted_perimeter_extrusions.data(); !visited[adjacent_extrusion_idx]) + available_candidates.emplace_back(adjacent_extrusion); + } + + std::vector adjacent_extrusions = ordered_perimeter_extrusions_to_minimize_distances(Point::Zero(), available_candidates); + std::reverse(adjacent_extrusions.begin(), adjacent_extrusions.end()); + for (const PerimeterExtrusion *adjacent_extrusion : adjacent_extrusions) + stack.push(adjacent_extrusion); + } + + visited[current_extrusion_idx] = true; + } + + if (!external_perimeters_first) + 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); + assert(grouped_extrusion_order.size() == grouped_ordered_extrusions.size()); + + PerimeterExtrusions ordered_extrusions; + for (size_t order_idx : grouped_extrusion_order) { + for (const PerimeterExtrusion *perimeter_extrusion : grouped_extrusions[order_idx].extrusions) + ordered_extrusions.emplace_back(*perimeter_extrusion); + } + + return ordered_extrusions; +} + +// FIXME: From the point of better patch planning, it should be better to do ordering when we have generated all extrusions (for now, when G-Code is exported). +// FIXME: It would be better to extract the adjacency graph of extrusions from the SkeletalTrapezoidation graph. +PerimeterExtrusions ordered_perimeter_extrusions(const Perimeters &perimeters, const bool external_perimeters_first) { + PerimeterExtrusions sorted_perimeter_extrusions = get_sorted_perimeter_extrusions_by_area(perimeters); + construct_perimeter_extrusions_adjacency_graph(sorted_perimeter_extrusions); + assign_nearest_external_perimeter(sorted_perimeter_extrusions); + return extract_ordered_perimeter_extrusions(sorted_perimeter_extrusions, external_perimeters_first); +} + +} // namespace Slic3r::Arachne::PerimeterOrder \ No newline at end of file diff --git a/src/libslic3r/Arachne/PerimeterOrder.hpp b/src/libslic3r/Arachne/PerimeterOrder.hpp new file mode 100644 index 0000000000..20fc3983d3 --- /dev/null +++ b/src/libslic3r/Arachne/PerimeterOrder.hpp @@ -0,0 +1,47 @@ +#ifndef slic3r_GCode_PerimeterOrder_hpp_ +#define slic3r_GCode_PerimeterOrder_hpp_ + +#include + +namespace Slic3r::Arachne::PerimeterOrder { + +// Data structure stores ExtrusionLine (closed and open) together with additional data. +struct PerimeterExtrusion +{ + explicit PerimeterExtrusion(const Arachne::ExtrusionLine &extrusion, const double area, const Polygon &polygon, const BoundingBox &bbox) + : extrusion(extrusion), area(area), polygon(polygon), bbox(bbox) {} + + Arachne::ExtrusionLine extrusion; + // Absolute value of the area of the polygon. The value is always non-negative, even for holes. + double area = 0; + + // Polygon is non-empty only for closed extrusions. + Polygon polygon; + BoundingBox bbox; + + std::vector adjacent_perimeter_extrusions; + + // How far is this perimeter from the nearest external perimeter. Contour is always preferred over holes. + size_t depth = std::numeric_limits::max(); + PerimeterExtrusion *nearest_external_perimeter = nullptr; + + // Should this extrusion be fuzzyfied during path generation? + bool fuzzify = false; + + // Returns if ExtrusionLine is a contour or a hole. + bool is_contour() const { return extrusion.is_contour(); } + + // Returns if ExtrusionLine is closed or opened. + bool is_closed() const { return extrusion.is_closed; } + + // Returns if ExtrusionLine is an external or an internal perimeter. + bool is_external_perimeter() const { return extrusion.is_external_perimeter(); } +}; + +using PerimeterExtrusions = std::vector; + +PerimeterExtrusions ordered_perimeter_extrusions(const Perimeters &perimeters, bool external_perimeters_first); + +} // namespace Slic3r::Arachne::PerimeterOrder + +#endif // slic3r_GCode_Travels_hpp_ diff --git a/src/libslic3r/Arachne/WallToolPaths.cpp b/src/libslic3r/Arachne/WallToolPaths.cpp index 6c5dafdac4..086644e7fa 100644 --- a/src/libslic3r/Arachne/WallToolPaths.cpp +++ b/src/libslic3r/Arachne/WallToolPaths.cpp @@ -758,99 +758,4 @@ bool WallToolPaths::removeEmptyToolPaths(std::vector &toolpa return toolpaths.empty(); } -/*! - * Get the order constraints of the insets when printing walls per region / hole. - * Each returned pair consists of adjacent wall lines where the left has an inset_idx one lower than the right. - * - * Odd walls should always go after their enclosing wall polygons. - * - * \param outer_to_inner Whether the wall polygons with a lower inset_idx should go before those with a higher one. - */ -WallToolPaths::ExtrusionLineSet WallToolPaths::getRegionOrder(const std::vector &input, const bool outer_to_inner) -{ - ExtrusionLineSet order_requirements; - - // We build a grid where we map toolpath vertex locations to toolpaths, - // so that we can easily find which two toolpaths are next to each other, - // which is the requirement for there to be an order constraint. - // - // We use a PointGrid rather than a LineGrid to save on computation time. - // In very rare cases two insets might lie next to each other without having neighboring vertices, e.g. - // \ . - // | / . - // | / . - // || . - // | \ . - // | \ . - // / . - // However, because of how Arachne works this will likely never be the case for two consecutive insets. - // On the other hand one could imagine that two consecutive insets of a very large circle - // could be simplify()ed such that the remaining vertices of the two insets don't align. - // In those cases the order requirement is not captured, - // which means that the PathOrderOptimizer *might* result in a violation of the user set path order. - // This problem is expected to be not so severe and happen very sparsely. - - coord_t max_line_w = 0u; - for (const ExtrusionLine *line : input) // compute max_line_w - for (const ExtrusionJunction &junction : *line) - max_line_w = std::max(max_line_w, junction.w); - if (max_line_w == 0u) - return order_requirements; - - struct LineLoc - { - ExtrusionJunction j; - const ExtrusionLine *line; - }; - struct Locator - { - Point operator()(const LineLoc &elem) { return elem.j.p; } - }; - - // How much farther two verts may be apart due to corners. - // This distance must be smaller than 2, because otherwise - // we could create an order requirement between e.g. - // wall 2 of one region and wall 3 of another region, - // while another wall 3 of the first region would lie in between those two walls. - // However, higher values are better against the limitations of using a PointGrid rather than a LineGrid. - constexpr float diagonal_extension = 1.9f; - const auto searching_radius = coord_t(max_line_w * diagonal_extension); - using GridT = SparsePointGrid; - GridT grid(searching_radius); - - for (const ExtrusionLine *line : input) - for (const ExtrusionJunction &junction : *line) grid.insert(LineLoc{junction, line}); - for (const std::pair &pair : grid) { - const LineLoc &lineloc_here = pair.second; - const ExtrusionLine *here = lineloc_here.line; - Point loc_here = pair.second.j.p; - std::vector nearby_verts = grid.getNearby(loc_here, searching_radius); - for (const LineLoc &lineloc_nearby : nearby_verts) { - const ExtrusionLine *nearby = lineloc_nearby.line; - if (nearby == here) - continue; - if (nearby->inset_idx == here->inset_idx) - continue; - if (nearby->inset_idx > here->inset_idx + 1) - continue; // not directly adjacent - if (here->inset_idx > nearby->inset_idx + 1) - continue; // not directly adjacent - if (!shorter_then(loc_here - lineloc_nearby.j.p, (lineloc_here.j.w + lineloc_nearby.j.w) / 2 * diagonal_extension)) - continue; // points are too far away from each other - if (here->is_odd || nearby->is_odd) { - if (here->is_odd && !nearby->is_odd && nearby->inset_idx < here->inset_idx) - order_requirements.emplace(std::make_pair(nearby, here)); - if (nearby->is_odd && !here->is_odd && here->inset_idx < nearby->inset_idx) - order_requirements.emplace(std::make_pair(here, nearby)); - } else if ((nearby->inset_idx < here->inset_idx) == outer_to_inner) { - order_requirements.emplace(std::make_pair(nearby, here)); - } else { - assert((nearby->inset_idx > here->inset_idx) == outer_to_inner); - order_requirements.emplace(std::make_pair(here, nearby)); - } - } - } - return order_requirements; -} - } // namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/WallToolPaths.hpp b/src/libslic3r/Arachne/WallToolPaths.hpp index 44f3affb69..bdc8593cab 100644 --- a/src/libslic3r/Arachne/WallToolPaths.hpp +++ b/src/libslic3r/Arachne/WallToolPaths.hpp @@ -75,15 +75,6 @@ public: static bool removeEmptyToolPaths(std::vector &toolpaths); using ExtrusionLineSet = ankerl::unordered_dense::set, boost::hash>>; - /*! - * Get the order constraints of the insets when printing walls per region / hole. - * Each returned pair consists of adjacent wall lines where the left has an inset_idx one lower than the right. - * - * Odd walls should always go after their enclosing wall polygons. - * - * \param outer_to_inner Whether the wall polygons with a lower inset_idx should go before those with a higher one. - */ - static ExtrusionLineSet getRegionOrder(const std::vector &input, bool outer_to_inner); protected: /*! diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp index 8631d9e17b..82f0969048 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp @@ -236,9 +236,10 @@ bool ExtrusionLine::is_contour() const return poly.is_clockwise(); } -double ExtrusionLine::area() const -{ - assert(this->is_closed); +double ExtrusionLine::area() const { + if (!this->is_closed) + return 0.; + double a = 0.; if (this->junctions.size() >= 3) { Vec2d p1 = this->junctions.back().p.cast(); @@ -248,9 +249,25 @@ double ExtrusionLine::area() const p1 = p2; } } + return 0.5 * a; } +Points to_points(const ExtrusionLine &extrusion_line) { + Points points; + points.reserve(extrusion_line.junctions.size()); + for (const ExtrusionJunction &junction : extrusion_line.junctions) + points.emplace_back(junction.p); + return points; +} + +BoundingBox get_extents(const ExtrusionLine &extrusion_line) { + BoundingBox bbox; + for (const ExtrusionJunction &junction : extrusion_line.junctions) + bbox.merge(junction.p); + return bbox; +} + } // namespace Slic3r::Arachne namespace Slic3r { diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp index d39e1e07b9..0eef4cd9aa 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp @@ -192,6 +192,8 @@ struct ExtrusionLine bool is_contour() const; double area() const; + + bool is_external_perimeter() const { return this->inset_idx == 0; } }; static inline Slic3r::ThickPolyline to_thick_polyline(const Arachne::ExtrusionLine &line_junctions) @@ -237,6 +239,7 @@ static inline Slic3r::ThickPolyline to_thick_polyline(const ClipperLib_Z::Path & static inline Polygon to_polygon(const ExtrusionLine &line) { Polygon out; + assert(line.is_closed); assert(line.junctions.size() >= 3); assert(line.junctions.front().p == line.junctions.back().p); out.points.reserve(line.junctions.size() - 1); @@ -245,15 +248,11 @@ static inline Polygon to_polygon(const ExtrusionLine &line) return out; } -#if 0 -static BoundingBox get_extents(const ExtrusionLine &extrusion_line) -{ - BoundingBox bbox; - for (const ExtrusionJunction &junction : extrusion_line.junctions) - bbox.merge(junction.p); - return bbox; -} +Points to_points(const ExtrusionLine &extrusion_line); +BoundingBox get_extents(const ExtrusionLine &extrusion_line); + +#if 0 static BoundingBox get_extents(const std::vector &extrusion_lines) { BoundingBox bbox; @@ -272,15 +271,6 @@ static BoundingBox get_extents(const std::vector &extrusi return bbox; } -static Points to_points(const ExtrusionLine &extrusion_line) -{ - Points points; - points.reserve(extrusion_line.junctions.size()); - for (const ExtrusionJunction &junction : extrusion_line.junctions) - points.emplace_back(junction.p); - return points; -} - static std::vector to_points(const std::vector &extrusion_lines) { std::vector points; @@ -293,6 +283,8 @@ static std::vector to_points(const std::vector &e #endif using VariableWidthLines = std::vector; //; } // namespace Slic3r::Arachne diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 09eca00720..004de96040 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -500,6 +500,8 @@ set(SLIC3R_SOURCES Geometry/Voronoi.cpp Geometry/VoronoiUtils.hpp Geometry/VoronoiUtils.cpp + Arachne/PerimeterOrder.hpp + Arachne/PerimeterOrder.cpp Arachne/SkeletalTrapezoidation.hpp Arachne/SkeletalTrapezoidation.cpp Arachne/SkeletalTrapezoidationEdge.hpp diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index fff8be41b3..722294321b 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -6,7 +6,6 @@ ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher ///|/ #include "PerimeterGenerator.hpp" -#include "AABBTreeIndirect.hpp" #include "AABBTreeLines.hpp" #include "BoundingBox.hpp" #include "BridgeDetector.hpp" @@ -14,8 +13,6 @@ #include "ExPolygon.hpp" #include "ExtrusionEntity.hpp" #include "ExtrusionEntityCollection.hpp" -#include "Geometry/MedialAxis.hpp" -#include "KDTreeIndirect.hpp" #include "MultiPoint.hpp" #include "Point.hpp" #include "Polygon.hpp" @@ -25,9 +22,9 @@ #include "Surface.hpp" #include "Geometry/ConvexHull.hpp" -#include "SurfaceCollection.hpp" #include "clipper/clipper_z.hpp" +#include "Arachne/PerimeterOrder.hpp" #include "Arachne/WallToolPaths.hpp" #include "Arachne/utils/ExtrusionLine.hpp" #include "Arachne/utils/ExtrusionJunction.hpp" @@ -36,16 +33,10 @@ #include #include #include -#include #include -#include #include #include -#include -#include -#include #include -#include #include #include #include @@ -53,15 +44,13 @@ #include -// #define ARACHNE_DEBUG +//#define ARACHNE_DEBUG #ifdef ARACHNE_DEBUG #include "SVG.hpp" #include "Utils.hpp" #endif -#include "SVG.hpp" - namespace Slic3r { ExtrusionMultiPath PerimeterGenerator::thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance, const float merge_tolerance) @@ -503,29 +492,20 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path &subject, con return clipped_paths; } -struct PerimeterGeneratorArachneExtrusion -{ - Arachne::ExtrusionLine *extrusion = nullptr; - // Indicates if closed ExtrusionLine is a contour or a hole. Used it only when ExtrusionLine is a closed loop. - bool is_contour = false; - // Should this extrusion be fuzzyfied on path generation? - bool fuzzify = false; -}; - -static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::Parameters ¶ms, const Polygons &lower_slices_polygons_cache, std::vector &pg_extrusions) +static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::Parameters ¶ms, const Polygons &lower_slices_polygons_cache, Arachne::PerimeterOrder::PerimeterExtrusions &pg_extrusions) { ExtrusionEntityCollection extrusion_coll; - for (PerimeterGeneratorArachneExtrusion &pg_extrusion : pg_extrusions) { - Arachne::ExtrusionLine *extrusion = pg_extrusion.extrusion; - if (extrusion->empty()) + for (Arachne::PerimeterOrder::PerimeterExtrusion &pg_extrusion : pg_extrusions) { + Arachne::ExtrusionLine &extrusion = pg_extrusion.extrusion; + if (extrusion.empty()) continue; - const bool is_external = extrusion->inset_idx == 0; + const bool is_external = extrusion.inset_idx == 0; ExtrusionRole role_normal = is_external ? ExtrusionRole::ExternalPerimeter : ExtrusionRole::Perimeter; ExtrusionRole role_overhang = role_normal | ExtrusionRoleModifier::Bridge; if (pg_extrusion.fuzzify) - fuzzy_extrusion_line(*extrusion, scaled(params.config.fuzzy_skin_thickness.value), scaled(params.config.fuzzy_skin_point_dist.value)); + fuzzy_extrusion_line(extrusion, scaled(params.config.fuzzy_skin_thickness.value), scaled(params.config.fuzzy_skin_point_dist.value)); ExtrusionPaths paths; // detect overhanging/bridging perimeters @@ -534,9 +514,9 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P params.object_config.support_material_contact_distance.value == 0)) { ClipperLib_Z::Path extrusion_path; - extrusion_path.reserve(extrusion->size()); + extrusion_path.reserve(extrusion.size()); BoundingBox extrusion_path_bbox; - for (const Arachne::ExtrusionJunction &ej : extrusion->junctions) { + for (const Arachne::ExtrusionJunction &ej : extrusion.junctions) { extrusion_path.emplace_back(ej.p.x(), ej.p.y(), ej.w); extrusion_path_bbox.merge(Point{ej.p.x(), ej.p.y()}); } @@ -574,7 +554,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P // Arachne sometimes creates extrusion with zero-length (just two same endpoints); if (!paths.empty()) { Point start_point = paths.front().first_point(); - if (!extrusion->is_closed) { + if (!extrusion.is_closed) { // Especially for open extrusion, we need to select a starting point that is at the start // or the end of the extrusions to make one continuous line. Also, we prefer a non-overhang // starting point. @@ -607,15 +587,15 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P chain_and_reorder_extrusion_paths(paths, &start_point); } } else { - extrusion_paths_append(paths, *extrusion, role_normal, is_external ? params.ext_perimeter_flow : params.perimeter_flow); + extrusion_paths_append(paths, extrusion, role_normal, is_external ? params.ext_perimeter_flow : params.perimeter_flow); } // Append paths to collection. if (!paths.empty()) { - if (extrusion->is_closed) { + if (extrusion.is_closed) { ExtrusionLoop extrusion_loop(std::move(paths)); // Restore the orientation of the extrusion loop. - if (pg_extrusion.is_contour == extrusion_loop.is_clockwise()) + if (pg_extrusion.is_contour() == extrusion_loop.is_clockwise()) extrusion_loop.reverse_loop(); for (auto it = std::next(extrusion_loop.paths.begin()); it != extrusion_loop.paths.end(); ++it) { @@ -654,7 +634,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P } #ifdef ARACHNE_DEBUG -static void export_perimeters_to_svg(const std::string &path, const Polygons &contours, const std::vector &perimeters, const ExPolygons &infill_area) +static void export_perimeters_to_svg(const std::string &path, const Polygons &contours, const Arachne::Perimeters &perimeters, const ExPolygons &infill_area) { coordf_t stroke_width = scale_(0.03); BoundingBox bbox = get_extents(contours); @@ -663,7 +643,7 @@ static void export_perimeters_to_svg(const std::string &path, const Polygons &co svg.draw(infill_area, "cyan"); - for (const Arachne::VariableWidthLines &perimeter : perimeters) + for (const Arachne::Perimeter &perimeter : perimeters) for (const Arachne::ExtrusionLine &extrusion_line : perimeter) { ThickPolyline thick_polyline = to_thick_polyline(extrusion_line); svg.draw({thick_polyline}, "green", "blue", stroke_width); @@ -1130,8 +1110,8 @@ void PerimeterGenerator::process_arachne( ExPolygons last = offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); Polygons last_p = to_polygons(last); Arachne::WallToolPaths wall_tool_paths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), 0, params.layer_height, params.object_config, params.print_config); - std::vector perimeters = wall_tool_paths.getToolPaths(); - ExPolygons infill_contour = union_ex(wall_tool_paths.getInnerContour()); + Arachne::Perimeters perimeters = wall_tool_paths.getToolPaths(); + ExPolygons infill_contour = union_ex(wall_tool_paths.getInnerContour()); // Check if there are some remaining perimeters to generate (the number of perimeters // is greater than one together with enabled the single perimeter on top surface feature). @@ -1168,7 +1148,7 @@ void PerimeterGenerator::process_arachne( const Polygons not_top_polygons = to_polygons(not_top_expolygons); Arachne::WallToolPaths inner_wall_tool_paths(not_top_polygons, perimeter_spacing, perimeter_spacing, coord_t(inner_loop_number + 1), 0, params.layer_height, params.object_config, params.print_config); - std::vector inner_perimeters = inner_wall_tool_paths.getToolPaths(); + Arachne::Perimeters inner_perimeters = inner_wall_tool_paths.getToolPaths(); // Recalculate indexes of inner perimeters before merging them. if (!perimeters.empty()) { @@ -1197,7 +1177,7 @@ void PerimeterGenerator::process_arachne( #ifdef ARACHNE_DEBUG { static int iRun = 0; - export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour())); + export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", params.layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour())); } #endif @@ -1205,107 +1185,20 @@ void PerimeterGenerator::process_arachne( // But in rare cases, Arachne produce ExtrusionLine marked as closed but without // equal the first and the last point. assert([&perimeters = std::as_const(perimeters)]() -> bool { - for (const Arachne::VariableWidthLines &perimeter : perimeters) + for (const Arachne::Perimeter &perimeter : perimeters) for (const Arachne::ExtrusionLine &el : perimeter) if (el.is_closed && el.junctions.front().p != el.junctions.back().p) return false; return true; }()); - int start_perimeter = int(perimeters.size()) - 1; - int end_perimeter = -1; - int direction = -1; - - if (params.config.external_perimeters_first) { - start_perimeter = 0; - end_perimeter = int(perimeters.size()); - direction = 1; - } - - std::vector all_extrusions; - for (int perimeter_idx = start_perimeter; perimeter_idx != end_perimeter; perimeter_idx += direction) { - if (perimeters[perimeter_idx].empty()) - continue; - for (Arachne::ExtrusionLine &wall : perimeters[perimeter_idx]) - all_extrusions.emplace_back(&wall); - } - - // Find topological order with constraints from extrusions_constrains. - std::vector blocked(all_extrusions.size(), 0); // Value indicating how many extrusions it is blocking (preceding extrusions) an extrusion. - std::vector> blocking(all_extrusions.size()); // Each extrusion contains a vector of extrusions that are blocked by this extrusion. - ankerl::unordered_dense::map map_extrusion_to_idx; - for (size_t idx = 0; idx < all_extrusions.size(); idx++) - map_extrusion_to_idx.emplace(all_extrusions[idx], idx); - - Arachne::WallToolPaths::ExtrusionLineSet extrusions_constrains = Arachne::WallToolPaths::getRegionOrder(all_extrusions, params.config.external_perimeters_first); - for (auto [before, after] : extrusions_constrains) { - auto after_it = map_extrusion_to_idx.find(after); - ++blocked[after_it->second]; - blocking[map_extrusion_to_idx.find(before)->second].emplace_back(after_it->second); - } - - std::vector processed(all_extrusions.size(), false); // Indicate that the extrusion was already processed. - Point current_position = all_extrusions.empty() ? Point::Zero() : all_extrusions.front()->junctions.front().p; // Some starting position. - std::vector ordered_extrusions; // To store our result in. At the end we'll std::swap. - ordered_extrusions.reserve(all_extrusions.size()); - - while (ordered_extrusions.size() < all_extrusions.size()) { - size_t best_candidate = 0; - double best_distance_sqr = std::numeric_limits::max(); - bool is_best_closed = false; - - std::vector available_candidates; - for (size_t candidate = 0; candidate < all_extrusions.size(); ++candidate) { - if (processed[candidate] || blocked[candidate]) - continue; // Not a valid candidate. - available_candidates.push_back(candidate); - } - - std::sort(available_candidates.begin(), available_candidates.end(), [&all_extrusions](const size_t a_idx, const size_t b_idx) -> bool { - return all_extrusions[a_idx]->is_closed < all_extrusions[b_idx]->is_closed; - }); - - for (const size_t candidate_path_idx : available_candidates) { - auto& path = all_extrusions[candidate_path_idx]; - - if (path->junctions.empty()) { // No vertices in the path. Can't find the start position then or really plan it in. Put that at the end. - if (best_distance_sqr == std::numeric_limits::max()) { - best_candidate = candidate_path_idx; - is_best_closed = path->is_closed; - } - continue; - } - - const Point candidate_position = path->junctions.front().p; - double distance_sqr = (current_position - candidate_position).cast().norm(); - if (distance_sqr < best_distance_sqr) { // Closer than the best candidate so far. - if (path->is_closed || (!path->is_closed && best_distance_sqr != std::numeric_limits::max()) || (!path->is_closed && !is_best_closed)) { - best_candidate = candidate_path_idx; - best_distance_sqr = distance_sqr; - is_best_closed = path->is_closed; - } - } - } - - auto &best_path = all_extrusions[best_candidate]; - ordered_extrusions.push_back({best_path, best_path->is_contour(), false}); - processed[best_candidate] = true; - for (size_t unlocked_idx : blocking[best_candidate]) - blocked[unlocked_idx]--; - - if (!best_path->junctions.empty()) { //If all paths were empty, the best path is still empty. We don't upate the current position then. - if(best_path->is_closed) - current_position = best_path->junctions[0].p; //We end where we started. - else - current_position = best_path->junctions.back().p; //Pick the other end from where we started. - } - } + Arachne::PerimeterOrder::PerimeterExtrusions ordered_extrusions = Arachne::PerimeterOrder::ordered_perimeter_extrusions(perimeters, params.config.external_perimeters_first); if (params.layer_id > 0 && params.config.fuzzy_skin != FuzzySkinType::None) { - std::vector closed_loop_extrusions; - for (PerimeterGeneratorArachneExtrusion &extrusion : ordered_extrusions) - if (extrusion.extrusion->inset_idx == 0) { - if (extrusion.extrusion->is_closed && params.config.fuzzy_skin == FuzzySkinType::External) { + std::vector closed_loop_extrusions; + for (Arachne::PerimeterOrder::PerimeterExtrusion &extrusion : ordered_extrusions) + if (extrusion.extrusion.inset_idx == 0) { + if (extrusion.extrusion.is_closed && params.config.fuzzy_skin == FuzzySkinType::External) { closed_loop_extrusions.emplace_back(&extrusion); } else { extrusion.fuzzify = true; @@ -1316,11 +1209,11 @@ void PerimeterGenerator::process_arachne( ClipperLib_Z::Paths loops_paths; loops_paths.reserve(closed_loop_extrusions.size()); for (const auto &cl_extrusion : closed_loop_extrusions) { - assert(cl_extrusion->extrusion->junctions.front() == cl_extrusion->extrusion->junctions.back()); + assert(cl_extrusion->extrusion.junctions.front() == cl_extrusion->extrusion.junctions.back()); size_t loop_idx = &cl_extrusion - &closed_loop_extrusions.front(); ClipperLib_Z::Path loop_path; - loop_path.reserve(cl_extrusion->extrusion->junctions.size() - 1); - for (auto junction_it = cl_extrusion->extrusion->junctions.begin(); junction_it != std::prev(cl_extrusion->extrusion->junctions.end()); ++junction_it) + loop_path.reserve(cl_extrusion->extrusion.junctions.size() - 1); + for (auto junction_it = cl_extrusion->extrusion.junctions.begin(); junction_it != std::prev(cl_extrusion->extrusion.junctions.end()); ++junction_it) loop_path.emplace_back(junction_it->p.x(), junction_it->p.y(), loop_idx); loops_paths.emplace_back(loop_path); } From e704d8216dc966db8889c0c6cefb10f6f60c19d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 11 Apr 2024 11:02:08 +0200 Subject: [PATCH 2/2] Remove some unused functions from Arachne perimeter generator. --- .../Arachne/SkeletalTrapezoidation.cpp | 14 ++++------ .../Arachne/SkeletalTrapezoidation.hpp | 2 -- .../Arachne/SkeletalTrapezoidationGraph.cpp | 2 +- .../Arachne/SkeletalTrapezoidationGraph.hpp | 2 +- src/libslic3r/Arachne/WallToolPaths.cpp | 1 - .../Arachne/utils/ExtrusionJunction.cpp | 18 ------------- .../Arachne/utils/ExtrusionJunction.hpp | 6 +++-- src/libslic3r/Arachne/utils/ExtrusionLine.cpp | 9 ------- src/libslic3r/Arachne/utils/ExtrusionLine.hpp | 5 ---- .../Arachne/utils/SparsePointGrid.hpp | 26 ------------------- src/libslic3r/Arachne/utils/SquareGrid.cpp | 1 - src/libslic3r/CMakeLists.txt | 1 - 12 files changed, 11 insertions(+), 76 deletions(-) delete mode 100644 src/libslic3r/Arachne/utils/ExtrusionJunction.cpp diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp index 82f86e7a78..c80e70e61c 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp @@ -152,8 +152,7 @@ void SkeletalTrapezoidation::transferEdge(Point from, Point to, const VD::edge_t assert(twin->prev->twin); // Back rib assert(twin->prev->twin->prev); // Prev segment along parabola - constexpr bool is_not_next_to_start_or_end = false; // Only ribs at the end of a cell should be skipped - graph.makeRib(prev_edge, start_source_point, end_source_point, is_not_next_to_start_or_end); + graph.makeRib(prev_edge, start_source_point, end_source_point); } assert(prev_edge); } @@ -203,10 +202,8 @@ void SkeletalTrapezoidation::transferEdge(Point from, Point to, const VD::edge_t p0 = p1; v0 = v1; - if (p1_idx < discretized.size() - 1) - { // Rib for last segment gets introduced outside this function! - constexpr bool is_not_next_to_start_or_end = false; // Only ribs at the end of a cell should be skipped - graph.makeRib(prev_edge, start_source_point, end_source_point, is_not_next_to_start_or_end); + if (p1_idx < discretized.size() - 1) { // Rib for last segment gets introduced outside this function! + graph.makeRib(prev_edge, start_source_point, end_source_point); } } assert(prev_edge); @@ -462,8 +459,7 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) node_t *starting_node = vd_node_to_he_node[starting_voronoi_edge->vertex0()]; starting_node->data.distance_to_boundary = 0; - constexpr bool is_next_to_start_or_end = true; - graph.makeRib(prev_edge, start_source_point, end_source_point, is_next_to_start_or_end); + graph.makeRib(prev_edge, start_source_point, end_source_point); for (const VD::edge_type* vd_edge = starting_voronoi_edge->next(); vd_edge != ending_voronoi_edge; vd_edge = vd_edge->next()) { assert(vd_edge->is_finite()); assert(Geometry::VoronoiUtils::is_in_range(*vd_edge)); @@ -471,7 +467,7 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) Point v1 = Geometry::VoronoiUtils::to_point(vd_edge->vertex0()).cast(); Point v2 = Geometry::VoronoiUtils::to_point(vd_edge->vertex1()).cast(); transferEdge(v1, v2, *vd_edge, prev_edge, start_source_point, end_source_point, segments); - graph.makeRib(prev_edge, start_source_point, end_source_point, vd_edge->next() == ending_voronoi_edge); + graph.makeRib(prev_edge, start_source_point, end_source_point); } transferEdge(Geometry::VoronoiUtils::to_point(ending_voronoi_edge->vertex0()).cast(), end_source_point, *ending_voronoi_edge, prev_edge, start_source_point, end_source_point, segments); diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp b/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp index 20f7b59186..b4c481263b 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp @@ -572,8 +572,6 @@ protected: * Genrate small segments for local maxima where the beading would only result in a single bead */ void generateLocalMaximaSingleBeads(); - - friend bool detect_voronoi_edge_intersecting_input_segment(const VD &voronoi_diagram, const std::vector &segments); }; } // namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp b/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp index 4629396e86..0f97b23db9 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp @@ -314,7 +314,7 @@ void SkeletalTrapezoidationGraph::collapseSmallEdges(coord_t snap_dist) } } -void SkeletalTrapezoidationGraph::makeRib(edge_t*& prev_edge, Point start_source_point, Point end_source_point, bool is_next_to_start_or_end) +void SkeletalTrapezoidationGraph::makeRib(edge_t*& prev_edge, Point start_source_point, Point end_source_point) { Point p; Line(start_source_point, end_source_point).distance_to_infinite_squared(prev_edge->to->p, &p); diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.hpp b/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.hpp index efda323837..41c681f3e7 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.hpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.hpp @@ -88,7 +88,7 @@ public: */ void collapseSmallEdges(coord_t snap_dist = 5); - void makeRib(edge_t*& prev_edge, Point start_source_point, Point end_source_point, bool is_next_to_start_or_end); + void makeRib(edge_t*& prev_edge, Point start_source_point, Point end_source_point); /*! * Insert a node into the graph and connect it to the input polygon using ribs diff --git a/src/libslic3r/Arachne/WallToolPaths.cpp b/src/libslic3r/Arachne/WallToolPaths.cpp index 086644e7fa..ff09dc7b28 100644 --- a/src/libslic3r/Arachne/WallToolPaths.cpp +++ b/src/libslic3r/Arachne/WallToolPaths.cpp @@ -6,7 +6,6 @@ #include "WallToolPaths.hpp" #include "SkeletalTrapezoidation.hpp" -#include "../ClipperUtils.hpp" #include "utils/linearAlg2D.hpp" #include "EdgeGrid.hpp" #include "utils/SparseLineGrid.hpp" diff --git a/src/libslic3r/Arachne/utils/ExtrusionJunction.cpp b/src/libslic3r/Arachne/utils/ExtrusionJunction.cpp deleted file mode 100644 index 3cdfa0d8d2..0000000000 --- a/src/libslic3r/Arachne/utils/ExtrusionJunction.cpp +++ /dev/null @@ -1,18 +0,0 @@ -//Copyright (c) 2020 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. - -#include "ExtrusionJunction.hpp" - -namespace Slic3r::Arachne -{ - -bool ExtrusionJunction::operator ==(const ExtrusionJunction& other) const -{ - return p == other.p - && w == other.w - && perimeter_index == other.perimeter_index; -} - -ExtrusionJunction::ExtrusionJunction(const Point p, const coord_t w, const coord_t perimeter_index) : p(p), w(w), perimeter_index(perimeter_index) {} - -} diff --git a/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp b/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp index 146525185f..49f721b5cc 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp +++ b/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp @@ -37,9 +37,11 @@ struct ExtrusionJunction */ size_t perimeter_index; - ExtrusionJunction(const Point p, const coord_t w, const coord_t perimeter_index); + ExtrusionJunction(const Point p, const coord_t w, const coord_t perimeter_index) : p(p), w(w), perimeter_index(perimeter_index) {} - bool operator==(const ExtrusionJunction& other) const; + bool operator==(const ExtrusionJunction &other) const { + return p == other.p && w == other.w && perimeter_index == other.perimeter_index; + } }; inline Point operator-(const ExtrusionJunction& a, const ExtrusionJunction& b) diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp index 82f0969048..7626b2b4b3 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp @@ -29,15 +29,6 @@ int64_t ExtrusionLine::getLength() const return len; } -coord_t ExtrusionLine::getMinimalWidth() const -{ - return std::min_element(junctions.cbegin(), junctions.cend(), - [](const ExtrusionJunction& l, const ExtrusionJunction& r) - { - return l.w < r.w; - })->w; -} - void ExtrusionLine::simplify(const int64_t smallest_line_segment_squared, const int64_t allowed_error_distance_squared, const int64_t maximum_extrusion_area_deviation) { const size_t min_path_size = is_closed ? 3 : 2; diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp index 0eef4cd9aa..f153768762 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp @@ -136,11 +136,6 @@ struct ExtrusionLine return ret; } - /*! - * Get the minimal width of this path - */ - coord_t getMinimalWidth() const; - /*! * Removes vertices of the ExtrusionLines to make sure that they are not too high * resolution. diff --git a/src/libslic3r/Arachne/utils/SparsePointGrid.hpp b/src/libslic3r/Arachne/utils/SparsePointGrid.hpp index 7bb51d7038..127380b3eb 100644 --- a/src/libslic3r/Arachne/utils/SparsePointGrid.hpp +++ b/src/libslic3r/Arachne/utils/SparsePointGrid.hpp @@ -39,16 +39,6 @@ public: */ void insert(const Elem &elem); - /*! - * Get just any element that's within a certain radius of a point. - * - * Rather than giving a vector of nearby elements, this function just gives - * a single element, any element, in no particular order. - * \param query_pt The point to query for an object nearby. - * \param radius The radius of what is considered "nearby". - */ - const ElemT *getAnyNearby(const Point &query_pt, coord_t radius); - protected: using GridPoint = typename SparseGrid::GridPoint; @@ -68,22 +58,6 @@ void SparsePointGrid::insert(const Elem &elem) SparseGrid::m_grid.emplace(grid_loc, elem); } -template -const ElemT *SparsePointGrid::getAnyNearby(const Point &query_pt, coord_t radius) -{ - const ElemT *ret = nullptr; - const std::function &process_func = [&ret, query_pt, radius, this](const ElemT &maybe_nearby) { - if (shorter_then(m_locator(maybe_nearby) - query_pt, radius)) { - ret = &maybe_nearby; - return false; - } - return true; - }; - SparseGrid::processNearby(query_pt, radius, process_func); - - return ret; -} - } // namespace Slic3r::Arachne #endif // UTILS_SPARSE_POINT_GRID_H diff --git a/src/libslic3r/Arachne/utils/SquareGrid.cpp b/src/libslic3r/Arachne/utils/SquareGrid.cpp index ae89965795..856eb5968b 100644 --- a/src/libslic3r/Arachne/utils/SquareGrid.cpp +++ b/src/libslic3r/Arachne/utils/SquareGrid.cpp @@ -2,7 +2,6 @@ //CuraEngine is released under the terms of the AGPLv3 or higher. #include "SquareGrid.hpp" -#include "../../Point.hpp" using namespace Slic3r::Arachne; diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 004de96040..5919143126 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -482,7 +482,6 @@ set(SLIC3R_SOURCES Arachne/BeadingStrategy/WideningBeadingStrategy.hpp Arachne/BeadingStrategy/WideningBeadingStrategy.cpp Arachne/utils/ExtrusionJunction.hpp - Arachne/utils/ExtrusionJunction.cpp Arachne/utils/ExtrusionLine.hpp Arachne/utils/ExtrusionLine.cpp Arachne/utils/HalfEdge.hpp