Ported chained_path() to XS

This commit is contained in:
Alessandro Ranellucci 2013-11-23 21:39:05 +01:00
parent 4d5d003ba7
commit 0516aac715
9 changed files with 74 additions and 31 deletions

View file

@ -195,7 +195,7 @@ sub make_fill {
} }
# organize infill paths using a nearest-neighbor search # organize infill paths using a nearest-neighbor search
@fills = @fills[ chained_path(\@fills_ordering_points) ]; @fills = @fills[ @{chained_path(\@fills_ordering_points)} ];
return @fills; return @fills;
} }

View file

@ -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 # 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 # 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 # one is the value to be returned in output (if the second item
@ -594,13 +572,15 @@ sub chained_path {
sub chained_path_items { sub chained_path_items {
my ($items, $start_near) = @_; 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] ]; return [ map $_->[1], @$items[@indices] ];
} }
sub chained_path_points { sub chained_path_points {
my ($points, $start_near) = @_; my ($points, $start_near) = @_;
return [ @$points[ chained_path($points, $start_near) ] ]; return [ @$points[ @{chained_path_from($points, $start_near)} ] ];
} }
sub douglas_peucker { sub douglas_peucker {

View file

@ -862,7 +862,7 @@ sub write_gcode {
} }
} else { } else {
# order objects using a nearest neighbor search # 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 # sort layers by Z
my %layers = (); # print_z => [ [layers], [layers], [layers] ] by obj_idx my %layers = (); # print_z => [ [layers], [layers], [layers] ] by obj_idx

View file

@ -1,5 +1,6 @@
#include "Geometry.hpp" #include "Geometry.hpp"
#include <algorithm> #include <algorithm>
#include <map>
namespace Slic3r { namespace Slic3r {
@ -50,4 +51,33 @@ convex_hull(Points points, Polygon &hull)
free(out_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<Points::size_type> &retval, Point start_near)
{
PointPtrs my_points;
std::map<Point*,Points::size_type> 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<Points::size_type> &retval)
{
if (points.empty()) return; // can't call front() on empty vector
chained_path(points, retval, points.front());
}
} }

View file

@ -6,6 +6,8 @@
namespace Slic3r { namespace Slic3r {
void convex_hull(Points points, Polygon &hull); void convex_hull(Points points, Polygon &hull);
void chained_path(Points &points, std::vector<Points::size_type> &retval, Point start_near);
void chained_path(Points &points, std::vector<Points::size_type> &retval);
} }

View file

@ -40,20 +40,30 @@ Point::coincides_with(const Point &point) const
} }
int 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; int idx = -1;
double distance = -1; // double because long is limited to 2147483647 on some platforms and it's not enough 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 /* If the X distance of the candidate is > than the total distance of the
best previous candidate, we know we don't want it */ 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 (distance != -1 && d > distance) continue;
/* If the Y distance of the candidate is > than the total distance of the /* If the Y distance of the candidate is > than the total distance of the
best previous candidate, we know we don't want it */ 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; if (distance != -1 && d > distance) continue;
idx = it - points.begin(); idx = it - points.begin();

View file

@ -10,6 +10,7 @@ namespace Slic3r {
class Line; class Line;
class Point; class Point;
typedef std::vector<Point> Points; typedef std::vector<Point> Points;
typedef std::vector<Point*> PointPtrs;
class Point class Point
{ {
@ -22,7 +23,8 @@ class Point
void rotate(double angle, Point* center); void rotate(double angle, Point* center);
bool coincides_with(const Point &point) const; bool coincides_with(const Point &point) const;
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; Point* nearest_point(Points points) const;
double distance_to(const Point* point) const; double distance_to(const Point* point) const;
double distance_to(const Line* line) const; double distance_to(const Line* line) const;

View file

@ -20,4 +20,21 @@ convex_hull(points)
OUTPUT: OUTPUT:
RETVAL RETVAL
std::vector<Points::size_type>
chained_path(points)
Points points
CODE:
chained_path(points, RETVAL);
OUTPUT:
RETVAL
std::vector<Points::size_type>
chained_path_from(points, start_from)
Points points
Point* start_from
CODE:
chained_path(points, RETVAL, *start_from);
OUTPUT:
RETVAL
%} %}

View file

@ -1,3 +1,5 @@
std::vector<Points::size_type> T_STD_VECTOR_INT
ZTable* O_OBJECT ZTable* O_OBJECT
TriangleMesh* O_OBJECT TriangleMesh* O_OBJECT
Point* O_OBJECT Point* O_OBJECT