From cf00527ef00b494d333d868c090dfa514f8f7fda Mon Sep 17 00:00:00 2001 From: "xun.zhang" Date: Fri, 27 Dec 2024 20:02:01 +0800 Subject: [PATCH] ENH: support hole compensation for Arachne jira:NONE Signed-off-by: xun.zhang Change-Id: Iaaca3a27f44e13049088480a9946117e984d5b5a --- .../Arachne/SkeletalTrapezoidation.cpp | 36 +++++++++---- .../Arachne/SkeletalTrapezoidation.hpp | 8 ++- .../Arachne/SkeletalTrapezoidationEdge.hpp | 11 ++++ .../Arachne/SkeletalTrapezoidationGraph.cpp | 15 ++++-- src/libslic3r/Arachne/WallToolPaths.cpp | 42 +++++++++++++--- src/libslic3r/Arachne/WallToolPaths.hpp | 4 ++ .../Arachne/utils/ExtrusionJunction.cpp | 5 +- .../Arachne/utils/ExtrusionJunction.hpp | 6 ++- src/libslic3r/Arachne/utils/ExtrusionLine.cpp | 16 +++++- src/libslic3r/Arachne/utils/ExtrusionLine.hpp | 2 + src/libslic3r/Geometry/VoronoiUtils.cpp | 2 + src/libslic3r/PerimeterGenerator.cpp | 50 +++++++++++++++++-- 12 files changed, 166 insertions(+), 31 deletions(-) diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp index 5d085f333..0ff08289d 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp @@ -104,7 +104,7 @@ SkeletalTrapezoidation::node_t &SkeletalTrapezoidation::makeNode(const VD::verte } } -void SkeletalTrapezoidation::transferEdge(Point from, Point to, const VD::edge_type &vd_edge, edge_t *&prev_edge, Point &start_source_point, Point &end_source_point, const std::vector &segments) { +void SkeletalTrapezoidation::transferEdge(Point from, Point to, const VD::edge_type &vd_edge, edge_t *&prev_edge, Point &start_source_point, Point &end_source_point, const std::vector &segments, const bool hole_compensation_flag) { auto he_edge_it = vd_edge_to_he_edge.find(vd_edge.twin()); if (he_edge_it != vd_edge_to_he_edge.end()) { // Twin segment(s) have already been made @@ -128,7 +128,7 @@ void SkeletalTrapezoidation::transferEdge(Point from, Point to, const VD::edge_t edge->twin = twin; twin->twin = edge; edge->from->incident_edge = edge; - + edge->data.setHoleCompensationFlag(hole_compensation_flag); if (prev_edge) { edge->prev = prev_edge; @@ -192,7 +192,8 @@ void SkeletalTrapezoidation::transferEdge(Point from, Point to, const VD::edge_t edge->from = v0; edge->to = v1; edge->from->incident_edge = edge; - + edge->data.setHoleCompensationFlag(hole_compensation_flag); + if (prev_edge) { edge->prev = prev_edge; @@ -373,13 +374,16 @@ bool SkeletalTrapezoidation::computePointCellRange(const VD::cell_type &cell, Po SkeletalTrapezoidation::SkeletalTrapezoidation(const Polygons& polys, const BeadingStrategy& beading_strategy, double transitioning_angle, coord_t discretization_step_size, coord_t transition_filter_dist, coord_t allowed_filter_deviation, - coord_t beading_propagation_transition_dist + coord_t beading_propagation_transition_dist, bool enable_hole_compensation, + const std::vector& hole_indices ): transitioning_angle(transitioning_angle), discretization_step_size(discretization_step_size), transition_filter_dist(transition_filter_dist), allowed_filter_deviation(allowed_filter_deviation), beading_propagation_transition_dist(beading_propagation_transition_dist), - beading_strategy(beading_strategy) + beading_strategy(beading_strategy), + enable_hole_compensation(enable_hole_compensation), + hole_indices(hole_indices) { constructFromPolygons(polys); } @@ -390,6 +394,8 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) this->outline = polys; #endif + std::set hole_indices_(this->hole_indices.begin(), this->hole_indices.end()); + // Check self intersections. assert([&polys]() -> bool { EdgeGrid::Grid grid; @@ -436,10 +442,15 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) const VD::edge_type *ending_voronoi_edge = nullptr; // Compute and store result in above variables + bool apply_hole_compensation = this->enable_hole_compensation; + if (cell.contains_point()) { const bool keep_going = computePointCellRange(cell, start_source_point, end_source_point, starting_voronoi_edge, ending_voronoi_edge, segments); if (!keep_going) continue; + + const PolygonsPointIndex source_point_idx = Geometry::VoronoiUtils::get_source_point_index(cell, segments.begin(), segments.end()); + apply_hole_compensation &= hole_indices_.find(source_point_idx.poly_idx) != hole_indices_.end(); } else { assert(cell.contains_segment()); Geometry::SegmentCellRange cell_range = Geometry::VoronoiUtils::compute_segment_cell_range(cell, segments.cbegin(), segments.cend()); @@ -448,6 +459,9 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) end_source_point = cell_range.segment_end_point; starting_voronoi_edge = cell_range.edge_begin; ending_voronoi_edge = cell_range.edge_end; + + const Segment& source_segment = Geometry::VoronoiUtils::get_source_segment(cell, segments.cbegin(), segments.cend()); + apply_hole_compensation &= hole_indices_.find(source_segment.poly_idx) != hole_indices_.end(); } if (!starting_voronoi_edge || !ending_voronoi_edge) { @@ -458,7 +472,7 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) // Copy start to end edge to graph assert(Geometry::VoronoiUtils::is_in_range(*starting_voronoi_edge)); edge_t *prev_edge = nullptr; - transferEdge(start_source_point, Geometry::VoronoiUtils::to_point(starting_voronoi_edge->vertex1()).cast(), *starting_voronoi_edge, prev_edge, start_source_point, end_source_point, segments); + transferEdge(start_source_point, Geometry::VoronoiUtils::to_point(starting_voronoi_edge->vertex1()).cast(), *starting_voronoi_edge, prev_edge, start_source_point, end_source_point, segments,apply_hole_compensation); node_t *starting_node = vd_node_to_he_node[starting_voronoi_edge->vertex0()]; starting_node->data.distance_to_boundary = 0; @@ -470,11 +484,11 @@ 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); + transferEdge(v1, v2, *vd_edge, prev_edge, start_source_point, end_source_point, segments,apply_hole_compensation); graph.makeRib(prev_edge, start_source_point, end_source_point, vd_edge->next() == ending_voronoi_edge); } - 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); + 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, apply_hole_compensation); prev_edge->to->data.distance_to_boundary = 0; } @@ -1775,6 +1789,8 @@ void SkeletalTrapezoidation::generateJunctions(ptr_vector_t& continue; } + bool apply_hole_compensation = edge->data.getHoleCompensationFlag(); + Beading* beading = &getOrCreateBeading(edge->to, node_beadings)->beading; edge_junctions.emplace_back(std::make_shared()); edge_.data.setExtrusionJunctions(edge_junctions.back()); // initialization @@ -1828,7 +1844,7 @@ void SkeletalTrapezoidation::generateJunctions(ptr_vector_t& { // Snap to start node if it is really close, in order to be able to see 3-way intersection later on more robustly junction = a; } - ret.emplace_back(junction, beading->bead_widths[junction_idx], junction_idx); + ret.emplace_back(ExtrusionJunction(junction, beading->bead_widths[junction_idx], junction_idx, apply_hole_compensation)); } } } @@ -2113,7 +2129,7 @@ void SkeletalTrapezoidation::generateLocalMaximaSingleBeads() constexpr coord_t n_segments = 6; for (coord_t segment = 0; segment < n_segments; segment++) { float a = 2.0 * M_PI / n_segments * segment; - line.junctions.emplace_back(node.p + Point(r * cos(a), r * sin(a)), width, inset_index); + line.junctions.emplace_back(ExtrusionJunction(node.p + Point(r * cos(a), r * sin(a)), width, inset_index, false)); } } } diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp b/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp index 75ff94015..043c83c7b 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp @@ -60,6 +60,8 @@ class SkeletalTrapezoidation template using ptr_vector_t = std::vector>; + bool enable_hole_compensation; + std::vector hole_indices; double transitioning_angle; //!< How pointy a region should be before we apply the method. Equals 180* - limit_bisector_angle coord_t discretization_step_size; //!< approximate size of segments when parabolic VD edges get discretized (and vertex-vertex edges) coord_t transition_filter_dist; //!< Filter transition mids (i.e. anchors) closer together than this @@ -108,7 +110,9 @@ public: , coord_t discretization_step_size , coord_t transition_filter_dist , coord_t allowed_filter_deviation - , coord_t beading_propagation_transition_dist); + , coord_t beading_propagation_transition_dist + , bool enable_hole_compensation + , const std::vector& hole_indices); /*! * A skeletal graph through the polygons that we need to fill with beads. @@ -180,7 +184,7 @@ protected: * Transfer an edge from the VD to the HE and perform discretization of parabolic edges (and vertex-vertex edges) * \p prev_edge serves as input and output. May be null as input. */ - void transferEdge(Point from, Point to, const VD::edge_type &vd_edge, edge_t *&prev_edge, Point &start_source_point, Point &end_source_point, const std::vector &segments); + void transferEdge(Point from, Point to, const VD::edge_type &vd_edge, edge_t *&prev_edge, Point &start_source_point, Point &end_source_point, const std::vector &segments, const bool hole_compensation_flag); /*! * Discretize a Voronoi edge that represents the medial axis of a vertex- diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp b/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp index e0d3fe81d..8f6562f58 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp @@ -110,7 +110,18 @@ public: return extrusion_junctions.lock(); } + void setHoleCompensationFlag(bool enabled) + { + apply_hole_compensation = enabled; + } + + bool getHoleCompensationFlag() const + { + return apply_hole_compensation; + } + private: + bool apply_hole_compensation{ false }; Central is_central; //! whether the edge is significant; whether the source segments have a sharp angle; -1 is unknown std::weak_ptr> transitions; diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp b/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp index 4ef96eda1..61d9a2463 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp @@ -324,12 +324,14 @@ void SkeletalTrapezoidationGraph::makeRib(edge_t*& prev_edge, Point start_source nodes.emplace_front(SkeletalTrapezoidationJoint(), p); node_t* node = &nodes.front(); node->data.distance_to_boundary = 0; - + edges.emplace_front(SkeletalTrapezoidationEdge(SkeletalTrapezoidationEdge::EdgeType::EXTRA_VD)); edge_t* forth_edge = &edges.front(); + forth_edge->data.setHoleCompensationFlag(prev_edge->data.getHoleCompensationFlag()); edges.emplace_front(SkeletalTrapezoidationEdge(SkeletalTrapezoidationEdge::EdgeType::EXTRA_VD)); edge_t* back_edge = &edges.front(); - + back_edge->data.setHoleCompensationFlag(prev_edge->data.getHoleCompensationFlag()); + prev_edge->next = forth_edge; forth_edge->prev = prev_edge; forth_edge->from = prev_edge->to; @@ -339,7 +341,7 @@ void SkeletalTrapezoidationGraph::makeRib(edge_t*& prev_edge, Point start_source back_edge->from = node; back_edge->to = prev_edge->to; node->incident_edge = back_edge; - + prev_edge = back_edge; } @@ -352,6 +354,8 @@ std::pairp; + bool apply_hole_compensation = edge.data.getHoleCompensationFlag(); + const Line source_segment = getSource(edge); Point px; source_segment.distance_to_squared(p, &px); @@ -372,6 +376,11 @@ std::pairdata.setHoleCompensationFlag(apply_hole_compensation); + second->data.setHoleCompensationFlag(apply_hole_compensation); + outward_edge->data.setHoleCompensationFlag(apply_hole_compensation); + inward_edge->data.setHoleCompensationFlag(apply_hole_compensation); + if (edge_before) { edge_before->next = first; diff --git a/src/libslic3r/Arachne/WallToolPaths.cpp b/src/libslic3r/Arachne/WallToolPaths.cpp index 13bc90172..5035d8d92 100644 --- a/src/libslic3r/Arachne/WallToolPaths.cpp +++ b/src/libslic3r/Arachne/WallToolPaths.cpp @@ -41,6 +41,12 @@ WallToolPaths::WallToolPaths(const Polygons& outline, const coord_t bead_width_0 { } +void WallToolPaths::EnableHoleCompensation(bool enable_, const std::vector& hole_indices_) +{ + enable_hole_compensation = enable_; + hole_indices = hole_indices_; +} + void simplify(Polygon &thiss, const int64_t smallest_line_segment_squared, const int64_t allowed_error_distance_squared) { if (thiss.size() < 3) { @@ -437,6 +443,13 @@ const std::vector &WallToolPaths::generate() if (this->inset_count < 1) return toolpaths; + size_t original_outline_size = outline.size(); + bool outline_size_change = false; + // Lambda for checking size changes + auto update_outline_size_change = [original_outline_size, &outline_size_change](const Polygons& polys) { + outline_size_change |= (original_outline_size != polys.size()); + }; + const coord_t smallest_segment = Slic3r::Arachne::meshfix_maximum_resolution; const coord_t allowed_distance = Slic3r::Arachne::meshfix_maximum_deviation; const coord_t epsilon_offset = (allowed_distance / 2) - 1; @@ -446,26 +459,37 @@ const std::vector &WallToolPaths::generate() // Simplify outline for boost::voronoi consumption. Absolutely no self intersections or near-self intersections allowed: // TODO: Open question: Does this indeed fix all (or all-but-one-in-a-million) cases for manifold but otherwise possibly complex polygons? Polygons prepared_outline = offset(offset(offset(outline, -epsilon_offset), epsilon_offset * 2), -epsilon_offset); - simplify(prepared_outline, smallest_segment, allowed_distance); - fixSelfIntersections(epsilon_offset, prepared_outline); - removeDegenerateVerts(prepared_outline); - removeColinearEdges(prepared_outline, 0.005); + update_outline_size_change(prepared_outline); + + // Helper function for applying a sequence of operations with size change tracking + auto process_with_size_check = [&](auto&& operation) { + operation(); + update_outline_size_change(prepared_outline); + }; + + process_with_size_check([&] { simplify(prepared_outline, smallest_segment, allowed_distance);}); + process_with_size_check([&] { fixSelfIntersections(epsilon_offset, prepared_outline); }); + process_with_size_check([&] { removeDegenerateVerts(prepared_outline); }); + process_with_size_check([&] { removeColinearEdges(prepared_outline, 0.005); }); // Removing collinear edges may introduce self intersections, so we need to fix them again - fixSelfIntersections(epsilon_offset, prepared_outline); - removeDegenerateVerts(prepared_outline); - removeSmallAreas(prepared_outline, small_area_length * small_area_length, false); + process_with_size_check([&] { fixSelfIntersections(epsilon_offset, prepared_outline); }); + process_with_size_check([&] { removeDegenerateVerts(prepared_outline); }); + process_with_size_check([&] { removeSmallAreas(prepared_outline, small_area_length * small_area_length, false); }); // The functions above could produce intersecting polygons that could cause a crash inside Arachne. // Applying Clipper union should be enough to get rid of this issue. // Clipper union also fixed an issue in Arachne that in post-processing Voronoi diagram, some edges // didn't have twin edges. (a non-planar Voronoi diagram probably caused this). prepared_outline = union_(prepared_outline); + update_outline_size_change(prepared_outline); if (area(prepared_outline) <= 0) { assert(toolpaths.empty()); return toolpaths; } + bool apply_hole_compensation = this->enable_hole_compensation && !outline_size_change; + const float external_perimeter_extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(unscale(bead_width_0), float(this->layer_height)); const float perimeter_extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(unscale(bead_width_x), float(this->layer_height)); @@ -501,7 +525,9 @@ const std::vector &WallToolPaths::generate() discretization_step_size, transition_filter_dist, allowed_filter_deviation, - wall_transition_length + wall_transition_length, + apply_hole_compensation, + hole_indices ); wall_maker.generateToolpaths(toolpaths); diff --git a/src/libslic3r/Arachne/WallToolPaths.hpp b/src/libslic3r/Arachne/WallToolPaths.hpp index 6bb115319..ed8e4b1f3 100644 --- a/src/libslic3r/Arachne/WallToolPaths.hpp +++ b/src/libslic3r/Arachne/WallToolPaths.hpp @@ -44,6 +44,7 @@ public: */ WallToolPaths(const Polygons& outline, coord_t bead_width_0, coord_t bead_width_x, size_t inset_count, coord_t wall_0_inset, coordf_t layer_height, const WallToolPathsParams ¶ms); + void EnableHoleCompensation(bool enable, const std::vector& hole_indices_); /*! * Generates the Toolpaths * \return A reference to the newly create ToolPaths @@ -131,6 +132,9 @@ private: std::vector toolpaths; // hole_indices; }; } // namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/utils/ExtrusionJunction.cpp b/src/libslic3r/Arachne/utils/ExtrusionJunction.cpp index 3cdfa0d8d..f8063f019 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionJunction.cpp +++ b/src/libslic3r/Arachne/utils/ExtrusionJunction.cpp @@ -10,9 +10,10 @@ bool ExtrusionJunction::operator ==(const ExtrusionJunction& other) const { return p == other.p && w == other.w - && perimeter_index == other.perimeter_index; + && perimeter_index == other.perimeter_index + && hole_compensation_flag == other.hole_compensation_flag; } -ExtrusionJunction::ExtrusionJunction(const Point p, const coord_t w, const coord_t perimeter_index) : p(p), w(w), perimeter_index(perimeter_index) {} +ExtrusionJunction::ExtrusionJunction(const Point p, const coord_t w, const coord_t perimeter_index, const bool compensation_flag) : p(p), w(w), perimeter_index(perimeter_index),hole_compensation_flag(compensation_flag) {} } diff --git a/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp b/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp index 146525185..c2a5fb4cc 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp +++ b/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp @@ -18,6 +18,10 @@ namespace Slic3r::Arachne */ struct ExtrusionJunction { + /*! + * whether the junction is generated from a hole that needs compensation + */ + bool hole_compensation_flag; /*! * The position of the centreline of the path when it reaches this junction. * This is the position that should end up in the g-code eventually. @@ -37,7 +41,7 @@ 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, const bool hole_compensation); bool operator==(const ExtrusionJunction& other) const; }; diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp index 676acb4c7..923738cc8 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp @@ -147,7 +147,7 @@ void ExtrusionLine::simplify(const int64_t smallest_line_segment_squared, const else { // New point seems like a valid one. - const ExtrusionJunction new_to_add = ExtrusionJunction(intersection_point, current.w, current.perimeter_index); + const ExtrusionJunction new_to_add = ExtrusionJunction(intersection_point, current.w, current.perimeter_index, current.hole_compensation_flag); // If there was a previous point added, remove it. if(!new_junctions.empty()) { @@ -232,6 +232,20 @@ int64_t ExtrusionLine::calculateExtrusionAreaDeviationError(ExtrusionJunction A, } } +bool ExtrusionLine::shouldApplyHoleCompensation(const double threshold) const +{ + int64_t total_length = 0; + int64_t marked_length = 0; + for (size_t idx = 1; idx < junctions.size(); ++idx) { + int64_t length = (junctions[idx].p - junctions[idx - 1].p).cast().norm(); + total_length += length; + int marked_rate = (int)(junctions[idx].hole_compensation_flag) + (int)(junctions[idx - 1].hole_compensation_flag); + marked_length += length * marked_rate / 2; + } + double rate = (double)(marked_length) / (double)(total_length); + return rate > threshold; +} + bool ExtrusionLine::is_contour() const { if (!this->is_closed) diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp index fda492475..09bacdd8d 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp @@ -190,6 +190,8 @@ struct ExtrusionLine * */ static int64_t calculateExtrusionAreaDeviationError(ExtrusionJunction A, ExtrusionJunction B, ExtrusionJunction C, coord_t& weighted_average_width); + bool shouldApplyHoleCompensation(const double threshold = 0.8) const; + bool is_contour() const; double area() const; diff --git a/src/libslic3r/Geometry/VoronoiUtils.cpp b/src/libslic3r/Geometry/VoronoiUtils.cpp index 1e9436325..6917f5e45 100644 --- a/src/libslic3r/Geometry/VoronoiUtils.cpp +++ b/src/libslic3r/Geometry/VoronoiUtils.cpp @@ -7,6 +7,7 @@ namespace Slic3r::Geometry { +using PolygonsSegmentIndexIt = std::vector::iterator; using PolygonsSegmentIndexConstIt = std::vector::const_iterator; using LinesIt = Lines::iterator; using ColoredLinesIt = ColoredLines::iterator; @@ -29,6 +30,7 @@ template SegmentCellRange VoronoiUtils::compute_segment_cell_range(const template SegmentCellRange VoronoiUtils::compute_segment_cell_range(const VoronoiDiagram::cell_type &, PolygonsSegmentIndexConstIt, PolygonsSegmentIndexConstIt); template Points VoronoiUtils::discretize_parabola(const Point &, const Arachne::PolygonsSegmentIndex &, const Point &, const Point &, coord_t, float); template Arachne::PolygonsPointIndex VoronoiUtils::get_source_point_index(const VoronoiDiagram::cell_type &, PolygonsSegmentIndexConstIt, PolygonsSegmentIndexConstIt); +template Arachne::PolygonsPointIndex VoronoiUtils::get_source_point_index(const VoronoiDiagram::cell_type &, PolygonsSegmentIndexIt, PolygonsSegmentIndexIt); template typename boost::polygon::enable_if< diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 8e60900e3..5b86773d2 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -103,12 +103,13 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine& ext_lines, double fuzzy const double range_random_point_dist = fuzzy_skin_point_dist / 2.; double dist_left_over = double(rand()) * (min_dist_between_points / 2) / double(RAND_MAX); // the distance to be traversed on the line before making the first new point + // do not apply hole compensation in fuzzy skin mode auto* p0 = &ext_lines.front(); std::vector out; out.reserve(ext_lines.size()); for (auto& p1 : ext_lines) { if (p0->p == p1.p) { // Connect endpoints. - out.emplace_back(p1.p, p1.w, p1.perimeter_index); + out.emplace_back(p1.p, p1.w, p1.perimeter_index, false); continue; } @@ -119,7 +120,7 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine& ext_lines, double fuzzy double dist_last_point = dist_left_over + p0p1_size * 2.; for (double p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + double(rand()) * range_random_point_dist / double(RAND_MAX)) { double r = double(rand()) * (fuzzy_skin_thickness * 2.) / double(RAND_MAX) - fuzzy_skin_thickness; - out.emplace_back(p0->p + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast(), p1.w, p1.perimeter_index); + out.emplace_back(p0->p + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast(), p1.w, p1.perimeter_index, false); dist_last_point = p0pa_dist; } dist_left_over = p0p1_size - dist_last_point; @@ -128,7 +129,7 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine& ext_lines, double fuzzy while (out.size() < 3) { size_t point_idx = ext_lines.size() - 2; - out.emplace_back(ext_lines[point_idx].p, ext_lines[point_idx].w, ext_lines[point_idx].perimeter_index); + out.emplace_back(ext_lines[point_idx].p, ext_lines[point_idx].w, ext_lines[point_idx].perimeter_index,false); if (point_idx == 0) break; --point_idx; @@ -1070,6 +1071,8 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p extrusion_paths_append(paths, *extrusion, role, is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow); } + bool apply_hole_compensation = extrusion->shouldApplyHoleCompensation(); + // Append paths to collection. if (!paths.empty()) { if (extrusion->is_closed) { @@ -1086,6 +1089,11 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p } assert(extrusion_loop.paths.front().first_point() == extrusion_loop.paths.back().last_point()); + if (apply_hole_compensation) { + for (auto& path : extrusion_loop.paths) + path.set_customize_flag(CustomizeFlag::cfCircleCompensation); + extrusion_loop.set_customize_flag(CustomizeFlag::cfCircleCompensation); + } extrusion_coll.append(std::move(extrusion_loop)); } else { @@ -1108,6 +1116,11 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p multi_path.paths.emplace_back(std::move(*it_path)); } + if (apply_hole_compensation) { + for (auto& path : multi_path.paths) + path.set_customize_flag(CustomizeFlag::cfCircleCompensation); + multi_path.set_customize_flag(CustomizeFlag::cfCircleCompensation); + } extrusion_coll.append(ExtrusionMultiPath(std::move(multi_path))); } } @@ -1120,6 +1133,20 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p } +static Polygons to_polygons_with_flag(const ExPolygon& src, const bool contour_flag, const std::vector& holes_flag, std::vector& flags_out) +{ + Polygons polygons; + polygons.reserve(src.num_contours()); + polygons.push_back(src.contour); + polygons.insert(polygons.end(), src.holes.begin(), src.holes.end()); + flags_out.reserve(holes_flag.size() + 1); + if(contour_flag == true) + flags_out.emplace_back(0); + for (size_t idx = 0; idx < holes_flag.size(); ++idx) + flags_out.emplace_back(holes_flag[idx] + 1); + return polygons; +} + void PerimeterGenerator::process_classic() { @@ -1781,8 +1808,19 @@ void PerimeterGenerator::process_arachne() // detect how many perimeters must be generated for this island int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops + bool apply_circle_compensation = true; + ExPolygons last = offset_ex(surface.expolygon.simplify_p(surface_simplify_resolution), -float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); - Polygons last_p = to_polygons(last); + int new_size = std::accumulate(last.begin(), last.end(), 0, [](int prev, const ExPolygon& expoly) { return prev + expoly.num_contours(); }); + if (last.size() != 1 || new_size != surface.expolygon.num_contours()) + apply_circle_compensation = false; + + std::vector circle_poly_indices; + Polygons last_p; + if (apply_circle_compensation) + last_p = to_polygons_with_flag(last.front(), surface.counter_circle_compensation, surface.holes_circle_compensation, circle_poly_indices); + else + last_p = to_polygons(last); // check whether to activate one wall mode if (generate_one_wall && !generate_one_wall_by_first_layer) @@ -1829,6 +1867,10 @@ void PerimeterGenerator::process_arachne() coord_t real_loop_number = generate_one_wall ? 1 : loop_number + 1; Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, real_loop_number, 0, layer_height, input_params); + + if (apply_circle_compensation) + wallToolPaths.EnableHoleCompensation(true, circle_poly_indices); + std::vector perimeters = wallToolPaths.getToolPaths(); ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour()); #ifdef ARACHNE_DEBUG