diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index e7abac998..19b3a90b6 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -329,10 +329,7 @@ sub scale { sub rotate { my $self = shift; - my ($angle, $center) = @_; - - $center = Slic3r::Point::XS->new(@$center) if ref($center) ne 'Slic3r::Point::XS'; - $_->rotate($angle, $center) for @{$self->expolygons}; + $_->rotate(@_) for @{$self->expolygons}; $self; } diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 70f6f2860..b5c809f5a 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -17,4 +17,13 @@ use overload sub clone { (ref $_[0])->_clone($_[0]) } +# to handle legacy code +sub rotate { + my $self = shift; + my ($angle, $center) = @_; + + $center = Slic3r::Point::XS->new(@$center) if ref($center) ne 'Slic3r::Point::XS'; + $self->_rotate($angle, $center); +} + 1; diff --git a/xs/src/ExPolygon.hpp b/xs/src/ExPolygon.hpp index c08b322c9..c8ebcd84f 100644 --- a/xs/src/ExPolygon.hpp +++ b/xs/src/ExPolygon.hpp @@ -21,6 +21,7 @@ class ExPolygon SV* arrayref(); void scale(double factor); void translate(double x, double y); + void _rotate(double angle, Point* center); }; #define scale_polygon(poly, factor) \ @@ -35,6 +36,14 @@ class ExPolygon (*pit).y += y; \ } +inline void +rotate_polygon(Polygon* poly, double angle, Point* center) +{ + for (Polygon::iterator pit = (*poly).begin(); pit != (*poly).end(); ++pit) { \ + (*pit).rotate(angle, center); + } +} + void ExPolygon::scale(double factor) { @@ -53,6 +62,15 @@ ExPolygon::translate(double x, double y) } } +void +ExPolygon::_rotate(double angle, Point* center) +{ + rotate_polygon(&contour, angle, center); + for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) { + rotate_polygon(&*it, angle, center); + } +} + void perl2polygon(SV* poly_sv, Polygon& poly) { diff --git a/xs/src/Point.hpp b/xs/src/Point.hpp index 2b22fa6b4..4b14b9115 100644 --- a/xs/src/Point.hpp +++ b/xs/src/Point.hpp @@ -8,14 +8,26 @@ extern "C" { #include "ppport.h" } +#include + class Point { public: unsigned long x; unsigned long y; Point(unsigned long _x = 0, unsigned long _y = 0): x(_x), y(_y) {}; + void rotate(double angle, Point* center); }; +void +Point::rotate(double angle, Point* center) +{ + double cur_x = (double)x; + double cur_y = (double)y; + x = (unsigned long)( (double)center->x + cos(angle) * (cur_x - (double)center->x) - sin(angle) * (cur_y - (double)center->y) ); + y = (unsigned long)( (double)center->y + cos(angle) * (cur_y - (double)center->y) + sin(angle) * (cur_x - (double)center->x) ); +} + SV* point2perl(Point& point) { AV* av = newAV(); diff --git a/xs/t/04_expolygon.t b/xs/t/04_expolygon.t index 476942c77..0f2116c1f 100644 --- a/xs/t/04_expolygon.t +++ b/xs/t/04_expolygon.t @@ -4,7 +4,9 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 7; +use Test::More tests => 9; + +use constant PI => 4 * atan2(1, 1); my $square = [ # ccw [100, 100], @@ -26,21 +28,47 @@ isa_ok $expolygon->arrayref, 'Slic3r::ExPolygon', 'Perl expolygon is blessed'; isa_ok $expolygon->[0], 'Slic3r::Polygon', 'Perl polygons are blessed'; isa_ok $expolygon->[0][0], 'Slic3r::Point', 'Perl polygon points are blessed'; -my $clone = $expolygon->clone; -is_deeply [ @$clone ], [$square, $hole_in_square], 'clone'; -# TODO: check that modifying the clone doesn't modify the original one +{ + my $clone = $expolygon->clone; + is_deeply [ @$clone ], [$square, $hole_in_square], 'clone'; + # The following tests implicitely check that modifying clones + # does not modify the original one. +} -$expolygon->scale(2.5); -is_deeply [ @$expolygon ], [ - [map [ 2.5*$_->[0], 2.5*$_->[1] ], @$square], - [map [ 2.5*$_->[0], 2.5*$_->[1] ], @$hole_in_square] - ], 'scale'; +{ + my $expolygon2 = $expolygon->clone; + $expolygon2->scale(2.5); + is_deeply [ @$expolygon2 ], [ + [map [ 2.5*$_->[0], 2.5*$_->[1] ], @$square], + [map [ 2.5*$_->[0], 2.5*$_->[1] ], @$hole_in_square] + ], 'scale'; +} -$expolygon->scale(1/2.5); -$expolygon->translate(10, -5); -is_deeply [ @$expolygon ], [ - [map [ $_->[0]+10, $_->[1]-5 ], @$square], - [map [ $_->[0]+10, $_->[1]-5 ], @$hole_in_square] - ], 'translate'; +{ + my $expolygon2 = $expolygon->clone; + $expolygon2->translate(10, -5); + is_deeply [ @$expolygon2 ], [ + [map [ $_->[0]+10, $_->[1]-5 ], @$square], + [map [ $_->[0]+10, $_->[1]-5 ], @$hole_in_square] + ], 'translate'; +} + +{ + my $expolygon2 = $expolygon->clone; + $expolygon2->rotate(PI/2, Slic3r::Point::XS->new(150,150)); + is_deeply [ @$expolygon2 ], [ + [ @$square[1,2,3,0] ], + [ @$hole_in_square[3,0,1,2] ] + ], 'rotate around Point::XS'; +} + +{ + my $expolygon2 = $expolygon->clone; + $expolygon2->rotate(PI/2, [150,150]); + is_deeply [ @$expolygon2 ], [ + [ @$square[1,2,3,0] ], + [ @$hole_in_square[3,0,1,2] ] + ], 'rotate around pure-Perl Point'; +} __END__ diff --git a/xs/xsp/ExPolygon.xsp b/xs/xsp/ExPolygon.xsp index 0af2dc6e4..be8d4aa61 100644 --- a/xs/xsp/ExPolygon.xsp +++ b/xs/xsp/ExPolygon.xsp @@ -9,6 +9,8 @@ %name{_clone} ExPolygon(ExPolygon& self); ~ExPolygon(); void scale(double factor); + void translate(double x, double y); + void _rotate(double angle, Point* center); %{ ExPolygon* diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index fd018878b..b41df45dc 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -2,3 +2,4 @@ %typemap{std::vector*}; %typemap{SV*}; %typemap{AV*}; +%typemap{Point*}; \ No newline at end of file