From d06831076d1cbd915d7dd236be44ae4ade9df200 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 26 Sep 2019 17:30:03 +0200 Subject: [PATCH] WIP: Consolidation of shortest path calculations, various chaining algorithms are replaced with the improved TSP algorithm. --- src/libslic3r/ClipperUtils.cpp | 21 ++++++------- src/libslic3r/Geometry.cpp | 56 +++------------------------------- src/libslic3r/Geometry.hpp | 3 -- src/libslic3r/Layer.cpp | 5 ++- src/libslic3r/PrintObject.cpp | 11 ++----- src/libslic3r/ShortestPath.cpp | 16 ++++++++++ src/libslic3r/ShortestPath.hpp | 4 +++ xs/xsp/Geometry.xsp | 5 +-- 8 files changed, 43 insertions(+), 78 deletions(-) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 4c6e542f4..c3183bd8e 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -1,5 +1,6 @@ #include "ClipperUtils.hpp" #include "Geometry.hpp" +#include "ShortestPath.hpp" // #define CLIPPER_UTILS_DEBUG @@ -671,21 +672,19 @@ void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval) // collect ordering points Points ordering_points; ordering_points.reserve(nodes.size()); - for (ClipperLib::PolyNodes::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { - Point p((*it)->Contour.front().X, (*it)->Contour.front().Y); - ordering_points.emplace_back(p); - } + for (ClipperLib::PolyNode *pn : nodes) + ordering_points.emplace_back(Point(pn->Contour.front().X, pn->Contour.front().Y)); // perform the ordering - ClipperLib::PolyNodes ordered_nodes; - Slic3r::Geometry::chained_path_items(ordering_points, nodes, ordered_nodes); - + ClipperLib::PolyNodes ordered_nodes = chain_clipper_polynodes(ordering_points, nodes); + // push results recursively - for (ClipperLib::PolyNodes::iterator it = ordered_nodes.begin(); it != ordered_nodes.end(); ++it) { + for (ClipperLib::PolyNode *pn : ordered_nodes) { // traverse the next depth - traverse_pt((*it)->Childs, retval); - retval->emplace_back(ClipperPath_to_Slic3rPolygon((*it)->Contour)); - if ((*it)->IsHole()) retval->back().reverse(); // ccw + traverse_pt(pn->Childs, retval); + retval->emplace_back(ClipperPath_to_Slic3rPolygon(pn->Contour)); + if (pn->IsHole()) + retval->back().reverse(); // ccw } } diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index cc8a86a96..8cf4047a1 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -309,49 +309,7 @@ convex_hull(const Polygons &polygons) return convex_hull(std::move(pp)); } -/* accepts an arrayref of points and returns a list of indices - according to a nearest-neighbor walk */ -void -chained_path(const Points &points, std::vector &retval, Point start_near) -{ - PointConstPtrs my_points; - std::map indices; - my_points.reserve(points.size()); - for (Points::const_iterator it = points.begin(); it != points.end(); ++it) { - my_points.push_back(&*it); - indices[&*it] = it - points.begin(); - } - - retval.reserve(points.size()); - while (!my_points.empty()) { - Points::size_type idx = start_near.nearest_point_index(my_points); - start_near = *my_points[idx]; - retval.push_back(indices[ my_points[idx] ]); - my_points.erase(my_points.begin() + idx); - } -} - -void -chained_path(const Points &points, std::vector &retval) -{ - if (points.empty()) return; // can't call front() on empty vector - chained_path(points, retval, points.front()); -} - -/* retval and items must be different containers */ -template -void -chained_path_items(Points &points, T &items, T &retval) -{ - std::vector indices; - chained_path(points, indices); - for (std::vector::const_iterator it = indices.begin(); it != indices.end(); ++it) - retval.push_back(items[*it]); -} -template void chained_path_items(Points &points, ClipperLib::PolyNodes &items, ClipperLib::PolyNodes &retval); - -bool -directions_parallel(double angle1, double angle2, double max_diff) +bool directions_parallel(double angle1, double angle2, double max_diff) { double diff = fabs(angle1 - angle2); max_diff += EPSILON; @@ -359,8 +317,7 @@ directions_parallel(double angle1, double angle2, double max_diff) } template -bool -contains(const std::vector &vector, const Point &point) +bool contains(const std::vector &vector, const Point &point) { for (typename std::vector::const_iterator it = vector.begin(); it != vector.end(); ++it) { if (it->contains(point)) return true; @@ -369,16 +326,14 @@ contains(const std::vector &vector, const Point &point) } template bool contains(const ExPolygons &vector, const Point &point); -double -rad2deg_dir(double angle) +double rad2deg_dir(double angle) { angle = (angle < PI) ? (-angle + PI/2.0) : (angle + PI/2.0); if (angle < 0) angle += PI; return rad2deg(angle); } -void -simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval) +void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval) { Polygons pp; for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++it) { @@ -391,8 +346,7 @@ simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval) *retval = Slic3r::simplify_polygons(pp); } -double -linint(double value, double oldmin, double oldmax, double newmin, double newmax) +double linint(double value, double oldmin, double oldmax, double newmin, double newmax) { return (value - oldmin) * (newmax - newmin) / (oldmax - oldmin) + newmin; } diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index eec267322..a574209d8 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -138,9 +138,6 @@ Pointf3s convex_hull(Pointf3s points); Polygon convex_hull(Points points); Polygon convex_hull(const Polygons &polygons); -void chained_path(const Points &points, std::vector &retval, Point start_near); -void chained_path(const Points &points, std::vector &retval); -template void chained_path_items(Points &points, T &items, T &retval); bool directions_parallel(double angle1, double angle2, double max_diff = 0); template bool contains(const std::vector &vector, const Point &point); template T rad2deg(T angle) { return T(180.0) * angle / T(PI); } diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 4ac64b777..94f114a26 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -1,8 +1,8 @@ #include "Layer.hpp" #include "ClipperUtils.hpp" -#include "Geometry.hpp" #include "Print.hpp" #include "Fill/Fill.hpp" +#include "ShortestPath.hpp" #include "SVG.hpp" #include @@ -57,8 +57,7 @@ void Layer::make_slices() ordering_points.push_back(ex.contour.first_point()); // sort slices - std::vector order; - Slic3r::Geometry::chained_path(ordering_points, order); + std::vector order = chain_points(ordering_points); // populate slices vector for (size_t i : order) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 2834d9105..4559df8b7 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -75,13 +74,9 @@ PrintBase::ApplyStatus PrintObject::set_copies(const Points &points) { // Order copies with a nearest-neighbor search. std::vector copies; - { - std::vector ordered_copies; - Slic3r::Geometry::chained_path(points, ordered_copies); - copies.reserve(ordered_copies.size()); - for (size_t point_idx : ordered_copies) - copies.emplace_back(points[point_idx] + m_copies_shift); - } + copies.reserve(points.size()); + for (const Point &pt : points) + copies.emplace_back(pt + m_copies_shift); // Invalidate and set copies. PrintBase::ApplyStatus status = PrintBase::APPLY_STATUS_UNCHANGED; if (copies != m_copies) { diff --git a/src/libslic3r/ShortestPath.cpp b/src/libslic3r/ShortestPath.cpp index 79e0fdf11..61762b66d 100644 --- a/src/libslic3r/ShortestPath.cpp +++ b/src/libslic3r/ShortestPath.cpp @@ -339,6 +339,22 @@ std::vector chain_points(const Points &points, Point *start_near) return out; } +template static inline T chain_path_items(const Points &points, const T &items) +{ + auto segment_end_point = [&points](size_t idx, bool /* first_point */) -> const Point& { return points[idx]; }; + std::vector> ordered = chain_segments(segment_end_point, points.size(), nullptr); + T out; + out.reserve(items.size()); + for (auto &segment_and_reversal : ordered) + out.emplace_back(items[segment_and_reversal.first]); + return out; +} + +ClipperLib::PolyNodes chain_clipper_polynodes(const Points &points, const ClipperLib::PolyNodes &items) +{ + return chain_path_items(points, items); +} + std::vector> chain_print_object_instances(const Print &print) { // Order objects using a nearest neighbor search. diff --git a/src/libslic3r/ShortestPath.hpp b/src/libslic3r/ShortestPath.hpp index c02e24aee..3a1b1af13 100644 --- a/src/libslic3r/ShortestPath.hpp +++ b/src/libslic3r/ShortestPath.hpp @@ -8,6 +8,8 @@ #include #include +namespace ClipperLib { class PolyNode; } + namespace Slic3r { std::vector chain_points(const Points &points, Point *start_near = nullptr); @@ -16,6 +18,8 @@ std::vector> chain_extrusion_entities(std::vector &entities, std::vector> &chain); void chain_and_reorder_extrusion_entities(std::vector &entities, const Point *start_near = nullptr); +std::vector chain_clipper_polynodes(const Points &points, const std::vector &items); + // Chain instances of print objects by an approximate shortest path. // Returns pairs of PrintObject idx and instance of that PrintObject. class Print; diff --git a/xs/xsp/Geometry.xsp b/xs/xsp/Geometry.xsp index b7e92ba69..5d6454e8a 100644 --- a/xs/xsp/Geometry.xsp +++ b/xs/xsp/Geometry.xsp @@ -3,6 +3,7 @@ %{ #include #include "libslic3r/Geometry.hpp" +#include "libslic3r/ShortestPath.hpp" %} @@ -49,7 +50,7 @@ std::vector chained_path(points) Points points CODE: - Slic3r::Geometry::chained_path(points, RETVAL); + RETVAL = chain_points(points); OUTPUT: RETVAL @@ -58,7 +59,7 @@ chained_path_from(points, start_from) Points points Point* start_from CODE: - Slic3r::Geometry::chained_path(points, RETVAL, *start_from); + RETVAL = chain_points(points, start_from); OUTPUT: RETVAL