From fe51f7783975e6090a4a9397d15998e955252096 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 16 Nov 2022 12:03:31 +0100 Subject: [PATCH] Improvements in performance of Medial Axis algorithm. Fixes Slicing slows or hangs on "Generating Permiters 20%" cpu load is at 100% #8164 Fixes Slicing hangs on generating perimeters with thing:3565827 (30g) #3259 --- src/libslic3r/ExPolygon.cpp | 11 +- src/libslic3r/ExPolygon.hpp | 8 +- src/libslic3r/Geometry/MedialAxis.cpp | 248 ++++++++++------------- src/libslic3r/Geometry/MedialAxis.hpp | 39 ++-- src/libslic3r/Geometry/VoronoiOffset.hpp | 2 +- src/libslic3r/PerimeterGenerator.cpp | 4 +- tests/fff_print/test_thin_walls.cpp | 18 +- tests/libslic3r/test_voronoi.cpp | 1 - 8 files changed, 157 insertions(+), 174 deletions(-) diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 771603548..8dc0ff547 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -206,12 +206,10 @@ void ExPolygon::simplify(double tolerance, ExPolygons* expolygons) const append(*expolygons, this->simplify(tolerance)); } -void -ExPolygon::medial_axis(double max_width, double min_width, ThickPolylines* polylines) const +void ExPolygon::medial_axis(double min_width, double max_width, ThickPolylines* polylines) const { // init helper object - Slic3r::Geometry::MedialAxis ma(max_width, min_width, this); - ma.lines = this->lines(); + Slic3r::Geometry::MedialAxis ma(min_width, max_width, *this); // compute the Voronoi diagram and extract medial axis polylines ThickPolylines pp; @@ -318,11 +316,10 @@ ExPolygon::medial_axis(double max_width, double min_width, ThickPolylines* polyl polylines->insert(polylines->end(), pp.begin(), pp.end()); } -void -ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines) const +void ExPolygon::medial_axis(double min_width, double max_width, Polylines* polylines) const { ThickPolylines tp; - this->medial_axis(max_width, min_width, &tp); + this->medial_axis(min_width, max_width, &tp); polylines->insert(polylines->end(), tp.begin(), tp.end()); } diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 55c3e60ef..17b5b1963 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -70,10 +70,10 @@ public: Polygons simplify_p(double tolerance) const; ExPolygons simplify(double tolerance) const; void simplify(double tolerance, ExPolygons* expolygons) const; - void medial_axis(double max_width, double min_width, ThickPolylines* polylines) const; - void medial_axis(double max_width, double min_width, Polylines* polylines) const; - Polylines medial_axis(double max_width, double min_width) const - { Polylines out; this->medial_axis(max_width, min_width, &out); return out; } + void medial_axis(double min_width, double max_width, ThickPolylines* polylines) const; + void medial_axis(double min_width, double max_width, Polylines* polylines) const; + Polylines medial_axis(double min_width, double max_width) const + { Polylines out; this->medial_axis(min_width, max_width, &out); return out; } Lines lines() const; // Number of contours (outer contour with holes). diff --git a/src/libslic3r/Geometry/MedialAxis.cpp b/src/libslic3r/Geometry/MedialAxis.cpp index ce38a6c70..c92796f41 100644 --- a/src/libslic3r/Geometry/MedialAxis.cpp +++ b/src/libslic3r/Geometry/MedialAxis.cpp @@ -1,6 +1,7 @@ #include "MedialAxis.hpp" #include "clipper.hpp" +#include "VoronoiOffset.hpp" #ifdef SLIC3R_DEBUG namespace boost { namespace polygon { @@ -392,8 +393,7 @@ inline const typename VD::point_type retrieve_cell_point(const typename VD::cell } template -inline std::pair -measure_edge_thickness(const VD &vd, const typename VD::edge_type& edge, const SEGMENTS &segments) +inline std::pair measure_edge_thickness(const VD &vd, const typename VD::edge_type& edge, const SEGMENTS &segments) { typedef typename VD::coord_type T; const typename VD::point_type pa(edge.vertex0()->x(), edge.vertex0()->y()); @@ -442,15 +442,21 @@ private: const Lines &lines; }; -void -MedialAxis::build(ThickPolylines* polylines) +MedialAxis::MedialAxis(double min_width, double max_width, const ExPolygon &expolygon) : + m_expolygon(expolygon), m_lines(expolygon.lines()), m_min_width(min_width), m_max_width(max_width) +{} + +void MedialAxis::build(ThickPolylines* polylines) { - construct_voronoi(this->lines.begin(), this->lines.end(), &this->vd); + construct_voronoi(m_lines.begin(), m_lines.end(), &m_vd); + Slic3r::Voronoi::annotate_inside_outside(m_vd, m_lines); +// static constexpr double threshold_alpha = M_PI / 12.; // 30 degrees +// std::vector skeleton_edges = Slic3r::Voronoi::skeleton_edges_rough(vd, lines, threshold_alpha); /* // DEBUG: dump all Voronoi edges { - for (VD::const_edge_iterator edge = this->vd.edges().begin(); edge != this->vd.edges().end(); ++edge) { + for (VD::const_edge_iterator edge = m_vd.edges().begin(); edge != m_vd.edges().end(); ++edge) { if (edge->is_infinite()) continue; ThickPolyline polyline; @@ -463,73 +469,59 @@ MedialAxis::build(ThickPolylines* polylines) */ //typedef const VD::vertex_type vert_t; - typedef const VD::edge_type edge_t; + using edge_t = const VD::edge_type; // collect valid edges (i.e. prune those not belonging to MAT) // note: this keeps twins, so it inserts twice the number of the valid edges - this->valid_edges.clear(); - { - std::set seen_edges; - for (VD::const_edge_iterator edge = this->vd.edges().begin(); edge != this->vd.edges().end(); ++edge) { - // if we only process segments representing closed loops, none if the - // infinite edges (if any) would be part of our MAT anyway - if (edge->is_secondary() || edge->is_infinite()) continue; - - // don't re-validate twins - if (seen_edges.find(&*edge) != seen_edges.end()) continue; // TODO: is this needed? - seen_edges.insert(&*edge); - seen_edges.insert(edge->twin()); - - if (!this->validate_edge(&*edge)) continue; - this->valid_edges.insert(&*edge); - this->valid_edges.insert(edge->twin()); + m_edge_data.assign(m_vd.edges().size() / 2, EdgeData{}); + for (VD::const_edge_iterator edge = m_vd.edges().begin(); edge != m_vd.edges().end(); edge += 2) + if (edge->is_primary() && edge->is_finite() && + (Voronoi::vertex_category(edge->vertex0()) == Voronoi::VertexCategory::Inside || + Voronoi::vertex_category(edge->vertex1()) == Voronoi::VertexCategory::Inside) && + this->validate_edge(&*edge)) { + // Valid skeleton edge. + this->edge_data(*edge).first.active = true; } - } - this->edges = this->valid_edges; // iterate through the valid edges to build polylines - while (!this->edges.empty()) { - const edge_t* edge = *this->edges.begin(); + ThickPolyline reverse_polyline; + for (VD::const_edge_iterator seed_edge = m_vd.edges().begin(); seed_edge != m_vd.edges().end(); seed_edge += 2) + if (EdgeData &seed_edge_data = this->edge_data(*seed_edge).first; seed_edge_data.active) { + // Mark this edge as visited. + seed_edge_data.active = false; + + // Start a polyline. + ThickPolyline polyline; + polyline.points.emplace_back(seed_edge->vertex0()->x(), seed_edge->vertex0()->y()); + polyline.points.emplace_back(seed_edge->vertex1()->x(), seed_edge->vertex1()->y()); + polyline.width.emplace_back(seed_edge_data.width_start); + polyline.width.emplace_back(seed_edge_data.width_end); + // Grow the polyline in a forward direction. + this->process_edge_neighbors(&*seed_edge, &polyline); - // start a polyline - ThickPolyline polyline; - polyline.points.push_back(Point( edge->vertex0()->x(), edge->vertex0()->y() )); - polyline.points.push_back(Point( edge->vertex1()->x(), edge->vertex1()->y() )); - polyline.width.push_back(this->thickness[edge].first); - polyline.width.push_back(this->thickness[edge].second); + // Grow the polyline in a backward direction. + reverse_polyline.clear(); + this->process_edge_neighbors(seed_edge->twin(), &reverse_polyline); + polyline.points.insert(polyline.points.begin(), reverse_polyline.points.rbegin(), reverse_polyline.points.rend()); + polyline.width.insert(polyline.width.begin(), reverse_polyline.width.rbegin(), reverse_polyline.width.rend()); + polyline.endpoints.first = reverse_polyline.endpoints.second; - // remove this edge and its twin from the available edges - (void)this->edges.erase(edge); - (void)this->edges.erase(edge->twin()); + assert(polyline.width.size() == polyline.points.size() * 2 - 2); - // get next points - this->process_edge_neighbors(edge, &polyline); - - // get previous points - { - ThickPolyline rpolyline; - this->process_edge_neighbors(edge->twin(), &rpolyline); - polyline.points.insert(polyline.points.begin(), rpolyline.points.rbegin(), rpolyline.points.rend()); - polyline.width.insert(polyline.width.begin(), rpolyline.width.rbegin(), rpolyline.width.rend()); - polyline.endpoints.first = rpolyline.endpoints.second; + // Prevent loop endpoints from being extended. + if (polyline.first_point() == polyline.last_point()) { + polyline.endpoints.first = false; + polyline.endpoints.second = false; + } + + // Append polyline to result. + polylines->emplace_back(std::move(polyline)); } - - assert(polyline.width.size() == polyline.points.size()*2 - 2); - - // prevent loop endpoints from being extended - if (polyline.first_point() == polyline.last_point()) { - polyline.endpoints.first = false; - polyline.endpoints.second = false; - } - - // append polyline to result - polylines->push_back(polyline); - } #ifdef SLIC3R_DEBUG { static int iRun = 0; - dump_voronoi_to_svg(this->lines, this->vd, polylines, debug_out_path("MedialAxis-%d.svg", iRun ++).c_str()); + dump_voronoi_to_svg(m_lines, m_vd, polylines, debug_out_path("MedialAxis-%d.svg", iRun ++).c_str()); printf("Thick lines: "); for (ThickPolylines::const_iterator it = polylines->begin(); it != polylines->end(); ++ it) { ThickLines lines = it->thicklines(); @@ -542,56 +534,66 @@ MedialAxis::build(ThickPolylines* polylines) #endif /* SLIC3R_DEBUG */ } -void -MedialAxis::build(Polylines* polylines) +void MedialAxis::build(Polylines* polylines) { ThickPolylines tp; this->build(&tp); polylines->insert(polylines->end(), tp.begin(), tp.end()); } -void -MedialAxis::process_edge_neighbors(const VD::edge_type* edge, ThickPolyline* polyline) +void MedialAxis::process_edge_neighbors(const VD::edge_type *edge, ThickPolyline* polyline) { - while (true) { + for (;;) { // Since rot_next() works on the edge starting point but we want // to find neighbors on the ending point, we just swap edge with // its twin. - const VD::edge_type* twin = edge->twin(); + const VD::edge_type *twin = edge->twin(); // count neighbors for this edge - std::vector neighbors; - for (const VD::edge_type* neighbor = twin->rot_next(); neighbor != twin; - neighbor = neighbor->rot_next()) { - if (this->valid_edges.count(neighbor) > 0) neighbors.push_back(neighbor); - } + size_t num_neighbors = 0; + const VD::edge_type *first_neighbor = nullptr; + for (const VD::edge_type *neighbor = twin->rot_next(); neighbor != twin; neighbor = neighbor->rot_next()) + if (this->edge_data(*neighbor).first.active) { + if (num_neighbors == 0) + first_neighbor = neighbor; + ++ num_neighbors; + } // if we have a single neighbor then we can continue recursively - if (neighbors.size() == 1) { - const VD::edge_type* neighbor = neighbors.front(); - - // break if this is a closed loop - if (this->edges.count(neighbor) == 0) return; - - Point new_point(neighbor->vertex1()->x(), neighbor->vertex1()->y()); - polyline->points.push_back(new_point); - polyline->width.push_back(this->thickness[neighbor].first); - polyline->width.push_back(this->thickness[neighbor].second); - (void)this->edges.erase(neighbor); - (void)this->edges.erase(neighbor->twin()); - edge = neighbor; - } else if (neighbors.size() == 0) { + if (num_neighbors == 1) { + if (std::pair neighbor_data = this->edge_data(*first_neighbor); + neighbor_data.first.active) { + neighbor_data.first.active = false; + polyline->points.emplace_back(first_neighbor->vertex1()->x(), first_neighbor->vertex1()->y()); + if (neighbor_data.second) { + polyline->width.push_back(neighbor_data.first.width_end); + polyline->width.push_back(neighbor_data.first.width_start); + } else { + polyline->width.push_back(neighbor_data.first.width_start); + polyline->width.push_back(neighbor_data.first.width_end); + } + edge = first_neighbor; + // Continue chaining. + continue; + } + } else if (num_neighbors == 0) { polyline->endpoints.second = true; - return; } else { - // T-shaped or star-shaped joint - return; + // T-shaped or star-shaped joint } + // Stop chaining. + break; } } bool MedialAxis::validate_edge(const VD::edge_type* edge) { + auto retrieve_segment = [this](const VD::cell_type* cell) -> const Line& { return m_lines[cell->source_index()]; }; + auto retrieve_endpoint = [retrieve_segment](const VD::cell_type* cell) -> const Point& { + const Line &line = retrieve_segment(cell); + return cell->source_category() == boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT ? line.a : line.b; + }; + // prevent overflows and detect almost-infinite edges #ifndef CLIPPERLIB_INT32 if (std::abs(edge->vertex0()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) || @@ -602,32 +604,18 @@ bool MedialAxis::validate_edge(const VD::edge_type* edge) #endif // CLIPPERLIB_INT32 // construct the line representing this edge of the Voronoi diagram - const Line line( - Point( edge->vertex0()->x(), edge->vertex0()->y() ), - Point( edge->vertex1()->x(), edge->vertex1()->y() ) - ); - - // discard edge if it lies outside the supplied shape - // this could maybe be optimized (checking inclusion of the endpoints - // might give false positives as they might belong to the contour itself) - if (this->expolygon != NULL) { - if (line.a == line.b) { - // in this case, contains(line) returns a false positive - if (!this->expolygon->contains(line.a)) return false; - } else { - if (!this->expolygon->contains(line)) return false; - } - } + const Line line({ edge->vertex0()->x(), edge->vertex0()->y() }, + { edge->vertex1()->x(), edge->vertex1()->y() }); // retrieve the original line segments which generated the edge we're checking const VD::cell_type* cell_l = edge->cell(); const VD::cell_type* cell_r = edge->twin()->cell(); - const Line &segment_l = this->retrieve_segment(cell_l); - const Line &segment_r = this->retrieve_segment(cell_r); + const Line &segment_l = retrieve_segment(cell_l); + const Line &segment_r = retrieve_segment(cell_r); /* SVG svg("edge.svg"); - svg.draw(*this->expolygon); + svg.draw(m_expolygon); svg.draw(line); svg.draw(segment_l, "red"); svg.draw(segment_r, "blue"); @@ -651,30 +639,30 @@ bool MedialAxis::validate_edge(const VD::edge_type* edge) coordf_t w0 = cell_r->contains_segment() ? segment_r.distance_to(line.a)*2 - : (this->retrieve_endpoint(cell_r) - line.a).cast().norm()*2; + : (retrieve_endpoint(cell_r) - line.a).cast().norm()*2; coordf_t w1 = cell_l->contains_segment() ? segment_l.distance_to(line.b)*2 - : (this->retrieve_endpoint(cell_l) - line.b).cast().norm()*2; + : (retrieve_endpoint(cell_l) - line.b).cast().norm()*2; if (cell_l->contains_segment() && cell_r->contains_segment()) { // calculate the relative angle between the two boundary segments double angle = fabs(segment_r.orientation() - segment_l.orientation()); - if (angle > PI) angle = 2*PI - angle; + if (angle > PI) + angle = 2. * PI - angle; assert(angle >= 0 && angle <= PI); - + // fabs(angle) ranges from 0 (collinear, same direction) to PI (collinear, opposite direction) // we're interested only in segments close to the second case (facing segments) // so we allow some tolerance. // this filter ensures that we're dealing with a narrow/oriented area (longer than thick) // we don't run it on edges not generated by two segments (thus generated by one segment // and the endpoint of another segment), since their orientation would not be meaningful - if (PI - angle > PI/8) { + if (PI - angle > PI / 8.) { // angle is not narrow enough - // only apply this filter to segments that are not too short otherwise their // angle could possibly be not meaningful - if (w0 < SCALED_EPSILON || w1 < SCALED_EPSILON || line.length() >= this->min_width) + if (w0 < SCALED_EPSILON || w1 < SCALED_EPSILON || line.length() >= m_min_width) return false; } } else { @@ -682,31 +670,17 @@ bool MedialAxis::validate_edge(const VD::edge_type* edge) return false; } - if (w0 < this->min_width && w1 < this->min_width) - return false; - - if (w0 > this->max_width && w1 > this->max_width) - return false; - - this->thickness[edge] = std::make_pair(w0, w1); - this->thickness[edge->twin()] = std::make_pair(w1, w0); - - return true; -} - -const Line& MedialAxis::retrieve_segment(const VD::cell_type* cell) const -{ - return this->lines[cell->source_index()]; -} - -const Point& MedialAxis::retrieve_endpoint(const VD::cell_type* cell) const -{ - const Line& line = this->retrieve_segment(cell); - if (cell->source_category() == boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT) { - return line.a; - } else { - return line.b; + if ((w0 >= m_min_width || w1 >= m_min_width) && + (w0 <= m_max_width || w1 <= m_max_width)) { + std::pair ed = this->edge_data(*edge); + if (ed.second) + std::swap(w0, w1); + ed.first.width_start = w0; + ed.first.width_end = w1; + return true; } + + return false; } } } // namespace Slicer::Geometry diff --git a/src/libslic3r/Geometry/MedialAxis.hpp b/src/libslic3r/Geometry/MedialAxis.hpp index cfbb5f080..b1354ddb2 100644 --- a/src/libslic3r/Geometry/MedialAxis.hpp +++ b/src/libslic3r/Geometry/MedialAxis.hpp @@ -4,30 +4,43 @@ #include "Voronoi.hpp" #include "../ExPolygon.hpp" -namespace Slic3r { namespace Geometry { +namespace Slic3r::Geometry { class MedialAxis { public: - Lines lines; - const ExPolygon* expolygon; - double max_width; - double min_width; - MedialAxis(double _max_width, double _min_width, const ExPolygon* _expolygon = NULL) - : expolygon(_expolygon), max_width(_max_width), min_width(_min_width) {}; + MedialAxis(double min_width, double max_width, const ExPolygon &expolygon); void build(ThickPolylines* polylines); void build(Polylines* polylines); private: + // Input + const ExPolygon &m_expolygon; + Lines m_lines; + // for filtering of the skeleton edges + double m_min_width; + double m_max_width; + + // Voronoi Diagram. using VD = VoronoiDiagram; - VD vd; - std::set edges, valid_edges; - std::map > thickness; + VD m_vd; + + // Annotations of the VD skeleton edges. + struct EdgeData { + bool active { false }; + double width_start { 0 }; + double width_end { 0 }; + }; + // Returns a reference to EdgeData and a "reversed" boolean. + std::pair edge_data(const VD::edge_type &edge) { + size_t edge_id = &edge - &m_vd.edges().front(); + return { m_edge_data[edge_id / 2], (edge_id & 1) != 0 }; + } + std::vector m_edge_data; + void process_edge_neighbors(const VD::edge_type* edge, ThickPolyline* polyline); bool validate_edge(const VD::edge_type* edge); - const Line& retrieve_segment(const VD::cell_type* cell) const; - const Point& retrieve_endpoint(const VD::cell_type* cell) const; }; -} } // namespace Slicer::Geometry +} // namespace Slicer::Geometry #endif // slic3r_Geometry_MedialAxis_hpp_ diff --git a/src/libslic3r/Geometry/VoronoiOffset.hpp b/src/libslic3r/Geometry/VoronoiOffset.hpp index 359fe010c..fa72ae2bc 100644 --- a/src/libslic3r/Geometry/VoronoiOffset.hpp +++ b/src/libslic3r/Geometry/VoronoiOffset.hpp @@ -1,4 +1,4 @@ -// Polygon offsetting using Voronoi diagram prodiced by boost::polygon. +// Polygon offsetting using Voronoi diagram produced by boost::polygon. #ifndef slic3r_VoronoiOffset_hpp_ #define slic3r_VoronoiOffset_hpp_ diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 17240d71d..a3540ff09 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -920,7 +920,7 @@ void PerimeterGenerator::process_classic( float(min_width / 2.)); // the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop for (ExPolygon &ex : expp) - ex.medial_axis(ext_perimeter_width + ext_perimeter_spacing2, min_width, &thin_walls); + ex.medial_axis(min_width, ext_perimeter_width + ext_perimeter_spacing2, &thin_walls); } if (params.spiral_vase && offsets.size() > 1) { // Remove all but the largest area polygon. @@ -1066,7 +1066,7 @@ void PerimeterGenerator::process_classic( offset2_ex(gaps, - float(max / 2.), float(max / 2. + ClipperSafetyOffset))); ThickPolylines polylines; for (const ExPolygon &ex : gaps_ex) - ex.medial_axis(max, min, &polylines); + ex.medial_axis(min, max, &polylines); if (! polylines.empty()) { ExtrusionEntityCollection gap_fill; variable_width(polylines, erGapFill, params.solid_infill_flow, gap_fill.entities); diff --git a/tests/fff_print/test_thin_walls.cpp b/tests/fff_print/test_thin_walls.cpp index cd80f3bd6..59fb6b080 100644 --- a/tests/fff_print/test_thin_walls.cpp +++ b/tests/fff_print/test_thin_walls.cpp @@ -16,7 +16,7 @@ SCENARIO("Medial Axis", "[ThinWalls]") { auto hole_in_square = Polygon::new_scale({ {140, 140}, {140, 160}, {160, 160}, {160, 140} }); ExPolygon expolygon{ square, hole_in_square }; WHEN("Medial axis is extracted") { - Polylines res = expolygon.medial_axis(scaled(40.), scaled(0.5)); + Polylines res = expolygon.medial_axis(scaled(0.5), scaled(40.)); THEN("medial axis of a square shape is a single path") { REQUIRE(res.size() == 1); } @@ -32,7 +32,7 @@ SCENARIO("Medial Axis", "[ThinWalls]") { GIVEN("narrow rectangle") { ExPolygon expolygon{ Polygon::new_scale({ {100, 100}, {120, 100}, {120, 200}, {100, 200} }) }; WHEN("Medial axis is extracted") { - Polylines res = expolygon.medial_axis(scaled(20.), scaled(0.5)); + Polylines res = expolygon.medial_axis(scaled(0.5), scaled(20.)); THEN("medial axis of a narrow rectangle is a single line") { REQUIRE(res.size() == 1); } @@ -50,7 +50,7 @@ SCENARIO("Medial Axis", "[ThinWalls]") { {100, 200} })}; WHEN("Medial axis is extracted") { - Polylines res = expolygon.medial_axis(scaled(1.), scaled(0.5)); + Polylines res = expolygon.medial_axis(scaled(0.5), scaled(1.)); THEN("medial axis of a narrow rectangle with an extra vertex is still a single line") { REQUIRE(res.size() == 1); } @@ -81,7 +81,7 @@ SCENARIO("Medial Axis", "[ThinWalls]") { {1687689,4235755},{1218962,3499999},{827499,2748020},{482284,1920196},{219954,1088186},{31126,236479},{0,0},{1005754,0} }}; WHEN("Medial axis is extracted") { - Polylines res = expolygon.medial_axis(scaled(1.324888), scaled(0.25)); + Polylines res = expolygon.medial_axis(scaled(0.25), scaled(1.324888)); THEN("medial axis of a semicircumference is a single line") { REQUIRE(res.size() == 1); } @@ -103,7 +103,7 @@ SCENARIO("Medial Axis", "[ThinWalls]") { GIVEN("narrow trapezoid") { ExPolygon expolygon{ Polygon::new_scale({ {100, 100}, {120, 100}, {112, 200}, {108, 200} }) }; WHEN("Medial axis is extracted") { - Polylines res = expolygon.medial_axis(scaled(20.), scaled(0.5)); + Polylines res = expolygon.medial_axis(scaled(0.5), scaled(20.)); THEN("medial axis of a narrow trapezoid is a single line") { REQUIRE(res.size() == 1); } @@ -115,7 +115,7 @@ SCENARIO("Medial Axis", "[ThinWalls]") { GIVEN("L shape") { ExPolygon expolygon{ Polygon::new_scale({ {100, 100}, {120, 100}, {120, 180}, {200, 180}, {200, 200}, {100, 200}, }) }; WHEN("Medial axis is extracted") { - Polylines res = expolygon.medial_axis(scaled(20.), scaled(0.5)); + Polylines res = expolygon.medial_axis(scaled(0.5), scaled(20.)); THEN("medial axis of an L shape is a single line") { REQUIRE(res.size() == 1); } @@ -134,7 +134,7 @@ SCENARIO("Medial Axis", "[ThinWalls]") { {-220815482,-37738966},{-221117540,-37738966},{-221117540,-51762024},{-203064906,-51762024}, }}; WHEN("Medial axis is extracted") { - Polylines res = expolygon.medial_axis(819998., 102499.75); + Polylines res = expolygon.medial_axis(102499.75, 819998.); THEN("medial axis is a single line") { REQUIRE(res.size() == 1); } @@ -147,7 +147,7 @@ SCENARIO("Medial Axis", "[ThinWalls]") { GIVEN("narrow triangle") { ExPolygon expolygon{ Polygon::new_scale({ {50, 100}, {1000, 102}, {50, 104} }) }; WHEN("Medial axis is extracted") { - Polylines res = expolygon.medial_axis(scaled(4.), scaled(0.5)); + Polylines res = expolygon.medial_axis(scaled(0.5), scaled(4.)); THEN("medial axis of a narrow triangle is a single line") { REQUIRE(res.size() == 1); } @@ -159,7 +159,7 @@ SCENARIO("Medial Axis", "[ThinWalls]") { GIVEN("GH #2474") { ExPolygon expolygon{{ {91294454,31032190},{11294481,31032190},{11294481,29967810},{44969182,29967810},{89909960,29967808},{91294454,29967808} }}; WHEN("Medial axis is extracted") { - Polylines res = expolygon.medial_axis(1871238, 500000); + Polylines res = expolygon.medial_axis(500000, 1871238); THEN("medial axis is a single line") { REQUIRE(res.size() == 1); } diff --git a/tests/libslic3r/test_voronoi.cpp b/tests/libslic3r/test_voronoi.cpp index fb36541dd..967cb0e96 100644 --- a/tests/libslic3r/test_voronoi.cpp +++ b/tests/libslic3r/test_voronoi.cpp @@ -1918,7 +1918,6 @@ TEST_CASE("Voronoi skeleton", "[VoronoiSkeleton]") Lines lines = to_lines(poly); construct_voronoi(lines.begin(), lines.end(), &vd); Slic3r::Voronoi::annotate_inside_outside(vd, lines); - Slic3r::Voronoi::annotate_inside_outside(vd, lines); static constexpr double threshold_alpha = M_PI / 12.; // 30 degrees std::vector skeleton_edges = Slic3r::Voronoi::skeleton_edges_rough(vd, lines, threshold_alpha);