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
@fills = @fills[ chained_path(\@fills_ordering_points) ];
@fills = @fills[ @{chained_path(\@fills_ordering_points)} ];
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
# 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 {

View file

@ -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

View file

@ -1,5 +1,6 @@
#include "Geometry.hpp"
#include <algorithm>
#include <map>
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<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 {
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
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();

View file

@ -10,6 +10,7 @@ namespace Slic3r {
class Line;
class Point;
typedef std::vector<Point> Points;
typedef std::vector<Point*> 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;

View file

@ -20,4 +20,21 @@ convex_hull(points)
OUTPUT:
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
TriangleMesh* O_OBJECT
Point* O_OBJECT