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 <math.h>
+
 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<unsigned int>*};
 %typemap{SV*};
 %typemap{AV*};
+%typemap{Point*};
\ No newline at end of file