From 0516aac71588d9558fff9ab9cfd125d41af6b412 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 23 Nov 2013 21:39:05 +0100 Subject: [PATCH] Ported chained_path() to XS --- lib/Slic3r/Fill.pm | 2 +- lib/Slic3r/Geometry.pm | 28 ++++------------------------ lib/Slic3r/Print.pm | 2 +- xs/src/Geometry.cpp | 30 ++++++++++++++++++++++++++++++ xs/src/Geometry.hpp | 2 ++ xs/src/Point.cpp | 18 ++++++++++++++---- xs/src/Point.hpp | 4 +++- xs/xsp/Geometry.xsp | 17 +++++++++++++++++ xs/xsp/my.map | 2 ++ 9 files changed, 74 insertions(+), 31 deletions(-) diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 95bd8e5af..4b0354cee 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -195,7 +195,7 @@ sub make_fill { } # organize infill paths using a nearest-neighbor search - @fills = @fills[ chained_path(\@fills_ordering_points) ]; + @fills = @fills[ @{chained_path(\@fills_ordering_points)} ]; return @fills; } diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index f3cb24f32..99405146d 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -565,28 +565,6 @@ sub polyline_remove_short_segments { } } -# accepts an arrayref of points; it returns a list of indices -# according to a nearest-neighbor walk -sub chained_path { - my ($items, $start_near) = @_; - - my @points = @$items; - my %indices = map { $points[$_] => $_ } 0 .. $#points; - - my @result = (); - if (!$start_near && @points) { - $start_near = shift @points; - push @result, $indices{$start_near}; - } - while (@points) { - my $idx = $start_near->nearest_point_index(\@points); - ($start_near) = splice @points, $idx, 1; - push @result, $indices{$start_near}; - } - - return @result; -} - # accepts an arrayref; each item should be an arrayref whose first # item is the point to be used for the shortest path, and the second # one is the value to be returned in output (if the second item @@ -594,13 +572,15 @@ sub chained_path { sub chained_path_items { my ($items, $start_near) = @_; - my @indices = chained_path([ map $_->[0], @$items ], $start_near); + my @indices = defined($start_near) + ? @{chained_path_from([ map $_->[0], @$items ], $start_near)} + : @{chained_path([ map $_->[0], @$items ])}; return [ map $_->[1], @$items[@indices] ]; } sub chained_path_points { my ($points, $start_near) = @_; - return [ @$points[ chained_path($points, $start_near) ] ]; + return [ @$points[ @{chained_path_from($points, $start_near)} ] ]; } sub douglas_peucker { diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 1b3dd253d..e8b6a4419 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -862,7 +862,7 @@ sub write_gcode { } } else { # order objects using a nearest neighbor search - my @obj_idx = chained_path([ map Slic3r::Point->new(@{$_->copies->[0]}), @{$self->objects} ]); + my @obj_idx = @{chained_path([ map Slic3r::Point->new(@{$_->copies->[0]}), @{$self->objects} ])}; # sort layers by Z my %layers = (); # print_z => [ [layers], [layers], [layers] ] by obj_idx diff --git a/xs/src/Geometry.cpp b/xs/src/Geometry.cpp index 050300e61..8da689b70 100644 --- a/xs/src/Geometry.cpp +++ b/xs/src/Geometry.cpp @@ -1,5 +1,6 @@ #include "Geometry.hpp" #include +#include namespace Slic3r { @@ -50,4 +51,33 @@ convex_hull(Points points, Polygon &hull) free(out_hull); } +/* accepts an arrayref of points and returns a list of indices + according to a nearest-neighbor walk */ +void +chained_path(Points &points, std::vector &retval, Point start_near) +{ + PointPtrs my_points; + std::map indices; + my_points.reserve(points.size()); + for (Points::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(Points &points, std::vector &retval) +{ + if (points.empty()) return; // can't call front() on empty vector + chained_path(points, retval, points.front()); +} + } diff --git a/xs/src/Geometry.hpp b/xs/src/Geometry.hpp index 8085d7f2b..0cd1a9bce 100644 --- a/xs/src/Geometry.hpp +++ b/xs/src/Geometry.hpp @@ -6,6 +6,8 @@ namespace Slic3r { void convex_hull(Points points, Polygon &hull); +void chained_path(Points &points, std::vector &retval, Point start_near); +void chained_path(Points &points, std::vector &retval); } diff --git a/xs/src/Point.cpp b/xs/src/Point.cpp index c8049c8d8..13e7d2361 100644 --- a/xs/src/Point.cpp +++ b/xs/src/Point.cpp @@ -40,20 +40,30 @@ Point::coincides_with(const Point &point) const } int -Point::nearest_point_index(const Points points) const +Point::nearest_point_index(Points &points) const +{ + PointPtrs p; + p.reserve(points.size()); + for (Points::iterator it = points.begin(); it != points.end(); ++it) + p.push_back(&*it); + return this->nearest_point_index(p); +} + +int +Point::nearest_point_index(PointPtrs &points) const { int idx = -1; double distance = -1; // double because long is limited to 2147483647 on some platforms and it's not enough - for (Points::const_iterator it = points.begin(); it != points.end(); ++it) { + for (PointPtrs::const_iterator it = points.begin(); it != points.end(); ++it) { /* If the X distance of the candidate is > than the total distance of the best previous candidate, we know we don't want it */ - double d = pow(this->x - (*it).x, 2); + double d = pow(this->x - (*it)->x, 2); if (distance != -1 && d > distance) continue; /* If the Y distance of the candidate is > than the total distance of the best previous candidate, we know we don't want it */ - d += pow(this->y - (*it).y, 2); + d += pow(this->y - (*it)->y, 2); if (distance != -1 && d > distance) continue; idx = it - points.begin(); diff --git a/xs/src/Point.hpp b/xs/src/Point.hpp index cf0ec2163..d89a12cb8 100644 --- a/xs/src/Point.hpp +++ b/xs/src/Point.hpp @@ -10,6 +10,7 @@ namespace Slic3r { class Line; class Point; typedef std::vector Points; +typedef std::vector PointPtrs; class Point { @@ -22,7 +23,8 @@ class Point void rotate(double angle, Point* center); bool coincides_with(const Point &point) const; bool coincides_with(const Point* point) const; - int nearest_point_index(const Points points) const; + int nearest_point_index(Points &points) const; + int nearest_point_index(PointPtrs &points) const; Point* nearest_point(Points points) const; double distance_to(const Point* point) const; double distance_to(const Line* line) const; diff --git a/xs/xsp/Geometry.xsp b/xs/xsp/Geometry.xsp index 52750c8f2..09724e368 100644 --- a/xs/xsp/Geometry.xsp +++ b/xs/xsp/Geometry.xsp @@ -20,4 +20,21 @@ convex_hull(points) OUTPUT: RETVAL +std::vector +chained_path(points) + Points points + CODE: + chained_path(points, RETVAL); + OUTPUT: + RETVAL + +std::vector +chained_path_from(points, start_from) + Points points + Point* start_from + CODE: + chained_path(points, RETVAL, *start_from); + OUTPUT: + RETVAL + %} diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 837c3eede..dcd0293f8 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -1,3 +1,5 @@ +std::vector T_STD_VECTOR_INT + ZTable* O_OBJECT TriangleMesh* O_OBJECT Point* O_OBJECT