diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm
index 27aa1a59b..6adb650c2 100644
--- a/lib/Slic3r/ExPolygon.pm
+++ b/lib/Slic3r/ExPolygon.pm
@@ -7,18 +7,6 @@ use warnings;
 use List::Util qw(first);
 use Slic3r::Geometry::Clipper qw(union_ex diff_pl);
 
-sub wkt {
-    my $self = shift;
-    return sprintf "POLYGON(%s)", 
-        join ',', map "($_)", map { join ',', map "$_->[0] $_->[1]", @$_ } @$self;
-}
-
-sub dump_perl {
-    my $self = shift;
-    return sprintf "[%s]", 
-        join ',', map "[$_]", map { join ',', map "[$_->[0],$_->[1]]", @$_ } @$self;
-}
-
 sub offset {
     my $self = shift;
     return Slic3r::Geometry::Clipper::offset(\@$self, @_);
diff --git a/lib/Slic3r/GUI/2DBed.pm b/lib/Slic3r/GUI/2DBed.pm
index ebbc70b6b..0891a4836 100644
--- a/lib/Slic3r/GUI/2DBed.pm
+++ b/lib/Slic3r/GUI/2DBed.pm
@@ -1,4 +1,5 @@
 # Bed shape dialog
+# still used by the Slic3r::GUI::Controller::ManualControlDialog Perl module.
 
 package Slic3r::GUI::2DBed;
 use strict;
diff --git a/lib/Slic3r/Point.pm b/lib/Slic3r/Point.pm
index 535a97194..1134138ea 100644
--- a/lib/Slic3r/Point.pm
+++ b/lib/Slic3r/Point.pm
@@ -7,11 +7,6 @@ sub new_scale {
     return $class->new(map Slic3r::Geometry::scale($_), @_);
 }
 
-sub dump_perl {
-    my $self = shift;
-    return sprintf "[%s,%s]", @$self;
-}
-
 package Slic3r::Pointf;
 use strict;
 use warnings;
diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm
index 9cc142409..a42b5d1c4 100644
--- a/lib/Slic3r/Polyline.pm
+++ b/lib/Slic3r/Polyline.pm
@@ -10,9 +10,4 @@ sub new_scale {
     return $class->new(map [ Slic3r::Geometry::scale($_->[X]), Slic3r::Geometry::scale($_->[Y]) ], @points);
 }
 
-sub dump_perl {
-    my $self = shift;
-    return sprintf "[%s]", join ',', map "[$_->[0],$_->[1]]", @$self;
-}
-
 1;
diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm
index a4847fb45..391b06dac 100644
--- a/xs/lib/Slic3r/XS.pm
+++ b/xs/lib/Slic3r/XS.pm
@@ -33,16 +33,6 @@ use overload
     '@{}' => sub { $_[0]->arrayref },
     'fallback' => 1;
 
-package Slic3r::Point3;
-use overload
-    '@{}' => sub { [ $_[0]->x, $_[0]->y, $_[0]->z ] },  #,
-    'fallback' => 1;
-
-sub pp {
-    my ($self) = @_;
-    return [ @$self ];
-}
-
 package Slic3r::Pointf;
 use overload
     '@{}' => sub { $_[0]->arrayref },
diff --git a/xs/src/admesh/connect.cpp b/xs/src/admesh/connect.cpp
index e9129d007..da5b66720 100644
--- a/xs/src/admesh/connect.cpp
+++ b/xs/src/admesh/connect.cpp
@@ -25,11 +25,11 @@
 #include <string.h>
 #include <math.h>
 
+#include <boost/detail/endian.hpp>
+
 #include "stl.h"
 
 
-static void stl_match_neighbors_exact(stl_file *stl,
-                                      stl_hash_edge *edge_a, stl_hash_edge *edge_b);
 static void stl_match_neighbors_nearby(stl_file *stl,
                                        stl_hash_edge *edge_a, stl_hash_edge *edge_b);
 static void stl_record_neighbors(stl_file *stl,
@@ -43,7 +43,6 @@ static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge,
 static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
                              void (*match_neighbors)(stl_file *stl,
                                  stl_hash_edge *edge_a, stl_hash_edge *edge_b));
-static int stl_get_hash_for_edge(int M, stl_hash_edge *edge);
 static int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b);
 static void stl_free_edges(stl_file *stl);
 static void stl_remove_facet(stl_file *stl, int facet_number);
@@ -82,37 +81,20 @@ stl_check_facets_exact(stl_file *stl) {
 
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     facet = stl->facet_start[i];
-    // Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
-    // When using a memcmp on raw floats, those numbers report to be different.
-    // Unify all +0 and -0 to +0 to make the floats equal under memcmp.
-    {
-      uint32_t *f = (uint32_t*)&facet;
-      for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
-        if (*f == 0x80000000)
-            // Negative zero, switch to positive zero.
-            *f = 0;
-    }
-
-    /* If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. */
-    if(   !memcmp(&facet.vertex[0], &facet.vertex[1],
-                  sizeof(stl_vertex))
-          || !memcmp(&facet.vertex[1], &facet.vertex[2],
-                     sizeof(stl_vertex))
-          || !memcmp(&facet.vertex[0], &facet.vertex[2],
-                     sizeof(stl_vertex))) {
+    // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
+    if (facet.vertex[0] == facet.vertex[1] ||
+        facet.vertex[1] == facet.vertex[2] ||
+        facet.vertex[0] == facet.vertex[2]) {
       stl->stats.degenerate_facets += 1;
       stl_remove_facet(stl, i);
-      i--;
+      -- i;
       continue;
-
     }
     for(j = 0; j < 3; j++) {
       edge.facet_number = i;
       edge.which_edge = j;
-      stl_load_edge_exact(stl, &edge, &facet.vertex[j],
-                          &facet.vertex[(j + 1) % 3]);
-
-      insert_hash_edge(stl, edge, stl_match_neighbors_exact);
+      stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
+      insert_hash_edge(stl, edge, stl_record_neighbors);
     }
   }
   stl_free_edges(stl);
@@ -131,28 +113,33 @@ stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge,
   if (stl->error) return;
 
   {
-    float diff_x = ABS(a->x - b->x);
-    float diff_y = ABS(a->y - b->y);
-    float diff_z = ABS(a->z - b->z);
-    float max_diff = STL_MAX(diff_x, diff_y);
-    max_diff = STL_MAX(diff_z, max_diff);
-    stl->stats.shortest_edge = STL_MIN(max_diff, stl->stats.shortest_edge);
+    stl_vertex diff = (*a - *b).cwiseAbs();
+    float max_diff = std::max(diff(0), std::max(diff(1), diff(2)));
+    stl->stats.shortest_edge = std::min(max_diff, stl->stats.shortest_edge);
   }
 
   // Ensure identical vertex ordering of equal edges.
   // This method is numerically robust.
-  if ((a->x != b->x) ? 
-        (a->x < b->x) : 
-        ((a->y != b->y) ? 
-            (a->y < b->y) : 
-            (a->z < b->z))) {
-    memcpy(&edge->key[0], a, sizeof(stl_vertex));
-    memcpy(&edge->key[3], b, sizeof(stl_vertex));
+  if (stl_vertex_lower(*a, *b)) {
   } else {
-    memcpy(&edge->key[0], b, sizeof(stl_vertex));
-    memcpy(&edge->key[3], a, sizeof(stl_vertex));
+    std::swap(a, b);
     edge->which_edge += 3; /* this edge is loaded backwards */
   }
+  memcpy(&edge->key[0],                  a->data(), sizeof(stl_vertex));
+  memcpy(&edge->key[sizeof(stl_vertex)], b->data(), sizeof(stl_vertex));
+  // Switch negative zeros to positive zeros, so memcmp will consider them to be equal.
+  for (size_t i = 0; i < 6; ++ i) {
+    unsigned char *p = edge->key + i * 4;
+#ifdef BOOST_LITTLE_ENDIAN
+    if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80)
+      // Negative zero, switch to positive zero.
+      p[3] = 0;
+#else /* BOOST_LITTLE_ENDIAN */
+    if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0)
+      // Negative zero, switch to positive zero.
+      p[0] = 0;
+#endif /* BOOST_LITTLE_ENDIAN */
+  }
 }
 
 static void
@@ -188,21 +175,17 @@ stl_initialize_facet_check_exact(stl_file *stl) {
   }
 }
 
-static void
-insert_hash_edge(stl_file *stl, stl_hash_edge edge,
+static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
                  void (*match_neighbors)(stl_file *stl,
-                     stl_hash_edge *edge_a, stl_hash_edge *edge_b)) {
-  stl_hash_edge *link;
-  stl_hash_edge *new_edge;
-  stl_hash_edge *temp;
-  int            chain_number;
-
+                     stl_hash_edge *edge_a, stl_hash_edge *edge_b))
+{
   if (stl->error) return;
 
-  chain_number = stl_get_hash_for_edge(stl->M, &edge);
-
-  link = stl->heads[chain_number];
+  int            chain_number = edge.hash(stl->M);
+  stl_hash_edge *link = stl->heads[chain_number];
 
+  stl_hash_edge *new_edge;
+  stl_hash_edge *temp;
   if(link == stl->tail) {
     /* This list doesn't have any edges currently in it.  Add this one. */
     new_edge = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
@@ -252,30 +235,17 @@ insert_hash_edge(stl_file *stl, stl_hash_edge edge,
   }
 }
 
-
-static int
-stl_get_hash_for_edge(int M, stl_hash_edge *edge) {
-  return ((edge->key[0] / 23 + edge->key[1] / 19 + edge->key[2] / 17
-           + edge->key[3] /13  + edge->key[4] / 11 + edge->key[5] / 7 ) % M);
+// Return 1 if the edges are not matched.
+static inline int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b)
+{
+    // Don't match edges of the same facet
+    return (edge_a->facet_number == edge_b->facet_number) || (*edge_a != *edge_b);
 }
 
-static int
-stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b) {
-  if(edge_a->facet_number == edge_b->facet_number) {
-    return 1;			/* Don't match edges of the same facet */
-  } else {
-    return memcmp(edge_a, edge_b, SIZEOF_EDGE_SORT);
-  }
-}
-
-void
-stl_check_facets_nearby(stl_file *stl, float tolerance) {
-  stl_hash_edge  edge[3];
-  stl_facet      facet;
-  int            i;
-  int            j;
-
-  if (stl->error) return;
+void stl_check_facets_nearby(stl_file *stl, float tolerance)
+{
+  if (stl->error)
+    return;
 
   if(   (stl->stats.connected_facets_1_edge == stl->stats.number_of_facets)
         && (stl->stats.connected_facets_2_edge == stl->stats.number_of_facets)
@@ -286,27 +256,19 @@ stl_check_facets_nearby(stl_file *stl, float tolerance) {
 
   stl_initialize_facet_check_nearby(stl);
 
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    facet = stl->facet_start[i];
-    // Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
-    // When using a memcmp on raw floats, those numbers report to be different.
-    // Unify all +0 and -0 to +0 to make the floats equal under memcmp.
-    {
-      uint32_t *f = (uint32_t*)&facet;
-      for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
-        if (*f == 0x80000000)
-            // Negative zero, switch to positive zero.
-            *f = 0;
-    }
-    for(j = 0; j < 3; j++) {
+  for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
+    //FIXME is the copy necessary?
+    stl_facet facet = stl->facet_start[i];
+    for (int j = 0; j < 3; j++) {
       if(stl->neighbors_start[i].neighbor[j] == -1) {
-        edge[j].facet_number = i;
-        edge[j].which_edge = j;
-        if(stl_load_edge_nearby(stl, &edge[j], &facet.vertex[j],
+        stl_hash_edge edge;
+        edge.facet_number = i;
+        edge.which_edge = j;
+        if(stl_load_edge_nearby(stl, &edge, &facet.vertex[j],
                                 &facet.vertex[(j + 1) % 3],
                                 tolerance)) {
           /* only insert edges that have different keys */
-          insert_hash_edge(stl, edge[j], stl_match_neighbors_nearby);
+          insert_hash_edge(stl, edge, stl_match_neighbors_nearby);
         }
       }
     }
@@ -315,27 +277,17 @@ stl_check_facets_nearby(stl_file *stl, float tolerance) {
   stl_free_edges(stl);
 }
 
-static int
-stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge,
-                     stl_vertex *a, stl_vertex *b, float tolerance) {
+static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, stl_vertex *a, stl_vertex *b, float tolerance)
+{
   // Index of a grid cell spaced by tolerance.
-  uint32_t vertex1[3] = {
-    (uint32_t)((a->x - stl->stats.min.x) / tolerance),
-    (uint32_t)((a->y - stl->stats.min.y) / tolerance),
-    (uint32_t)((a->z - stl->stats.min.z) / tolerance)
-  };
-  uint32_t vertex2[3] = {
-    (uint32_t)((b->x - stl->stats.min.x) / tolerance),
-    (uint32_t)((b->y - stl->stats.min.y) / tolerance),
-    (uint32_t)((b->z - stl->stats.min.z) / tolerance)
-  };
+  typedef Eigen::Matrix<int32_t,  3, 1, Eigen::DontAlign> Vec3i;
+  Vec3i vertex1 = (*a / tolerance).cast<int32_t>();
+  Vec3i vertex2 = (*b / tolerance).cast<int32_t>();
+  static_assert(sizeof(Vec3i) == 12, "size of Vec3i incorrect");
 
-  if(   (vertex1[0] == vertex2[0])
-        && (vertex1[1] == vertex2[1])
-        && (vertex1[2] == vertex2[2])) {
-    /* Both vertices hash to the same value */
+  if (vertex1 == vertex2)
+    // Both vertices hash to the same value
     return 0;
-  }
 
   // Ensure identical vertex ordering of edges, which vertices land into equal grid cells.
   // This method is numerically robust.
@@ -344,30 +296,27 @@ stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge,
         ((vertex1[1] != vertex2[1]) ? 
             (vertex1[1] < vertex2[1]) : 
             (vertex1[2] < vertex2[2]))) {
-    memcpy(&edge->key[0], vertex1, sizeof(stl_vertex));
-    memcpy(&edge->key[3], vertex2, sizeof(stl_vertex));
+    memcpy(&edge->key[0],                  vertex1.data(), sizeof(stl_vertex));
+    memcpy(&edge->key[sizeof(stl_vertex)], vertex2.data(), sizeof(stl_vertex));
   } else {
-    memcpy(&edge->key[0], vertex2, sizeof(stl_vertex));
-    memcpy(&edge->key[3], vertex1, sizeof(stl_vertex));
+    memcpy(&edge->key[0],                  vertex2.data(), sizeof(stl_vertex));
+    memcpy(&edge->key[sizeof(stl_vertex)], vertex1.data(), sizeof(stl_vertex));
     edge->which_edge += 3; /* this edge is loaded backwards */
   }
   return 1;
 }
 
-static void
-stl_free_edges(stl_file *stl) {
-  int i;
-  stl_hash_edge *temp;
-
-  if (stl->error) return;
+static void stl_free_edges(stl_file *stl)
+{
+  if (stl->error)
+    return;
 
   if(stl->stats.malloced != stl->stats.freed) {
-    for(i = 0; i < stl->M; i++) {
-      for(temp = stl->heads[i]; stl->heads[i] != stl->tail;
-          temp = stl->heads[i]) {
+    for (int i = 0; i < stl->M; i++) {
+      for (stl_hash_edge *temp = stl->heads[i]; stl->heads[i] != stl->tail; temp = stl->heads[i]) {
         stl->heads[i] = stl->heads[i]->next;
         free(temp);
-        stl->stats.freed++;
+        ++ stl->stats.freed;
       }
     }
   }
@@ -375,8 +324,8 @@ stl_free_edges(stl_file *stl) {
   free(stl->tail);
 }
 
-static void
-stl_initialize_facet_check_nearby(stl_file *stl) {
+static void stl_initialize_facet_check_nearby(stl_file *stl)
+{
   int i;
 
   if (stl->error) return;
@@ -467,16 +416,8 @@ stl_record_neighbors(stl_file *stl,
   }
 }
 
-static void
-stl_match_neighbors_exact(stl_file *stl,
-                          stl_hash_edge *edge_a, stl_hash_edge *edge_b) {
-  if (stl->error) return;
-  stl_record_neighbors(stl, edge_a, edge_b);
-}
-
-static void
-stl_match_neighbors_nearby(stl_file *stl,
-                           stl_hash_edge *edge_a, stl_hash_edge *edge_b) {
+static void stl_match_neighbors_nearby(stl_file *stl, stl_hash_edge *edge_a, stl_hash_edge *edge_b)
+{
   int facet1;
   int facet2;
   int vertex1;
@@ -517,9 +458,7 @@ stl_match_neighbors_nearby(stl_file *stl,
 }
 
 
-static void
-stl_change_vertices(stl_file *stl, int facet_num, int vnot,
-                    stl_vertex new_vertex) {
+static void stl_change_vertices(stl_file *stl, int facet_num, int vnot, stl_vertex new_vertex) {
   int first_facet;
   int direction;
   int next_edge;
@@ -551,30 +490,30 @@ stl_change_vertices(stl_file *stl, int facet_num, int vnot,
       }
     }
 #if 0
-    if (stl->facet_start[facet_num].vertex[pivot_vertex].x == new_vertex.x &&
-        stl->facet_start[facet_num].vertex[pivot_vertex].y == new_vertex.y &&
-        stl->facet_start[facet_num].vertex[pivot_vertex].z == new_vertex.z)
+    if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) &&
+        stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) &&
+        stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2))
       printf("Changing vertex %f,%f,%f: Same !!!\r\n", 
-        new_vertex.x, new_vertex.y, new_vertex.z);
+        new_vertex(0), new_vertex(1), new_vertex(2));
     else {
-      if (stl->facet_start[facet_num].vertex[pivot_vertex].x != new_vertex.x)
+      if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0))
         printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", 
-          stl->facet_start[facet_num].vertex[pivot_vertex].x,
-          *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex].x),
-          new_vertex.x,
-          *reinterpret_cast<const int*>(&new_vertex.x));
-      if (stl->facet_start[facet_num].vertex[pivot_vertex].y != new_vertex.y)
+          stl->facet_start[facet_num].vertex[pivot_vertex](0),
+          *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](0)),
+          new_vertex(0),
+          *reinterpret_cast<const int*>(&new_vertex(0)));
+      if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1))
         printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", 
-          stl->facet_start[facet_num].vertex[pivot_vertex].y,
-          *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex].y),
-          new_vertex.y,
-          *reinterpret_cast<const int*>(&new_vertex.y));
-      if (stl->facet_start[facet_num].vertex[pivot_vertex].z != new_vertex.z)
+          stl->facet_start[facet_num].vertex[pivot_vertex](1),
+          *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](1)),
+          new_vertex(1),
+          *reinterpret_cast<const int*>(&new_vertex(1)));
+      if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2))
         printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", 
-          stl->facet_start[facet_num].vertex[pivot_vertex].z,
-          *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex].z),
-          new_vertex.z,
-          *reinterpret_cast<const int*>(&new_vertex.z));
+          stl->facet_start[facet_num].vertex[pivot_vertex](2),
+          *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](2)),
+          new_vertex(2),
+          *reinterpret_cast<const int*>(&new_vertex(2)));
     }
 #endif
     stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex;
@@ -595,7 +534,6 @@ Try using a smaller tolerance or don't do a nearby check\n");
   }
 }
 
-
 static void
 stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
                              stl_hash_edge *edge_b, int *facet1, int *vertex1,
@@ -622,11 +560,10 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
     v1b = (edge_b->which_edge + 1) % 3;
   }
 
-  /* Of the first pair, which vertex, if any, should be changed */
-  if(!memcmp(&stl->facet_start[edge_a->facet_number].vertex[v1a],
-             &stl->facet_start[edge_b->facet_number].vertex[v1b],
-             sizeof(stl_vertex))) {
-    /* These facets are already equal.  No need to change. */
+  // Of the first pair, which vertex, if any, should be changed
+  if(stl->facet_start[edge_a->facet_number].vertex[v1a] == 
+     stl->facet_start[edge_b->facet_number].vertex[v1b]) {
+    // These facets are already equal.  No need to change.
     *facet1 = -1;
   } else {
     if(   (stl->neighbors_start[edge_a->facet_number].neighbor[v1a] == -1)
@@ -644,10 +581,9 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
   }
 
   /* Of the second pair, which vertex, if any, should be changed */
-  if(!memcmp(&stl->facet_start[edge_a->facet_number].vertex[v2a],
-             &stl->facet_start[edge_b->facet_number].vertex[v2b],
-             sizeof(stl_vertex))) {
-    /* These facets are already equal.  No need to change. */
+  if(stl->facet_start[edge_a->facet_number].vertex[v2a] == 
+     stl->facet_start[edge_b->facet_number].vertex[v2b]) {
+    // These facets are already equal.  No need to change.
     *facet2 = -1;
   } else {
     if(   (stl->neighbors_start[edge_a->facet_number].neighbor[v2a] == -1)
@@ -718,40 +654,35 @@ in stl_remove_facet: neighbor = %d numfacets = %d this is wrong\n",
   }
 }
 
-void
-stl_remove_unconnected_facets(stl_file *stl) {
+void stl_remove_unconnected_facets(stl_file *stl)
+{
   /* A couple of things need to be done here.  One is to remove any */
   /* completely unconnected facets (0 edges connected) since these are */
   /* useless and could be completely wrong.   The second thing that needs to */
   /* be done is to remove any degenerate facets that were created during */
   /* stl_check_facets_nearby(). */
+  if (stl->error)
+    return;
 
-  int i;
-
-  if (stl->error) return;
-
-  /* remove degenerate facets */
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    if(   !memcmp(&stl->facet_start[i].vertex[0],
-                  &stl->facet_start[i].vertex[1], sizeof(stl_vertex))
-          || !memcmp(&stl->facet_start[i].vertex[1],
-                     &stl->facet_start[i].vertex[2], sizeof(stl_vertex))
-          || !memcmp(&stl->facet_start[i].vertex[0],
-                     &stl->facet_start[i].vertex[2], sizeof(stl_vertex))) {
+  // remove degenerate facets
+  for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
+    if(stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] ||
+       stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] ||
+       stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) {
       stl_remove_degenerate(stl, i);
       i--;
     }
   }
 
   if(stl->stats.connected_facets_1_edge < stl->stats.number_of_facets) {
-    /* remove completely unconnected facets */
-    for(i = 0; i < stl->stats.number_of_facets; i++) {
-      if(   (stl->neighbors_start[i].neighbor[0] == -1)
-            && (stl->neighbors_start[i].neighbor[1] == -1)
-            && (stl->neighbors_start[i].neighbor[2] == -1)) {
-        /* This facet is completely unconnected.  Remove it. */
+    // remove completely unconnected facets
+    for (int i = 0; i < stl->stats.number_of_facets; i++) {
+      if (stl->neighbors_start[i].neighbor[0] == -1 &&
+          stl->neighbors_start[i].neighbor[1] == -1 &&
+          stl->neighbors_start[i].neighbor[2] == -1) {
+        // This facet is completely unconnected.  Remove it.
         stl_remove_facet(stl, i);
-        i--;
+        -- i;
       }
     }
   }
@@ -771,30 +702,24 @@ stl_remove_degenerate(stl_file *stl, int facet) {
 
   if (stl->error) return;
 
-  if(   !memcmp(&stl->facet_start[facet].vertex[0],
-                &stl->facet_start[facet].vertex[1], sizeof(stl_vertex))
-        && !memcmp(&stl->facet_start[facet].vertex[1],
-                   &stl->facet_start[facet].vertex[2], sizeof(stl_vertex))) {
+  if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1] &&
+      stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
     /* all 3 vertices are equal.  Just remove the facet.  I don't think*/
     /* this is really possible, but just in case... */
     printf("removing a facet in stl_remove_degenerate\n");
-
     stl_remove_facet(stl, facet);
     return;
   }
 
-  if(!memcmp(&stl->facet_start[facet].vertex[0],
-             &stl->facet_start[facet].vertex[1], sizeof(stl_vertex))) {
+  if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) {
     edge1 = 1;
     edge2 = 2;
     edge3 = 0;
-  } else if(!memcmp(&stl->facet_start[facet].vertex[1],
-                    &stl->facet_start[facet].vertex[2], sizeof(stl_vertex))) {
+  } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
     edge1 = 0;
     edge2 = 2;
     edge3 = 1;
-  } else if(!memcmp(&stl->facet_start[facet].vertex[2],
-                    &stl->facet_start[facet].vertex[0], sizeof(stl_vertex))) {
+  } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) {
     edge1 = 0;
     edge2 = 1;
     edge3 = 2;
@@ -883,7 +808,7 @@ stl_fill_holes(stl_file *stl) {
       stl_load_edge_exact(stl, &edge, &facet.vertex[j],
                           &facet.vertex[(j + 1) % 3]);
 
-      insert_hash_edge(stl, edge, stl_match_neighbors_exact);
+      insert_hash_edge(stl, edge, stl_record_neighbors);
     }
   }
 
@@ -939,7 +864,7 @@ stl_fill_holes(stl_file *stl) {
             stl_load_edge_exact(stl, &edge, &new_facet.vertex[k],
                                 &new_facet.vertex[(k + 1) % 3]);
 
-            insert_hash_edge(stl, edge, stl_match_neighbors_exact);
+            insert_hash_edge(stl, edge, stl_record_neighbors);
           }
           break;
         } else {
@@ -977,9 +902,7 @@ stl_add_facet(stl_file *stl, stl_facet *new_facet) {
   stl->facet_start[stl->stats.number_of_facets] = *new_facet;
 
   /* note that the normal vector is not set here, just initialized to 0 */
-  stl->facet_start[stl->stats.number_of_facets].normal.x = 0.0;
-  stl->facet_start[stl->stats.number_of_facets].normal.y = 0.0;
-  stl->facet_start[stl->stats.number_of_facets].normal.z = 0.0;
+  stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero();
 
   stl->neighbors_start[stl->stats.number_of_facets].neighbor[0] = -1;
   stl->neighbors_start[stl->stats.number_of_facets].neighbor[1] = -1;
diff --git a/xs/src/admesh/normals.cpp b/xs/src/admesh/normals.cpp
index b7cf9a8ab..a8faa44bd 100644
--- a/xs/src/admesh/normals.cpp
+++ b/xs/src/admesh/normals.cpp
@@ -27,12 +27,6 @@
 
 #include "stl.h"
 
-static void stl_reverse_vector(float v[]) {
-  v[0] *= -1;
-  v[1] *= -1;
-  v[2] *= -1;
-}
-
 static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag);
 
 static void
@@ -228,102 +222,52 @@ static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_
   /* Returns 2 if the normal is not within tolerance and backwards */
   /* Returns 4 if the status is unknown. */
 
-  float normal[3];
-  float test_norm[3];
   stl_facet *facet;
 
   facet = &stl->facet_start[facet_num];
 
+  stl_normal normal;
   stl_calculate_normal(normal, facet);
   stl_normalize_vector(normal);
+  stl_normal normal_dif = (normal - facet->normal).cwiseAbs();
 
-  if(   (ABS(normal[0] - facet->normal.x) < 0.001)
-        && (ABS(normal[1] - facet->normal.y) < 0.001)
-        && (ABS(normal[2] - facet->normal.z) < 0.001)) {
+  const float eps = 0.001f;
+  if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
     /* It is not really necessary to change the values here */
     /* but just for consistency, I will. */
-    facet->normal.x = normal[0];
-    facet->normal.y = normal[1];
-    facet->normal.z = normal[2];
+    facet->normal = normal;
     return 0;
   }
 
-  test_norm[0] = facet->normal.x;
-  test_norm[1] = facet->normal.y;
-  test_norm[2] = facet->normal.z;
-
+  stl_normal test_norm = facet->normal;
   stl_normalize_vector(test_norm);
-  if(   (ABS(normal[0] - test_norm[0]) < 0.001)
-        && (ABS(normal[1] - test_norm[1]) < 0.001)
-        && (ABS(normal[2] - test_norm[2]) < 0.001)) {
+  normal_dif = (normal - test_norm).cwiseAbs();
+  if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
     if(normal_fix_flag) {
-      facet->normal.x = normal[0];
-      facet->normal.y = normal[1];
-      facet->normal.z = normal[2];
+      facet->normal = normal;
       stl->stats.normals_fixed += 1;
     }
     return 1;
   }
 
-  stl_reverse_vector(test_norm);
-  if(   (ABS(normal[0] - test_norm[0]) < 0.001)
-        && (ABS(normal[1] - test_norm[1]) < 0.001)
-        && (ABS(normal[2] - test_norm[2]) < 0.001)) {
-    /* Facet is backwards. */
+  test_norm *= -1.f;
+  normal_dif = (normal - test_norm).cwiseAbs();
+  if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
+    // Facet is backwards.
     if(normal_fix_flag) {
-      facet->normal.x = normal[0];
-      facet->normal.y = normal[1];
-      facet->normal.z = normal[2];
+      facet->normal = normal;
       stl->stats.normals_fixed += 1;
     }
     return 2;
   }
   if(normal_fix_flag) {
-    facet->normal.x = normal[0];
-    facet->normal.y = normal[1];
-    facet->normal.z = normal[2];
+    facet->normal = normal;
     stl->stats.normals_fixed += 1;
   }
   return 4;
 }
 
-void stl_calculate_normal(float normal[], stl_facet *facet) {
-  float v1[3] = {
-    facet->vertex[1].x - facet->vertex[0].x,
-    facet->vertex[1].y - facet->vertex[0].y,
-    facet->vertex[1].z - facet->vertex[0].z
-  };
-  float v2[3] = {
-    facet->vertex[2].x - facet->vertex[0].x,
-    facet->vertex[2].y - facet->vertex[0].y,
-    facet->vertex[2].z - facet->vertex[0].z
-  };
-  normal[0] = (float)((double)v1[1] * (double)v2[2]) - ((double)v1[2] * (double)v2[1]);
-  normal[1] = (float)((double)v1[2] * (double)v2[0]) - ((double)v1[0] * (double)v2[2]);
-  normal[2] = (float)((double)v1[0] * (double)v2[1]) - ((double)v1[1] * (double)v2[0]);
-}
-
-void stl_normalize_vector(float v[]) {
-  double length;
-  double factor;
-  float min_normal_length;
-
-  length = sqrt((double)v[0] * (double)v[0] + (double)v[1] * (double)v[1] + (double)v[2] * (double)v[2]);
-  min_normal_length = 0.000000000001;
-  if(length < min_normal_length) {
-    v[0] = 0.0;
-    v[1] = 0.0;
-    v[2] = 0.0;
-    return;
-  }
-  factor = 1.0 / length;
-  v[0] *= factor;
-  v[1] *= factor;
-  v[2] *= factor;
-}
-
-void
-stl_fix_normal_values(stl_file *stl) {
+void stl_fix_normal_values(stl_file *stl) {
   int i;
 
   if (stl->error) return;
@@ -333,20 +277,16 @@ stl_fix_normal_values(stl_file *stl) {
   }
 }
 
-void
-stl_reverse_all_facets(stl_file *stl) {
-  int i;
-  float normal[3];
+void stl_reverse_all_facets(stl_file *stl)
+{
+  if (stl->error)
+  	return;
 
-  if (stl->error) return;
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
+  stl_normal normal;
+  for(int i = 0; i < stl->stats.number_of_facets; i++) {
     stl_reverse_facet(stl, i);
     stl_calculate_normal(normal, &stl->facet_start[i]);
     stl_normalize_vector(normal);
-    stl->facet_start[i].normal.x = normal[0];
-    stl->facet_start[i].normal.y = normal[1];
-    stl->facet_start[i].normal.z = normal[2];
+    stl->facet_start[i].normal = normal;
   }
 }
-
diff --git a/xs/src/admesh/shared.cpp b/xs/src/admesh/shared.cpp
index 8080f3574..91bb82e00 100644
--- a/xs/src/admesh/shared.cpp
+++ b/xs/src/admesh/shared.cpp
@@ -169,7 +169,7 @@ stl_write_off(stl_file *stl, char *file) {
 
   for(i = 0; i < stl->stats.shared_vertices; i++) {
     fprintf(fp, "\t%f %f %f\n",
-            stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z);
+            stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
   }
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0],
@@ -216,10 +216,10 @@ stl_write_vrml(stl_file *stl, char *file) {
 
   for(i = 0; i < (stl->stats.shared_vertices - 1); i++) {
     fprintf(fp, "\t\t\t\t%f %f %f,\n",
-            stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z);
+            stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
   }
   fprintf(fp, "\t\t\t\t%f %f %f]\n",
-          stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z);
+          stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
   fprintf(fp, "\t\t}\n");
   fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
   fprintf(fp, "\t\t\tcoordIndex [\n");
@@ -254,7 +254,7 @@ void stl_write_obj (stl_file *stl, char *file) {
   }
 
   for (i = 0; i < stl->stats.shared_vertices; i++) {
-    fprintf(fp, "v %f %f %f\n", stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z);
+    fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
   }
   for (i = 0; i < stl->stats.number_of_facets; i++) {
     fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
diff --git a/xs/src/admesh/stl.h b/xs/src/admesh/stl.h
index dc0f7ae19..5f7a3c5c1 100644
--- a/xs/src/admesh/stl.h
+++ b/xs/src/admesh/stl.h
@@ -27,9 +27,7 @@
 #include <stdint.h>
 #include <stddef.h>
 
-#define STL_MAX(A,B) ((A)>(B)? (A):(B))
-#define STL_MIN(A,B) ((A)<(B)? (A):(B))
-#define ABS(X)  ((X) < 0 ? -(X) : (X))
+#include <Eigen/Geometry> 
 
 // Size of the binary STL header, free form.
 #define LABEL_SIZE             80
@@ -39,31 +37,16 @@
 #define HEADER_SIZE            84
 #define STL_MIN_FILE_SIZE      284
 #define ASCII_LINES_PER_FACET  7
-// Comparing an edge by memcmp, 2x3x4 bytes = 24
-#define SIZEOF_EDGE_SORT       24
-
-typedef struct {
-  float x;
-  float y;
-  float z;
-} stl_vertex;
 
+typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_vertex;
+typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_normal;
 static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
-
-typedef struct {
-  float x;
-  float y;
-  float z;
-} stl_normal;
-
 static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
 
-typedef char stl_extra[2];
-
 typedef struct {
   stl_normal normal;
   stl_vertex vertex[3];
-  stl_extra  extra;
+  char       extra[2];
 } stl_facet;
 #define SIZEOF_STL_FACET       50
 
@@ -81,8 +64,12 @@ typedef struct {
 } stl_edge;
 
 typedef struct stl_hash_edge {
-  // Key of a hash edge: 2x binary copy of a floating point vertex.
-  uint32_t       key[6];
+  // Key of a hash edge: sorted vertices of the edge.
+  unsigned char key[2 * sizeof(stl_vertex)];
+  // Compare two keys.
+  bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; }
+  bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); }
+  int  hash(int M) const { return ((key[0] / 23 + key[1] / 19 + key[2] / 17 + key[3] /13  + key[4] / 11 + key[5] / 7 ) % M); }
   // Index of a facet owning this edge.
   int            facet_number;
   // Index of this edge inside the facet with an index of facet_number.
@@ -91,8 +78,6 @@ typedef struct stl_hash_edge {
   struct stl_hash_edge  *next;
 } stl_hash_edge;
 
-static_assert(offsetof(stl_hash_edge, facet_number) == SIZEOF_EDGE_SORT, "size of stl_hash_edge.key incorrect");
-
 typedef struct {
   // Index of a neighbor facet.
   int   neighbor[3];
@@ -179,8 +164,8 @@ extern void stl_fix_normal_values(stl_file *stl);
 extern void stl_reverse_all_facets(stl_file *stl);
 extern void stl_translate(stl_file *stl, float x, float y, float z);
 extern void stl_translate_relative(stl_file *stl, float x, float y, float z);
-extern void stl_scale_versor(stl_file *stl, float versor[3]);
-extern void stl_scale(stl_file *stl, float factor);
+extern void stl_scale_versor(stl_file *stl, const stl_vertex &versor);
+inline void stl_scale(stl_file *stl, float factor) { stl_scale_versor(stl, stl_vertex(factor, factor, factor)); }
 extern void stl_rotate_x(stl_file *stl, float angle);
 extern void stl_rotate_y(stl_file *stl, float angle);
 extern void stl_rotate_z(stl_file *stl, float angle);
@@ -195,8 +180,20 @@ extern void stl_write_obj(stl_file *stl, char *file);
 extern void stl_write_off(stl_file *stl, char *file);
 extern void stl_write_dxf(stl_file *stl, char *file, char *label);
 extern void stl_write_vrml(stl_file *stl, char *file);
-extern void stl_calculate_normal(float normal[], stl_facet *facet);
-extern void stl_normalize_vector(float v[]);
+inline void stl_calculate_normal(stl_normal &normal, stl_facet *facet) {
+  normal = (facet->vertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]);
+}
+inline void stl_normalize_vector(stl_normal &normal) {
+  double length = normal.cast<double>().norm();
+  if (length < 0.000000000001)
+    normal = stl_normal::Zero();
+  else
+    normal *= (1.0 / length);
+}
+inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) {
+  return (a(0) != b(0)) ? (a(0) < b(0)) :
+        ((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2)));
+}
 extern void stl_calculate_volume(stl_file *stl);
 
 extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag);
@@ -204,8 +201,8 @@ extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int toler
 extern void stl_initialize(stl_file *stl);
 extern void stl_count_facets(stl_file *stl, const char *file);
 extern void stl_allocate(stl_file *stl);
-extern void stl_read(stl_file *stl, int first_facet, int first);
-extern void stl_facet_stats(stl_file *stl, stl_facet facet, int first);
+extern void stl_read(stl_file *stl, int first_facet, bool first);
+extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first);
 extern void stl_reallocate(stl_file *stl);
 extern void stl_add_facet(stl_file *stl, stl_facet *new_facet);
 extern void stl_get_size(stl_file *stl);
diff --git a/xs/src/admesh/stl_io.cpp b/xs/src/admesh/stl_io.cpp
index 1603981fc..81e29d286 100644
--- a/xs/src/admesh/stl_io.cpp
+++ b/xs/src/admesh/stl_io.cpp
@@ -44,9 +44,9 @@ stl_print_edges(stl_file *stl, FILE *file) {
   for(i = 0; i < edges_allocated; i++) {
     fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n",
             stl->edge_start[i].facet_number,
-            stl->edge_start[i].p1.x, stl->edge_start[i].p1.y,
-            stl->edge_start[i].p1.z, stl->edge_start[i].p2.x,
-            stl->edge_start[i].p2.y, stl->edge_start[i].p2.z);
+            stl->edge_start[i].p1(0), stl->edge_start[i].p1(1),
+            stl->edge_start[i].p1(2), stl->edge_start[i].p2(0),
+            stl->edge_start[i].p2(1), stl->edge_start[i].p2(2));
   }
 }
 
@@ -75,11 +75,11 @@ File type          : ASCII STL file\n");
 Header             : %s\n", stl->stats.header);
   fprintf(file, "============== Size ==============\n");
   fprintf(file, "Min X = % f, Max X = % f\n",
-          stl->stats.min.x, stl->stats.max.x);
+          stl->stats.min(0), stl->stats.max(0));
   fprintf(file, "Min Y = % f, Max Y = % f\n",
-          stl->stats.min.y, stl->stats.max.y);
+          stl->stats.min(1), stl->stats.max(1));
   fprintf(file, "Min Z = % f, Max Z = % f\n",
-          stl->stats.min.z, stl->stats.max.z);
+          stl->stats.min(2), stl->stats.max(2));
 
   fprintf(file, "\
 ========= Facet Status ========== Original ============ Final ====\n");
@@ -149,18 +149,18 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) {
 
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     fprintf(fp, "  facet normal % .8E % .8E % .8E\n",
-            stl->facet_start[i].normal.x, stl->facet_start[i].normal.y,
-            stl->facet_start[i].normal.z);
+            stl->facet_start[i].normal(0), stl->facet_start[i].normal(1),
+            stl->facet_start[i].normal(2));
     fprintf(fp, "    outer loop\n");
     fprintf(fp, "      vertex % .8E % .8E % .8E\n",
-            stl->facet_start[i].vertex[0].x, stl->facet_start[i].vertex[0].y,
-            stl->facet_start[i].vertex[0].z);
+            stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
+            stl->facet_start[i].vertex[0](2));
     fprintf(fp, "      vertex % .8E % .8E % .8E\n",
-            stl->facet_start[i].vertex[1].x, stl->facet_start[i].vertex[1].y,
-            stl->facet_start[i].vertex[1].z);
+            stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
+            stl->facet_start[i].vertex[1](2));
     fprintf(fp, "      vertex % .8E % .8E % .8E\n",
-            stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y,
-            stl->facet_start[i].vertex[2].z);
+            stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
+            stl->facet_start[i].vertex[2](2));
     fprintf(fp, "    endloop\n");
     fprintf(fp, "  endfacet\n");
   }
@@ -264,9 +264,9 @@ void
 stl_write_vertex(stl_file *stl, int facet, int vertex) {
   if (stl->error) return;
   printf("  vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
-         stl->facet_start[facet].vertex[vertex].x,
-         stl->facet_start[facet].vertex[vertex].y,
-         stl->facet_start[facet].vertex[vertex].z);
+         stl->facet_start[facet].vertex[vertex](0),
+         stl->facet_start[facet].vertex[vertex](1),
+         stl->facet_start[facet].vertex[vertex](2));
 }
 
 void
@@ -309,10 +309,10 @@ stl_write_quad_object(stl_file *stl, char *file) {
   int       i;
   int       j;
   char      *error_msg;
-  stl_vertex connect_color;
-  stl_vertex uncon_1_color;
-  stl_vertex uncon_2_color;
-  stl_vertex uncon_3_color;
+  stl_vertex connect_color = stl_vertex::Zero();
+  stl_vertex uncon_1_color = stl_vertex::Zero();
+  stl_vertex uncon_2_color = stl_vertex::Zero();
+  stl_vertex uncon_3_color = stl_vertex::Zero();
   stl_vertex color;
 
   if (stl->error) return;
@@ -330,19 +330,6 @@ stl_write_quad_object(stl_file *stl, char *file) {
     return;
   }
 
-  connect_color.x = 0.0;
-  connect_color.y = 0.0;
-  connect_color.z = 1.0;
-  uncon_1_color.x = 0.0;
-  uncon_1_color.y = 1.0;
-  uncon_1_color.z = 0.0;
-  uncon_2_color.x = 1.0;
-  uncon_2_color.y = 1.0;
-  uncon_2_color.z = 1.0;
-  uncon_3_color.x = 1.0;
-  uncon_3_color.y = 0.0;
-  uncon_3_color.z = 0.0;
-
   fprintf(fp, "CQUAD\n");
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     j = ((stl->neighbors_start[i].neighbor[0] == -1) +
@@ -358,21 +345,21 @@ stl_write_quad_object(stl_file *stl, char *file) {
       color = uncon_3_color;
     }
     fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
-            stl->facet_start[i].vertex[0].x,
-            stl->facet_start[i].vertex[0].y,
-            stl->facet_start[i].vertex[0].z, color.x, color.y, color.z);
+            stl->facet_start[i].vertex[0](0),
+            stl->facet_start[i].vertex[0](1),
+            stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
     fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
-            stl->facet_start[i].vertex[1].x,
-            stl->facet_start[i].vertex[1].y,
-            stl->facet_start[i].vertex[1].z, color.x, color.y, color.z);
+            stl->facet_start[i].vertex[1](0),
+            stl->facet_start[i].vertex[1](1),
+            stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
     fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
-            stl->facet_start[i].vertex[2].x,
-            stl->facet_start[i].vertex[2].y,
-            stl->facet_start[i].vertex[2].z, color.x, color.y, color.z);
+            stl->facet_start[i].vertex[2](0),
+            stl->facet_start[i].vertex[2](1),
+            stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
     fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
-            stl->facet_start[i].vertex[2].x,
-            stl->facet_start[i].vertex[2].y,
-            stl->facet_start[i].vertex[2].z, color.x, color.y, color.z);
+            stl->facet_start[i].vertex[2](0),
+            stl->facet_start[i].vertex[2](1),
+            stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
   }
   fclose(fp);
 }
@@ -409,17 +396,17 @@ stl_write_dxf(stl_file *stl, char *file, char *label) {
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     fprintf(fp, "0\n3DFACE\n8\n0\n");
     fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n",
-            stl->facet_start[i].vertex[0].x, stl->facet_start[i].vertex[0].y,
-            stl->facet_start[i].vertex[0].z);
+            stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
+            stl->facet_start[i].vertex[0](2));
     fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n",
-            stl->facet_start[i].vertex[1].x, stl->facet_start[i].vertex[1].y,
-            stl->facet_start[i].vertex[1].z);
+            stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
+            stl->facet_start[i].vertex[1](2));
     fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n",
-            stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y,
-            stl->facet_start[i].vertex[2].z);
+            stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
+            stl->facet_start[i].vertex[2](2));
     fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n",
-            stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y,
-            stl->facet_start[i].vertex[2].z);
+            stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
+            stl->facet_start[i].vertex[2](2));
   }
 
   fprintf(fp, "0\nENDSEC\n0\nEOF\n");
diff --git a/xs/src/admesh/stlinit.cpp b/xs/src/admesh/stlinit.cpp
index e572ce930..47a37f0a5 100644
--- a/xs/src/admesh/stlinit.cpp
+++ b/xs/src/admesh/stlinit.cpp
@@ -40,7 +40,7 @@ stl_open(stl_file *stl, const char *file) {
   stl_initialize(stl);
   stl_count_facets(stl, file);
   stl_allocate(stl);
-  stl_read(stl, 0, 1);
+  stl_read(stl, 0, true);
   if (!stl->error) fclose(stl->fp);
 }
 
@@ -227,7 +227,7 @@ stl_open_merge(stl_file *stl, char *file_to_merge) {
      Start at num_facets_so_far, the index to the first unused facet.  Also say
      that this isn't our first time so we should augment stats like min and max
      instead of erasing them. */
-  stl_read(stl, num_facets_so_far, 0);
+  stl_read(stl, num_facets_so_far, false);
 
   /* Restore the stl information we overwrote (for stl_read) so that it still accurately
      reflects the subject part: */
@@ -255,8 +255,7 @@ stl_reallocate(stl_file *stl) {
 /* Reads the contents of the file pointed to by stl->fp into the stl structure,
    starting at facet first_facet.  The second argument says if it's our first
    time running this for the stl and therefore we should reset our max and min stats. */
-void
-stl_read(stl_file *stl, int first_facet, int first) {
+void stl_read(stl_file *stl, int first_facet, bool first) {
   stl_facet facet;
   int   i;
 
@@ -294,11 +293,11 @@ stl_read(stl_file *stl, int first_facet, int first) {
       assert(res_normal == 3);
       int res_outer_loop = fscanf(stl->fp, " outer loop");
       assert(res_outer_loop == 0);
-      int res_vertex1    = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[0].x, &facet.vertex[0].y, &facet.vertex[0].z);
+      int res_vertex1    = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
       assert(res_vertex1 == 3);
-      int res_vertex2    = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[1].x, &facet.vertex[1].y, &facet.vertex[1].z);
+      int res_vertex2    = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
       assert(res_vertex2 == 3);
-      int res_vertex3    = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[2].x, &facet.vertex[2].y, &facet.vertex[2].z);
+      int res_vertex3    = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
       assert(res_vertex3 == 3);
       int res_endloop    = fscanf(stl->fp, " endloop");
       assert(res_endloop == 0);
@@ -311,9 +310,9 @@ stl_read(stl_file *stl, int first_facet, int first) {
       }
 
       // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
-	  if (sscanf(normal_buf[0], "%f", &facet.normal.x) != 1 ||
-		  sscanf(normal_buf[1], "%f", &facet.normal.y) != 1 ||
-		  sscanf(normal_buf[2], "%f", &facet.normal.z) != 1) {
+	  if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
+		  sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
+		  sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
 		  // Normal was mangled. Maybe denormals or "not a number" were stored?
 		  // Just reset the normal and silently ignore it.
 		  memset(&facet.normal, 0, sizeof(facet.normal));
@@ -326,104 +325,45 @@ stl_read(stl_file *stl, int first_facet, int first) {
       // It may be worth to round these numbers to zero during loading to reduce the number of errors reported
       // during the STL import.
       for (size_t j = 0; j < 3; ++ j) {
-        if (facet.vertex[j].x > -1e-12f && facet.vertex[j].x < 1e-12f)
-            printf("stl_read: facet %d.x = %e\r\n", j, facet.vertex[j].x);
-        if (facet.vertex[j].y > -1e-12f && facet.vertex[j].y < 1e-12f)
-            printf("stl_read: facet %d.y = %e\r\n", j, facet.vertex[j].y);
-        if (facet.vertex[j].z > -1e-12f && facet.vertex[j].z < 1e-12f)
-            printf("stl_read: facet %d.z = %e\r\n", j, facet.vertex[j].z);
+        if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f)
+            printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0));
+        if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f)
+            printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1));
+        if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f)
+            printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2));
       }
 #endif
 
-#if 1
-    {
-      // Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
-      // When using a memcmp on raw floats, those numbers report to be different.
-      // Unify all +0 and -0 to +0 to make the floats equal under memcmp.
-      uint32_t *f = (uint32_t*)&facet;
-      for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
-        if (*f == 0x80000000)
-          // Negative zero, switch to positive zero.
-          *f = 0;
-    }
-#else
-    {
-      // Due to the nature of the floating point numbers, close to zero values may be represented with singificantly higher precision 
-      // than the rest of the vertices. Round them to zero.
-      float *f = (float*)&facet;
-      for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
-        if (*f > -1e-12f && *f < 1e-12f)
-          // Negative zero, switch to positive zero.
-          *f = 0;
-    }
-#endif
     /* Write the facet into memory. */
-    memcpy(stl->facet_start+i, &facet, SIZEOF_STL_FACET);
+    stl->facet_start[i] = facet;
     stl_facet_stats(stl, facet, first);
-    first = 0;
   }
-  stl->stats.size.x = stl->stats.max.x - stl->stats.min.x;
-  stl->stats.size.y = stl->stats.max.y - stl->stats.min.y;
-  stl->stats.size.z = stl->stats.max.z - stl->stats.min.z;
-  stl->stats.bounding_diameter = sqrt(
-                                   stl->stats.size.x * stl->stats.size.x +
-                                   stl->stats.size.y * stl->stats.size.y +
-                                   stl->stats.size.z * stl->stats.size.z
-                                 );
+  stl->stats.size = stl->stats.max - stl->stats.min;
+  stl->stats.bounding_diameter = stl->stats.size.norm();
 }
 
-void
-stl_facet_stats(stl_file *stl, stl_facet facet, int first) {
-  float diff_x;
-  float diff_y;
-  float diff_z;
-  float max_diff;
+void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first)
+{
+  if (stl->error)
+  	return;
 
-  if (stl->error) return;
+  // While we are going through all of the facets, let's find the
+  // maximum and minimum values for x, y, and z
 
-  /* while we are going through all of the facets, let's find the  */
-  /* maximum and minimum values for x, y, and z  */
-
-  /* Initialize the max and min values the first time through*/
   if (first) {
-    stl->stats.max.x = facet.vertex[0].x;
-    stl->stats.min.x = facet.vertex[0].x;
-    stl->stats.max.y = facet.vertex[0].y;
-    stl->stats.min.y = facet.vertex[0].y;
-    stl->stats.max.z = facet.vertex[0].z;
-    stl->stats.min.z = facet.vertex[0].z;
-
-    diff_x = ABS(facet.vertex[0].x - facet.vertex[1].x);
-    diff_y = ABS(facet.vertex[0].y - facet.vertex[1].y);
-    diff_z = ABS(facet.vertex[0].z - facet.vertex[1].z);
-    max_diff = STL_MAX(diff_x, diff_y);
-    max_diff = STL_MAX(diff_z, max_diff);
-    stl->stats.shortest_edge = max_diff;
-
-    first = 0;
+	// Initialize the max and min values the first time through
+    stl->stats.min = facet.vertex[0];
+    stl->stats.max = facet.vertex[0];
+    stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs();
+    stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2)));
+    first = false;
   }
 
-  /* now find the max and min values */
-  stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[0].x);
-  stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[0].x);
-  stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[0].y);
-  stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[0].y);
-  stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[0].z);
-  stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[0].z);
-
-  stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[1].x);
-  stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[1].x);
-  stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[1].y);
-  stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[1].y);
-  stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[1].z);
-  stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[1].z);
-
-  stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[2].x);
-  stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[2].x);
-  stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[2].y);
-  stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[2].y);
-  stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[2].z);
-  stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[2].z);
+  // Now find the max and min values.
+  for (size_t i = 0; i < 3; ++ i) {
+  	stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]);
+  	stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
+  }
 }
 
 void
diff --git a/xs/src/admesh/util.cpp b/xs/src/admesh/util.cpp
index f3bf59b56..fba1ee76b 100644
--- a/xs/src/admesh/util.cpp
+++ b/xs/src/admesh/util.cpp
@@ -62,7 +62,7 @@ stl_verify_neighbors(stl_file *stl) {
         edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
         edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
       }
-      if(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) {
+      if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
         /* These edges should match but they don't.  Print results. */
         printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
                j, i, vnot + 1, neighbor);
@@ -73,114 +73,67 @@ stl_verify_neighbors(stl_file *stl) {
   }
 }
 
-void
-stl_translate(stl_file *stl, float x, float y, float z) {
-  int i;
-  int j;
-
-  if (stl->error) return;
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl->facet_start[i].vertex[j].x -= (stl->stats.min.x - x);
-      stl->facet_start[i].vertex[j].y -= (stl->stats.min.y - y);
-      stl->facet_start[i].vertex[j].z -= (stl->stats.min.z - z);
-    }
-  }
-  stl->stats.max.x -= (stl->stats.min.x - x);
-  stl->stats.max.y -= (stl->stats.min.y - y);
-  stl->stats.max.z -= (stl->stats.min.z - z);
-  stl->stats.min.x = x;
-  stl->stats.min.y = y;
-  stl->stats.min.z = z;
+void stl_translate(stl_file *stl, float x, float y, float z)
+{
+  if (stl->error)
+  	return;
 
+  stl_vertex new_min(x, y, z);
+  stl_vertex shift = new_min - stl->stats.min;
+  for (int i = 0; i < stl->stats.number_of_facets; ++ i)
+    for (int j = 0; j < 3; ++ j)
+      stl->facet_start[i].vertex[j] += shift;
+  stl->stats.min = new_min;
+  stl->stats.max += shift;
   stl_invalidate_shared_vertices(stl);
 }
 
 /* Translates the stl by x,y,z, relatively from wherever it is currently */
-void
-stl_translate_relative(stl_file *stl, float x, float y, float z) {
-  int i;
-  int j;
-
-  if (stl->error) return;
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl->facet_start[i].vertex[j].x += x;
-      stl->facet_start[i].vertex[j].y += y;
-      stl->facet_start[i].vertex[j].z += z;
-    }
-  }
-  stl->stats.min.x += x;
-  stl->stats.min.y += y;
-  stl->stats.min.z += z;
-  stl->stats.max.x += x;
-  stl->stats.max.y += y;
-  stl->stats.max.z += z;
+void stl_translate_relative(stl_file *stl, float x, float y, float z)
+{
+  if (stl->error)
+  	return;
 
+  stl_vertex shift(x, y, z);
+  for (int i = 0; i < stl->stats.number_of_facets; ++ i)
+    for (int j = 0; j < 3; ++ j)
+      stl->facet_start[i].vertex[j] += shift;
+  stl->stats.min += shift;
+  stl->stats.max += shift;
   stl_invalidate_shared_vertices(stl);
 }
 
-void
-stl_scale_versor(stl_file *stl, float versor[3]) {
-  int i;
-  int j;
-
-  if (stl->error) return;
-
-  /* scale extents */
-  stl->stats.min.x *= versor[0];
-  stl->stats.min.y *= versor[1];
-  stl->stats.min.z *= versor[2];
-  stl->stats.max.x *= versor[0];
-  stl->stats.max.y *= versor[1];
-  stl->stats.max.z *= versor[2];
-
-  /* scale size */
-  stl->stats.size.x *= versor[0];
-  stl->stats.size.y *= versor[1];
-  stl->stats.size.z *= versor[2];
-
-  /* scale volume */
-  if (stl->stats.volume > 0.0) {
-    stl->stats.volume *= (versor[0] * versor[1] * versor[2]);
-  }
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl->facet_start[i].vertex[j].x *= versor[0];
-      stl->facet_start[i].vertex[j].y *= versor[1];
-      stl->facet_start[i].vertex[j].z *= versor[2];
-    }
-  }
+void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
+{
+  if (stl->error)
+  	return;
 
+  // Scale extents.
+  auto s = versor.array();
+  stl->stats.min.array() *= s;
+  stl->stats.max.array() *= s;
+  // Scale size.
+  stl->stats.size.array() *= s;
+  // Scale volume.
+  if (stl->stats.volume > 0.0)
+    stl->stats.volume *= versor(0) * versor(1) * versor(2);
+  // Scale the mesh.
+  for (int i = 0; i < stl->stats.number_of_facets; ++ i)
+    for (int j = 0; j < 3; ++ j)
+      stl->facet_start[i].vertex[j].array() *= s;
   stl_invalidate_shared_vertices(stl);
 }
 
-void
-stl_scale(stl_file *stl, float factor) {
-  float versor[3];
-
-  if (stl->error) return;
-
-  versor[0] = factor;
-  versor[1] = factor;
-  versor[2] = factor;
-  stl_scale_versor(stl, versor);
-}
-
-static void calculate_normals(stl_file *stl) {
-  float normal[3];
-
-  if (stl->error) return;
+static void calculate_normals(stl_file *stl) 
+{
+  if (stl->error)
+  	return;
 
+  stl_normal normal;
   for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
     stl_calculate_normal(normal, &stl->facet_start[i]);
     stl_normalize_vector(normal);
-    stl->facet_start[i].normal.x = normal[0];
-    stl->facet_start[i].normal.y = normal[1];
-    stl->facet_start[i].normal.z = normal[2];
+    stl->facet_start[i].normal = normal;
   }
 }
 
@@ -193,9 +146,9 @@ void stl_transform(stl_file *stl, float *trafo3x4) {
     for (i_vertex = 0; i_vertex < 3; ++ i_vertex) {
       stl_vertex &v_dst = vertices[i_vertex];
       stl_vertex  v_src = v_dst;
-      v_dst.x = trafo3x4[0] * v_src.x + trafo3x4[1] * v_src.y + trafo3x4[2]  * v_src.z + trafo3x4[3];
-      v_dst.y = trafo3x4[4] * v_src.x + trafo3x4[5] * v_src.y + trafo3x4[6]  * v_src.z + trafo3x4[7];
-      v_dst.z = trafo3x4[8] * v_src.x + trafo3x4[9] * v_src.y + trafo3x4[10] * v_src.z + trafo3x4[11];
+      v_dst(0) = trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2]  * v_src(2) + trafo3x4[3];
+      v_dst(1) = trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6]  * v_src(2) + trafo3x4[7];
+      v_dst(2) = trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11];
     }
   }
   stl_get_size(stl);
@@ -214,8 +167,8 @@ stl_rotate_x(stl_file *stl, float angle) {
 
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     for(j = 0; j < 3; j++) {
-      stl_rotate(&stl->facet_start[i].vertex[j].y,
-                 &stl->facet_start[i].vertex[j].z, c, s);
+      stl_rotate(&stl->facet_start[i].vertex[j](1),
+                 &stl->facet_start[i].vertex[j](2), c, s);
     }
   }
   stl_get_size(stl);
@@ -234,8 +187,8 @@ stl_rotate_y(stl_file *stl, float angle) {
 
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     for(j = 0; j < 3; j++) {
-      stl_rotate(&stl->facet_start[i].vertex[j].z,
-                 &stl->facet_start[i].vertex[j].x, c, s);
+      stl_rotate(&stl->facet_start[i].vertex[j](2),
+                 &stl->facet_start[i].vertex[j](0), c, s);
     }
   }
   stl_get_size(stl);
@@ -254,8 +207,8 @@ stl_rotate_z(stl_file *stl, float angle) {
 
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     for(j = 0; j < 3; j++) {
-      stl_rotate(&stl->facet_start[i].vertex[j].x,
-                 &stl->facet_start[i].vertex[j].y, c, s);
+      stl_rotate(&stl->facet_start[i].vertex[j](0),
+                 &stl->facet_start[i].vertex[j](1), c, s);
     }
   }
   stl_get_size(stl);
@@ -272,142 +225,98 @@ stl_rotate(float *x, float *y, const double c, const double s) {
   *y = float(s * xold + c * yold);
 }
 
-extern void
-stl_get_size(stl_file *stl) {
-  int i;
-  int j;
-
-  if (stl->error) return;
-  if (stl->stats.number_of_facets == 0) return;
-
-  stl->stats.min.x = stl->facet_start[0].vertex[0].x;
-  stl->stats.min.y = stl->facet_start[0].vertex[0].y;
-  stl->stats.min.z = stl->facet_start[0].vertex[0].z;
-  stl->stats.max.x = stl->facet_start[0].vertex[0].x;
-  stl->stats.max.y = stl->facet_start[0].vertex[0].y;
-  stl->stats.max.z = stl->facet_start[0].vertex[0].z;
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl->stats.min.x = STL_MIN(stl->stats.min.x,
-                                 stl->facet_start[i].vertex[j].x);
-      stl->stats.min.y = STL_MIN(stl->stats.min.y,
-                                 stl->facet_start[i].vertex[j].y);
-      stl->stats.min.z = STL_MIN(stl->stats.min.z,
-                                 stl->facet_start[i].vertex[j].z);
-      stl->stats.max.x = STL_MAX(stl->stats.max.x,
-                                 stl->facet_start[i].vertex[j].x);
-      stl->stats.max.y = STL_MAX(stl->stats.max.y,
-                                 stl->facet_start[i].vertex[j].y);
-      stl->stats.max.z = STL_MAX(stl->stats.max.z,
-                                 stl->facet_start[i].vertex[j].z);
+void stl_get_size(stl_file *stl)
+{
+  if (stl->error || stl->stats.number_of_facets == 0)
+  	return;
+  stl->stats.min = stl->facet_start[0].vertex[0];
+  stl->stats.max = stl->stats.min;
+  for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
+  	const stl_facet &face = stl->facet_start[i];
+    for (int j = 0; j < 3; ++ j) {
+      stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]);
+      stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]);
     }
   }
-  stl->stats.size.x = stl->stats.max.x - stl->stats.min.x;
-  stl->stats.size.y = stl->stats.max.y - stl->stats.min.y;
-  stl->stats.size.z = stl->stats.max.z - stl->stats.min.z;
-  stl->stats.bounding_diameter = sqrt(
-                                   stl->stats.size.x * stl->stats.size.x +
-                                   stl->stats.size.y * stl->stats.size.y +
-                                   stl->stats.size.z * stl->stats.size.z
-                                 );
+  stl->stats.size = stl->stats.max - stl->stats.min;
+  stl->stats.bounding_diameter = stl->stats.size.norm();
 }
 
-void
-stl_mirror_xy(stl_file *stl) {
-  int i;
-  int j;
-  float temp_size;
+void stl_mirror_xy(stl_file *stl)
+{
+  if (stl->error) 
+  	return;
 
-  if (stl->error) return;
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl->facet_start[i].vertex[j].z *= -1.0;
+  for(int i = 0; i < stl->stats.number_of_facets; i++) {
+    for(int j = 0; j < 3; j++) {
+      stl->facet_start[i].vertex[j](2) *= -1.0;
     }
   }
-  temp_size = stl->stats.min.z;
-  stl->stats.min.z = stl->stats.max.z;
-  stl->stats.max.z = temp_size;
-  stl->stats.min.z *= -1.0;
-  stl->stats.max.z *= -1.0;
+  float temp_size = stl->stats.min(2);
+  stl->stats.min(2) = stl->stats.max(2);
+  stl->stats.max(2) = temp_size;
+  stl->stats.min(2) *= -1.0;
+  stl->stats.max(2) *= -1.0;
   stl_reverse_all_facets(stl);
   stl->stats.facets_reversed -= stl->stats.number_of_facets;  /* for not altering stats */
 }
 
-void
-stl_mirror_yz(stl_file *stl) {
-  int i;
-  int j;
-  float temp_size;
-
+void stl_mirror_yz(stl_file *stl)
+{
   if (stl->error) return;
 
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl->facet_start[i].vertex[j].x *= -1.0;
+  for (int i = 0; i < stl->stats.number_of_facets; i++) {
+    for (int j = 0; j < 3; j++) {
+      stl->facet_start[i].vertex[j](0) *= -1.0;
     }
   }
-  temp_size = stl->stats.min.x;
-  stl->stats.min.x = stl->stats.max.x;
-  stl->stats.max.x = temp_size;
-  stl->stats.min.x *= -1.0;
-  stl->stats.max.x *= -1.0;
+  float temp_size = stl->stats.min(0);
+  stl->stats.min(0) = stl->stats.max(0);
+  stl->stats.max(0) = temp_size;
+  stl->stats.min(0) *= -1.0;
+  stl->stats.max(0) *= -1.0;
   stl_reverse_all_facets(stl);
   stl->stats.facets_reversed -= stl->stats.number_of_facets;  /* for not altering stats */
 }
 
-void
-stl_mirror_xz(stl_file *stl) {
-  int i;
-  int j;
-  float temp_size;
+void stl_mirror_xz(stl_file *stl)
+{
+  if (stl->error)
+  	return;
 
-  if (stl->error) return;
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl->facet_start[i].vertex[j].y *= -1.0;
+  for (int i = 0; i < stl->stats.number_of_facets; i++) {
+    for (int j = 0; j < 3; j++) {
+      stl->facet_start[i].vertex[j](1) *= -1.0;
     }
   }
-  temp_size = stl->stats.min.y;
-  stl->stats.min.y = stl->stats.max.y;
-  stl->stats.max.y = temp_size;
-  stl->stats.min.y *= -1.0;
-  stl->stats.max.y *= -1.0;
+  float temp_size = stl->stats.min(1);
+  stl->stats.min(1) = stl->stats.max(1);
+  stl->stats.max(1) = temp_size;
+  stl->stats.min(1) *= -1.0;
+  stl->stats.max(1) *= -1.0;
   stl_reverse_all_facets(stl);
   stl->stats.facets_reversed -= stl->stats.number_of_facets;  /* for not altering stats */
 }
 
-static float get_volume(stl_file *stl) {
-  stl_vertex p0;
-  stl_vertex p;
-  stl_normal n;
-  float height;
-  float area;
-  float volume = 0.0;
+static float get_volume(stl_file *stl)
+{
+  if (stl->error)
+  	return 0;
 
-  if (stl->error) return 0;
-
-  /* Choose a point, any point as the reference */
-  p0.x = stl->facet_start[0].vertex[0].x;
-  p0.y = stl->facet_start[0].vertex[0].y;
-  p0.z = stl->facet_start[0].vertex[0].z;
-
-  for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
-    p.x = stl->facet_start[i].vertex[0].x - p0.x;
-    p.y = stl->facet_start[i].vertex[0].y - p0.y;
-    p.z = stl->facet_start[i].vertex[0].z - p0.z;
-    /* Do dot product to get distance from point to plane */
-    n = stl->facet_start[i].normal;
-    height = (n.x * p.x) + (n.y * p.y) + (n.z * p.z);
-    area = get_area(&stl->facet_start[i]);
+  // Choose a point, any point as the reference.
+  stl_vertex p0 = stl->facet_start[0].vertex[0];
+  float volume = 0.f;
+  for(uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+    // Do dot product to get distance from point to plane.
+    float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0);
+    float area   = get_area(&stl->facet_start[i]);
     volume += (area * height) / 3.0f;
   }
   return volume;
 }
 
-void stl_calculate_volume(stl_file *stl) {
+void stl_calculate_volume(stl_file *stl)
+{
   if (stl->error) return;
   stl->stats.volume = get_volume(stl);
   if(stl->stats.volume < 0.0) {
@@ -416,35 +325,32 @@ void stl_calculate_volume(stl_file *stl) {
   }
 }
 
-static float get_area(stl_facet *facet) {
-  double cross[3][3];
-  float sum[3];
-  float n[3];
-  float area;
-  int i;
-
+static float get_area(stl_facet *facet)
+{
   /* cast to double before calculating cross product because large coordinates
      can result in overflowing product
     (bad area is responsible for bad volume and bad facets reversal) */
-  for(i = 0; i < 3; i++) {
-    cross[i][0]=(((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].z) -
-                 ((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].y));
-    cross[i][1]=(((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].x) -
-                 ((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].z));
-    cross[i][2]=(((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].y) -
-                 ((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].x));
+  double cross[3][3];
+  for (int i = 0; i < 3; i++) {
+    cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) -
+                 ((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1)));
+    cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) -
+                 ((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2)));
+    cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) -
+                 ((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0)));
   }
 
-  sum[0] = cross[0][0] + cross[1][0] + cross[2][0];
-  sum[1] = cross[0][1] + cross[1][1] + cross[2][1];
-  sum[2] = cross[0][2] + cross[1][2] + cross[2][2];
+  stl_normal sum;
+  sum(0) = cross[0][0] + cross[1][0] + cross[2][0];
+  sum(1) = cross[0][1] + cross[1][1] + cross[2][1];
+  sum(2) = cross[0][2] + cross[1][2] + cross[2][2];
 
-  /* This should already be done.  But just in case, let's do it again */
+  // This should already be done.  But just in case, let's do it again.
+  //FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy.
+  stl_normal n;
   stl_calculate_normal(n, facet);
   stl_normalize_vector(n);
-
-  area = 0.5 * (n[0] * sum[0] + n[1] * sum[1] + n[2] * sum[2]);
-  return area;
+  return 0.5f * n.dot(sum);
 }
 
 void stl_repair(stl_file *stl,
diff --git a/xs/src/eigen/Eigen/Cholesky b/xs/src/eigen/Eigen/Cholesky
index 369d1f5ec..1332b540d 100644
--- a/xs/src/eigen/Eigen/Cholesky
+++ b/xs/src/eigen/Eigen/Cholesky
@@ -9,6 +9,7 @@
 #define EIGEN_CHOLESKY_MODULE_H
 
 #include "Core"
+#include "Jacobi"
 
 #include "src/Core/util/DisableStupidWarnings.h"
 
@@ -31,7 +32,11 @@
 #include "src/Cholesky/LLT.h"
 #include "src/Cholesky/LDLT.h"
 #ifdef EIGEN_USE_LAPACKE
+#ifdef EIGEN_USE_MKL
+#include "mkl_lapacke.h"
+#else
 #include "src/misc/lapacke.h"
+#endif
 #include "src/Cholesky/LLT_LAPACKE.h"
 #endif
 
diff --git a/xs/src/eigen/Eigen/Core b/xs/src/eigen/Eigen/Core
index 0f7fa630d..4d4901e03 100644
--- a/xs/src/eigen/Eigen/Core
+++ b/xs/src/eigen/Eigen/Core
@@ -14,6 +14,22 @@
 // first thing Eigen does: stop the compiler from committing suicide
 #include "src/Core/util/DisableStupidWarnings.h"
 
+#if defined(__CUDACC__) && !defined(EIGEN_NO_CUDA)
+  #define EIGEN_CUDACC __CUDACC__
+#endif
+
+#if defined(__CUDA_ARCH__) && !defined(EIGEN_NO_CUDA)
+  #define EIGEN_CUDA_ARCH __CUDA_ARCH__
+#endif
+
+#if defined(__CUDACC_VER_MAJOR__) && (__CUDACC_VER_MAJOR__ >= 9)
+#define EIGEN_CUDACC_VER  ((__CUDACC_VER_MAJOR__ * 10000) + (__CUDACC_VER_MINOR__ * 100))
+#elif defined(__CUDACC_VER__)
+#define EIGEN_CUDACC_VER __CUDACC_VER__
+#else
+#define EIGEN_CUDACC_VER 0
+#endif
+
 // Handle NVCC/CUDA/SYCL
 #if defined(__CUDACC__) || defined(__SYCL_DEVICE_ONLY__)
   // Do not try asserts on CUDA and SYCL!
@@ -155,6 +171,9 @@
       #ifdef __AVX512DQ__
         #define EIGEN_VECTORIZE_AVX512DQ
       #endif
+      #ifdef __AVX512ER__
+        #define EIGEN_VECTORIZE_AVX512ER
+      #endif
     #endif
 
     // include files
@@ -229,7 +248,7 @@
 #if defined __CUDACC__
   #define EIGEN_VECTORIZE_CUDA
   #include <vector_types.h>
-  #if defined __CUDACC_VER__ && __CUDACC_VER__ >= 70500
+  #if EIGEN_CUDACC_VER >= 70500
     #define EIGEN_HAS_CUDA_FP16
   #endif
 #endif
@@ -352,6 +371,7 @@ using std::ptrdiff_t;
 #include "src/Core/MathFunctions.h"
 #include "src/Core/GenericPacketMath.h"
 #include "src/Core/MathFunctionsImpl.h"
+#include "src/Core/arch/Default/ConjHelper.h"
 
 #if defined EIGEN_VECTORIZE_AVX512
   #include "src/Core/arch/SSE/PacketMath.h"
@@ -367,6 +387,7 @@ using std::ptrdiff_t;
   #include "src/Core/arch/AVX/MathFunctions.h"
   #include "src/Core/arch/AVX/Complex.h"
   #include "src/Core/arch/AVX/TypeCasting.h"
+  #include "src/Core/arch/SSE/TypeCasting.h"
 #elif defined EIGEN_VECTORIZE_SSE
   #include "src/Core/arch/SSE/PacketMath.h"
   #include "src/Core/arch/SSE/MathFunctions.h"
diff --git a/xs/src/eigen/Eigen/Eigenvalues b/xs/src/eigen/Eigen/Eigenvalues
index 009e529e1..f3f661b07 100644
--- a/xs/src/eigen/Eigen/Eigenvalues
+++ b/xs/src/eigen/Eigen/Eigenvalues
@@ -45,7 +45,11 @@
 #include "src/Eigenvalues/GeneralizedEigenSolver.h"
 #include "src/Eigenvalues/MatrixBaseEigenvalues.h"
 #ifdef EIGEN_USE_LAPACKE
+#ifdef EIGEN_USE_MKL
+#include "mkl_lapacke.h"
+#else
 #include "src/misc/lapacke.h"
+#endif
 #include "src/Eigenvalues/RealSchur_LAPACKE.h"
 #include "src/Eigenvalues/ComplexSchur_LAPACKE.h"
 #include "src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h"
diff --git a/xs/src/eigen/Eigen/LU b/xs/src/eigen/Eigen/LU
index 6f6c55629..6418a86e1 100644
--- a/xs/src/eigen/Eigen/LU
+++ b/xs/src/eigen/Eigen/LU
@@ -28,7 +28,11 @@
 #include "src/LU/FullPivLU.h"
 #include "src/LU/PartialPivLU.h"
 #ifdef EIGEN_USE_LAPACKE
+#ifdef EIGEN_USE_MKL
+#include "mkl_lapacke.h"
+#else
 #include "src/misc/lapacke.h"
+#endif
 #include "src/LU/PartialPivLU_LAPACKE.h"
 #endif
 #include "src/LU/Determinant.h"
diff --git a/xs/src/eigen/Eigen/QR b/xs/src/eigen/Eigen/QR
index 80838e3bd..c7e914469 100644
--- a/xs/src/eigen/Eigen/QR
+++ b/xs/src/eigen/Eigen/QR
@@ -36,7 +36,11 @@
 #include "src/QR/ColPivHouseholderQR.h"
 #include "src/QR/CompleteOrthogonalDecomposition.h"
 #ifdef EIGEN_USE_LAPACKE
+#ifdef EIGEN_USE_MKL
+#include "mkl_lapacke.h"
+#else
 #include "src/misc/lapacke.h"
+#endif
 #include "src/QR/HouseholderQR_LAPACKE.h"
 #include "src/QR/ColPivHouseholderQR_LAPACKE.h"
 #endif
diff --git a/xs/src/eigen/Eigen/QtAlignedMalloc b/xs/src/eigen/Eigen/QtAlignedMalloc
index c6571f129..4f07df02a 100644
--- a/xs/src/eigen/Eigen/QtAlignedMalloc
+++ b/xs/src/eigen/Eigen/QtAlignedMalloc
@@ -27,7 +27,7 @@ void qFree(void *ptr)
 void *qRealloc(void *ptr, std::size_t size)
 {
   void* newPtr = Eigen::internal::aligned_malloc(size);
-  memcpy(newPtr, ptr, size);
+  std::memcpy(newPtr, ptr, size);
   Eigen::internal::aligned_free(ptr);
   return newPtr;
 }
diff --git a/xs/src/eigen/Eigen/SVD b/xs/src/eigen/Eigen/SVD
index 86143c23d..5d0e75f7f 100644
--- a/xs/src/eigen/Eigen/SVD
+++ b/xs/src/eigen/Eigen/SVD
@@ -37,7 +37,11 @@
 #include "src/SVD/JacobiSVD.h"
 #include "src/SVD/BDCSVD.h"
 #if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT)
+#ifdef EIGEN_USE_MKL
+#include "mkl_lapacke.h"
+#else
 #include "src/misc/lapacke.h"
+#endif
 #include "src/SVD/JacobiSVD_LAPACKE.h"
 #endif
 
diff --git a/xs/src/eigen/Eigen/src/Cholesky/LDLT.h b/xs/src/eigen/Eigen/src/Cholesky/LDLT.h
index fcee7b2e3..0313a54bf 100644
--- a/xs/src/eigen/Eigen/src/Cholesky/LDLT.h
+++ b/xs/src/eigen/Eigen/src/Cholesky/LDLT.h
@@ -248,7 +248,7 @@ template<typename _MatrixType, int _UpLo> class LDLT
     /** \brief Reports whether previous computation was successful.
       *
       * \returns \c Success if computation was succesful,
-      *          \c NumericalIssue if the matrix.appears to be negative.
+      *          \c NumericalIssue if the factorization failed because of a zero pivot.
       */
     ComputationInfo info() const
     {
@@ -376,6 +376,8 @@ template<> struct ldlt_inplace<Lower>
 
       if((rs>0) && pivot_is_valid)
         A21 /= realAkk;
+      else if(rs>0)
+        ret = ret && (A21.array()==Scalar(0)).all();
 
       if(found_zero_pivot && pivot_is_valid) ret = false; // factorization failed
       else if(!pivot_is_valid) found_zero_pivot = true;
@@ -568,13 +570,14 @@ void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) cons
   // more precisely, use pseudo-inverse of D (see bug 241)
   using std::abs;
   const typename Diagonal<const MatrixType>::RealReturnType vecD(vectorD());
-  // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon
-  // as motivated by LAPACK's xGELSS:
+  // In some previous versions, tolerance was set to the max of 1/highest (or rather numeric_limits::min())
+  // and the maximal diagonal entry * epsilon as motivated by LAPACK's xGELSS:
   // RealScalar tolerance = numext::maxi(vecD.array().abs().maxCoeff() * NumTraits<RealScalar>::epsilon(),RealScalar(1) / NumTraits<RealScalar>::highest());
   // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest
   // diagonal element is not well justified and leads to numerical issues in some cases.
   // Moreover, Lapack's xSYTRS routines use 0 for the tolerance.
-  RealScalar tolerance = RealScalar(1) / NumTraits<RealScalar>::highest();
+  // Using numeric_limits::min() gives us more robustness to denormals.
+  RealScalar tolerance = (std::numeric_limits<RealScalar>::min)();
 
   for (Index i = 0; i < vecD.size(); ++i)
   {
diff --git a/xs/src/eigen/Eigen/src/Cholesky/LLT.h b/xs/src/eigen/Eigen/src/Cholesky/LLT.h
index 87ca8d423..e1624d21b 100644
--- a/xs/src/eigen/Eigen/src/Cholesky/LLT.h
+++ b/xs/src/eigen/Eigen/src/Cholesky/LLT.h
@@ -24,7 +24,7 @@ template<typename MatrixType, int UpLo> struct LLT_Traits;
   *
   * \tparam _MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition
   * \tparam _UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper.
-  *             The other triangular part won't be read.
+  *               The other triangular part won't be read.
   *
   * This class performs a LL^T Cholesky decomposition of a symmetric, positive definite
   * matrix A such that A = LL^* = U^*U, where L is lower triangular.
@@ -41,14 +41,18 @@ template<typename MatrixType, int UpLo> struct LLT_Traits;
   * Example: \include LLT_example.cpp
   * Output: \verbinclude LLT_example.out
   *
+  * \b Performance: for best performance, it is recommended to use a column-major storage format
+  * with the Lower triangular part (the default), or, equivalently, a row-major storage format
+  * with the Upper triangular part. Otherwise, you might get a 20% slowdown for the full factorization
+  * step, and rank-updates can be up to 3 times slower.
+  *
   * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism.
   *
+  * Note that during the decomposition, only the lower (or upper, as defined by _UpLo) triangular part of A is considered.
+  * Therefore, the strict lower part does not have to store correct values.
+  *
   * \sa MatrixBase::llt(), SelfAdjointView::llt(), class LDLT
   */
- /* HEY THIS DOX IS DISABLED BECAUSE THERE's A BUG EITHER HERE OR IN LDLT ABOUT THAT (OR BOTH)
-  * Note that during the decomposition, only the upper triangular part of A is considered. Therefore,
-  * the strict lower part does not have to store correct values.
-  */
 template<typename _MatrixType, int _UpLo> class LLT
 {
   public:
@@ -146,7 +150,7 @@ template<typename _MatrixType, int _UpLo> class LLT
     }
 
     template<typename Derived>
-    void solveInPlace(MatrixBase<Derived> &bAndX) const;
+    void solveInPlace(const MatrixBase<Derived> &bAndX) const;
 
     template<typename InputType>
     LLT& compute(const EigenBase<InputType>& matrix);
@@ -177,7 +181,7 @@ template<typename _MatrixType, int _UpLo> class LLT
     /** \brief Reports whether previous computation was successful.
       *
       * \returns \c Success if computation was succesful,
-      *          \c NumericalIssue if the matrix.appears to be negative.
+      *          \c NumericalIssue if the matrix.appears not to be positive definite.
       */
     ComputationInfo info() const
     {
@@ -425,7 +429,8 @@ LLT<MatrixType,_UpLo>& LLT<MatrixType,_UpLo>::compute(const EigenBase<InputType>
   eigen_assert(a.rows()==a.cols());
   const Index size = a.rows();
   m_matrix.resize(size, size);
-  m_matrix = a.derived();
+  if (!internal::is_same_dense(m_matrix, a.derived()))
+    m_matrix = a.derived();
 
   // Compute matrix L1 norm = max abs column sum.
   m_l1_norm = RealScalar(0);
@@ -485,11 +490,14 @@ void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const
   *
   * This version avoids a copy when the right hand side matrix b is not needed anymore.
   *
+  * \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here.
+  * This function will const_cast it, so constness isn't honored here.
+  *
   * \sa LLT::solve(), MatrixBase::llt()
   */
 template<typename MatrixType, int _UpLo>
 template<typename Derived>
-void LLT<MatrixType,_UpLo>::solveInPlace(MatrixBase<Derived> &bAndX) const
+void LLT<MatrixType,_UpLo>::solveInPlace(const MatrixBase<Derived> &bAndX) const
 {
   eigen_assert(m_isInitialized && "LLT is not initialized.");
   eigen_assert(m_matrix.rows()==bAndX.rows());
diff --git a/xs/src/eigen/Eigen/src/Core/Array.h b/xs/src/eigen/Eigen/src/Core/Array.h
index 0d34269fd..e10020d4f 100644
--- a/xs/src/eigen/Eigen/src/Core/Array.h
+++ b/xs/src/eigen/Eigen/src/Core/Array.h
@@ -231,10 +231,16 @@ class Array
             : Base(other)
     { }
 
+  private:
+    struct PrivateType {};
+  public:
+
     /** \sa MatrixBase::operator=(const EigenBase<OtherDerived>&) */
     template<typename OtherDerived>
     EIGEN_DEVICE_FUNC
-    EIGEN_STRONG_INLINE Array(const EigenBase<OtherDerived> &other)
+    EIGEN_STRONG_INLINE Array(const EigenBase<OtherDerived> &other,
+                              typename internal::enable_if<internal::is_convertible<typename OtherDerived::Scalar,Scalar>::value,
+                                                           PrivateType>::type = PrivateType())
       : Base(other.derived())
     { }
 
diff --git a/xs/src/eigen/Eigen/src/Core/ArrayBase.h b/xs/src/eigen/Eigen/src/Core/ArrayBase.h
index f0232f65e..3dbc7084c 100644
--- a/xs/src/eigen/Eigen/src/Core/ArrayBase.h
+++ b/xs/src/eigen/Eigen/src/Core/ArrayBase.h
@@ -175,7 +175,7 @@ template<typename Derived> class ArrayBase
   */
 template<typename Derived>
 template<typename OtherDerived>
-EIGEN_STRONG_INLINE Derived &
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived &
 ArrayBase<Derived>::operator-=(const ArrayBase<OtherDerived> &other)
 {
   call_assignment(derived(), other.derived(), internal::sub_assign_op<Scalar,typename OtherDerived::Scalar>());
@@ -188,7 +188,7 @@ ArrayBase<Derived>::operator-=(const ArrayBase<OtherDerived> &other)
   */
 template<typename Derived>
 template<typename OtherDerived>
-EIGEN_STRONG_INLINE Derived &
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived &
 ArrayBase<Derived>::operator+=(const ArrayBase<OtherDerived>& other)
 {
   call_assignment(derived(), other.derived(), internal::add_assign_op<Scalar,typename OtherDerived::Scalar>());
@@ -201,7 +201,7 @@ ArrayBase<Derived>::operator+=(const ArrayBase<OtherDerived>& other)
   */
 template<typename Derived>
 template<typename OtherDerived>
-EIGEN_STRONG_INLINE Derived &
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived &
 ArrayBase<Derived>::operator*=(const ArrayBase<OtherDerived>& other)
 {
   call_assignment(derived(), other.derived(), internal::mul_assign_op<Scalar,typename OtherDerived::Scalar>());
@@ -214,7 +214,7 @@ ArrayBase<Derived>::operator*=(const ArrayBase<OtherDerived>& other)
   */
 template<typename Derived>
 template<typename OtherDerived>
-EIGEN_STRONG_INLINE Derived &
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived &
 ArrayBase<Derived>::operator/=(const ArrayBase<OtherDerived>& other)
 {
   call_assignment(derived(), other.derived(), internal::div_assign_op<Scalar,typename OtherDerived::Scalar>());
diff --git a/xs/src/eigen/Eigen/src/Core/ArrayWrapper.h b/xs/src/eigen/Eigen/src/Core/ArrayWrapper.h
index a04521a16..688aadd62 100644
--- a/xs/src/eigen/Eigen/src/Core/ArrayWrapper.h
+++ b/xs/src/eigen/Eigen/src/Core/ArrayWrapper.h
@@ -32,7 +32,8 @@ struct traits<ArrayWrapper<ExpressionType> >
   // Let's remove NestByRefBit
   enum {
     Flags0 = traits<typename remove_all<typename ExpressionType::Nested>::type >::Flags,
-    Flags = Flags0 & ~NestByRefBit
+    LvalueBitFlag = is_lvalue<ExpressionType>::value ? LvalueBit : 0,
+    Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag
   };
 };
 }
@@ -129,7 +130,8 @@ struct traits<MatrixWrapper<ExpressionType> >
   // Let's remove NestByRefBit
   enum {
     Flags0 = traits<typename remove_all<typename ExpressionType::Nested>::type >::Flags,
-    Flags = Flags0 & ~NestByRefBit
+    LvalueBitFlag = is_lvalue<ExpressionType>::value ? LvalueBit : 0,
+    Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag
   };
 };
 }
diff --git a/xs/src/eigen/Eigen/src/Core/AssignEvaluator.h b/xs/src/eigen/Eigen/src/Core/AssignEvaluator.h
index b0ec7b7ca..dbe435d86 100644
--- a/xs/src/eigen/Eigen/src/Core/AssignEvaluator.h
+++ b/xs/src/eigen/Eigen/src/Core/AssignEvaluator.h
@@ -39,7 +39,7 @@ public:
   enum {
     DstAlignment = DstEvaluator::Alignment,
     SrcAlignment = SrcEvaluator::Alignment,
-    DstHasDirectAccess = DstFlags & DirectAccessBit,
+    DstHasDirectAccess = (DstFlags & DirectAccessBit) == DirectAccessBit,
     JointAlignment = EIGEN_PLAIN_ENUM_MIN(DstAlignment,SrcAlignment)
   };
 
@@ -83,7 +83,7 @@ private:
                        && int(OuterStride)!=Dynamic && int(OuterStride)%int(InnerPacketSize)==0
                        && (EIGEN_UNALIGNED_VECTORIZE  || int(JointAlignment)>=int(InnerRequiredAlignment)),
     MayLinearize = bool(StorageOrdersAgree) && (int(DstFlags) & int(SrcFlags) & LinearAccessBit),
-    MayLinearVectorize = bool(MightVectorize) && MayLinearize && DstHasDirectAccess
+    MayLinearVectorize = bool(MightVectorize) && bool(MayLinearize) && bool(DstHasDirectAccess)
                        && (EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment)) || MaxSizeAtCompileTime == Dynamic),
       /* If the destination isn't aligned, we have to do runtime checks and we don't unroll,
          so it's only good for large enough sizes. */
diff --git a/xs/src/eigen/Eigen/src/Core/Assign_MKL.h b/xs/src/eigen/Eigen/src/Core/Assign_MKL.h
index 6c2ab9264..6866095bf 100644
--- a/xs/src/eigen/Eigen/src/Core/Assign_MKL.h
+++ b/xs/src/eigen/Eigen/src/Core/Assign_MKL.h
@@ -84,7 +84,8 @@ class vml_assign_traits
   struct Assignment<DstXprType, CwiseUnaryOp<scalar_##EIGENOP##_op<EIGENTYPE>, SrcXprNested>, assign_op<EIGENTYPE,EIGENTYPE>,   \
                    Dense2Dense, typename enable_if<vml_assign_traits<DstXprType,SrcXprNested>::EnableVml>::type> {              \
     typedef CwiseUnaryOp<scalar_##EIGENOP##_op<EIGENTYPE>, SrcXprNested> SrcXprType;                                            \
-    static void run(DstXprType &dst, const SrcXprType &src, const assign_op<EIGENTYPE,EIGENTYPE> &/*func*/) {                   \
+    static void run(DstXprType &dst, const SrcXprType &src, const assign_op<EIGENTYPE,EIGENTYPE> &func) {                       \
+      resize_if_allowed(dst, src, func);                                                                                        \
       eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols());                                                       \
       if(vml_assign_traits<DstXprType,SrcXprNested>::Traversal==LinearTraversal) {                                              \
         VMLOP(dst.size(), (const VMLTYPE*)src.nestedExpression().data(),                                                        \
@@ -144,7 +145,8 @@ EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(ceil,  Ceil,   _)
                    Dense2Dense, typename enable_if<vml_assign_traits<DstXprType,SrcXprNested>::EnableVml>::type> {            \
     typedef CwiseBinaryOp<scalar_##EIGENOP##_op<EIGENTYPE,EIGENTYPE>, SrcXprNested,                                           \
                     const CwiseNullaryOp<internal::scalar_constant_op<EIGENTYPE>,Plain> > SrcXprType;                         \
-    static void run(DstXprType &dst, const SrcXprType &src, const assign_op<EIGENTYPE,EIGENTYPE> &/*func*/) {                 \
+    static void run(DstXprType &dst, const SrcXprType &src, const assign_op<EIGENTYPE,EIGENTYPE> &func) {                     \
+      resize_if_allowed(dst, src, func);                                                                                      \
       eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols());                                                     \
       VMLTYPE exponent = reinterpret_cast<const VMLTYPE&>(src.rhs().functor().m_other);                                       \
       if(vml_assign_traits<DstXprType,SrcXprNested>::Traversal==LinearTraversal)                                              \
diff --git a/xs/src/eigen/Eigen/src/Core/CoreEvaluators.h b/xs/src/eigen/Eigen/src/Core/CoreEvaluators.h
index f7c1effca..910889efa 100644
--- a/xs/src/eigen/Eigen/src/Core/CoreEvaluators.h
+++ b/xs/src/eigen/Eigen/src/Core/CoreEvaluators.h
@@ -977,7 +977,7 @@ struct evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel> >
     OuterStrideAtCompileTime = HasSameStorageOrderAsArgType
                              ? int(outer_stride_at_compile_time<ArgType>::ret)
                              : int(inner_stride_at_compile_time<ArgType>::ret),
-    MaskPacketAccessBit = (InnerStrideAtCompileTime == 1) ? PacketAccessBit : 0,
+    MaskPacketAccessBit = (InnerStrideAtCompileTime == 1 || HasSameStorageOrderAsArgType) ? PacketAccessBit : 0,
     
     FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (evaluator<ArgType>::Flags&LinearAccessBit))) ? LinearAccessBit : 0,    
     FlagsRowMajorBit = XprType::Flags&RowMajorBit,
@@ -987,7 +987,9 @@ struct evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel> >
     Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit,
     
     PacketAlignment = unpacket_traits<PacketScalar>::alignment,
-    Alignment0 = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % int(PacketAlignment)) == 0)) ? int(PacketAlignment) : 0,
+    Alignment0 = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic)
+                             && (OuterStrideAtCompileTime!=0)
+                             && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % int(PacketAlignment)) == 0)) ? int(PacketAlignment) : 0,
     Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator<ArgType>::Alignment, Alignment0)
   };
   typedef block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel> block_evaluator_type;
@@ -1018,14 +1020,16 @@ struct unary_evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>, IndexBa
   EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& block)
     : m_argImpl(block.nestedExpression()), 
       m_startRow(block.startRow()), 
-      m_startCol(block.startCol()) 
+      m_startCol(block.startCol()),
+      m_linear_offset(InnerPanel?(XprType::IsRowMajor ? block.startRow()*block.cols() : block.startCol()*block.rows()):0)
   { }
  
   typedef typename XprType::Scalar Scalar;
   typedef typename XprType::CoeffReturnType CoeffReturnType;
 
   enum {
-    RowsAtCompileTime = XprType::RowsAtCompileTime
+    RowsAtCompileTime = XprType::RowsAtCompileTime,
+    ForwardLinearAccess = InnerPanel && bool(evaluator<ArgType>::Flags&LinearAccessBit)
   };
  
   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
@@ -1037,7 +1041,10 @@ struct unary_evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>, IndexBa
   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
   CoeffReturnType coeff(Index index) const
   { 
-    return coeff(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0);
+    if (ForwardLinearAccess)
+      return m_argImpl.coeff(m_linear_offset.value() + index); 
+    else
+      return coeff(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0);
   }
 
   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
@@ -1049,7 +1056,10 @@ struct unary_evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>, IndexBa
   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
   Scalar& coeffRef(Index index)
   { 
-    return coeffRef(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0);
+    if (ForwardLinearAccess)
+      return m_argImpl.coeffRef(m_linear_offset.value() + index); 
+    else
+      return coeffRef(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0);
   }
  
   template<int LoadMode, typename PacketType>
@@ -1063,8 +1073,11 @@ struct unary_evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>, IndexBa
   EIGEN_STRONG_INLINE
   PacketType packet(Index index) const 
   { 
-    return packet<LoadMode,PacketType>(RowsAtCompileTime == 1 ? 0 : index,
-                                       RowsAtCompileTime == 1 ? index : 0);
+    if (ForwardLinearAccess)
+      return m_argImpl.template packet<LoadMode,PacketType>(m_linear_offset.value() + index);
+    else
+      return packet<LoadMode,PacketType>(RowsAtCompileTime == 1 ? 0 : index,
+                                         RowsAtCompileTime == 1 ? index : 0);
   }
   
   template<int StoreMode, typename PacketType>
@@ -1078,15 +1091,19 @@ struct unary_evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>, IndexBa
   EIGEN_STRONG_INLINE
   void writePacket(Index index, const PacketType& x) 
   {
-    return writePacket<StoreMode,PacketType>(RowsAtCompileTime == 1 ? 0 : index,
-                                             RowsAtCompileTime == 1 ? index : 0,
-                                             x);
+    if (ForwardLinearAccess)
+      return m_argImpl.template writePacket<StoreMode,PacketType>(m_linear_offset.value() + index, x);
+    else
+      return writePacket<StoreMode,PacketType>(RowsAtCompileTime == 1 ? 0 : index,
+                                              RowsAtCompileTime == 1 ? index : 0,
+                                              x);
   }
  
 protected:
   evaluator<ArgType> m_argImpl;
   const variable_if_dynamic<Index, (ArgType::RowsAtCompileTime == 1 && BlockRows==1) ? 0 : Dynamic> m_startRow;
   const variable_if_dynamic<Index, (ArgType::ColsAtCompileTime == 1 && BlockCols==1) ? 0 : Dynamic> m_startCol;
+  const variable_if_dynamic<Index, InnerPanel ? Dynamic : 0> m_linear_offset;
 };
 
 // TODO: This evaluator does not actually use the child evaluator; 
diff --git a/xs/src/eigen/Eigen/src/Core/CwiseNullaryOp.h b/xs/src/eigen/Eigen/src/Core/CwiseNullaryOp.h
index dd498f758..ddd607e38 100644
--- a/xs/src/eigen/Eigen/src/Core/CwiseNullaryOp.h
+++ b/xs/src/eigen/Eigen/src/Core/CwiseNullaryOp.h
@@ -105,7 +105,7 @@ class CwiseNullaryOp : public internal::dense_xpr_base< CwiseNullaryOp<NullaryOp
   */
 template<typename Derived>
 template<typename CustomNullaryOp>
-EIGEN_STRONG_INLINE const CwiseNullaryOp<CustomNullaryOp, typename DenseBase<Derived>::PlainObject>
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseNullaryOp<CustomNullaryOp, typename DenseBase<Derived>::PlainObject>
 DenseBase<Derived>::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func)
 {
   return CwiseNullaryOp<CustomNullaryOp, PlainObject>(rows, cols, func);
@@ -150,7 +150,7 @@ DenseBase<Derived>::NullaryExpr(Index size, const CustomNullaryOp& func)
   */
 template<typename Derived>
 template<typename CustomNullaryOp>
-EIGEN_STRONG_INLINE const CwiseNullaryOp<CustomNullaryOp, typename DenseBase<Derived>::PlainObject>
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseNullaryOp<CustomNullaryOp, typename DenseBase<Derived>::PlainObject>
 DenseBase<Derived>::NullaryExpr(const CustomNullaryOp& func)
 {
   return CwiseNullaryOp<CustomNullaryOp, PlainObject>(RowsAtCompileTime, ColsAtCompileTime, func);
@@ -192,7 +192,7 @@ DenseBase<Derived>::Constant(Index rows, Index cols, const Scalar& value)
   * \sa class CwiseNullaryOp
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
 DenseBase<Derived>::Constant(Index size, const Scalar& value)
 {
   return DenseBase<Derived>::NullaryExpr(size, internal::scalar_constant_op<Scalar>(value));
@@ -208,7 +208,7 @@ DenseBase<Derived>::Constant(Index size, const Scalar& value)
   * \sa class CwiseNullaryOp
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
 DenseBase<Derived>::Constant(const Scalar& value)
 {
   EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived)
@@ -220,7 +220,7 @@ DenseBase<Derived>::Constant(const Scalar& value)
   * \sa LinSpaced(Index,Scalar,Scalar), setLinSpaced(Index,const Scalar&,const Scalar&)
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
 DenseBase<Derived>::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high)
 {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
@@ -232,7 +232,7 @@ DenseBase<Derived>::LinSpaced(Sequential_t, Index size, const Scalar& low, const
   * \sa LinSpaced(Scalar,Scalar)
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
 DenseBase<Derived>::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high)
 {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
@@ -264,7 +264,7 @@ DenseBase<Derived>::LinSpaced(Sequential_t, const Scalar& low, const Scalar& hig
   * \sa setLinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
 DenseBase<Derived>::LinSpaced(Index size, const Scalar& low, const Scalar& high)
 {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
@@ -276,7 +276,7 @@ DenseBase<Derived>::LinSpaced(Index size, const Scalar& low, const Scalar& high)
   * Special version for fixed size types which does not require the size parameter.
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::RandomAccessLinSpacedReturnType
 DenseBase<Derived>::LinSpaced(const Scalar& low, const Scalar& high)
 {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
@@ -286,7 +286,7 @@ DenseBase<Derived>::LinSpaced(const Scalar& low, const Scalar& high)
 
 /** \returns true if all coefficients in this matrix are approximately equal to \a val, to within precision \a prec */
 template<typename Derived>
-bool DenseBase<Derived>::isApproxToConstant
+EIGEN_DEVICE_FUNC bool DenseBase<Derived>::isApproxToConstant
 (const Scalar& val, const RealScalar& prec) const
 {
   typename internal::nested_eval<Derived,1>::type self(derived());
@@ -301,7 +301,7 @@ bool DenseBase<Derived>::isApproxToConstant
   *
   * \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */
 template<typename Derived>
-bool DenseBase<Derived>::isConstant
+EIGEN_DEVICE_FUNC bool DenseBase<Derived>::isConstant
 (const Scalar& val, const RealScalar& prec) const
 {
   return isApproxToConstant(val, prec);
@@ -312,7 +312,7 @@ bool DenseBase<Derived>::isConstant
   * \sa setConstant(), Constant(), class CwiseNullaryOp
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE void DenseBase<Derived>::fill(const Scalar& val)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void DenseBase<Derived>::fill(const Scalar& val)
 {
   setConstant(val);
 }
@@ -322,7 +322,7 @@ EIGEN_STRONG_INLINE void DenseBase<Derived>::fill(const Scalar& val)
   * \sa fill(), setConstant(Index,const Scalar&), setConstant(Index,Index,const Scalar&), setZero(), setOnes(), Constant(), class CwiseNullaryOp, setZero(), setOnes()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setConstant(const Scalar& val)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setConstant(const Scalar& val)
 {
   return derived() = Constant(rows(), cols(), val);
 }
@@ -337,7 +337,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setConstant(const Scalar& val)
   * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&)
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived&
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived&
 PlainObjectBase<Derived>::setConstant(Index size, const Scalar& val)
 {
   resize(size);
@@ -356,7 +356,7 @@ PlainObjectBase<Derived>::setConstant(Index size, const Scalar& val)
   * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&)
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived&
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived&
 PlainObjectBase<Derived>::setConstant(Index rows, Index cols, const Scalar& val)
 {
   resize(rows, cols);
@@ -380,7 +380,7 @@ PlainObjectBase<Derived>::setConstant(Index rows, Index cols, const Scalar& val)
   * \sa LinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high)
 {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
   return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op<Scalar,PacketScalar>(low,high,newSize));
@@ -400,7 +400,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setLinSpaced(Index newSize, con
   * \sa LinSpaced(Index,const Scalar&,const Scalar&), setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setLinSpaced(const Scalar& low, const Scalar& high)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setLinSpaced(const Scalar& low, const Scalar& high)
 {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
   return setLinSpaced(size(), low, high);
@@ -423,7 +423,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setLinSpaced(const Scalar& low,
   * \sa Zero(), Zero(Index)
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
 DenseBase<Derived>::Zero(Index rows, Index cols)
 {
   return Constant(rows, cols, Scalar(0));
@@ -446,7 +446,7 @@ DenseBase<Derived>::Zero(Index rows, Index cols)
   * \sa Zero(), Zero(Index,Index)
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
 DenseBase<Derived>::Zero(Index size)
 {
   return Constant(size, Scalar(0));
@@ -463,7 +463,7 @@ DenseBase<Derived>::Zero(Index size)
   * \sa Zero(Index), Zero(Index,Index)
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
 DenseBase<Derived>::Zero()
 {
   return Constant(Scalar(0));
@@ -478,7 +478,7 @@ DenseBase<Derived>::Zero()
   * \sa class CwiseNullaryOp, Zero()
   */
 template<typename Derived>
-bool DenseBase<Derived>::isZero(const RealScalar& prec) const
+EIGEN_DEVICE_FUNC bool DenseBase<Derived>::isZero(const RealScalar& prec) const
 {
   typename internal::nested_eval<Derived,1>::type self(derived());
   for(Index j = 0; j < cols(); ++j)
@@ -496,7 +496,7 @@ bool DenseBase<Derived>::isZero(const RealScalar& prec) const
   * \sa class CwiseNullaryOp, Zero()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setZero()
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setZero()
 {
   return setConstant(Scalar(0));
 }
@@ -511,7 +511,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setZero()
   * \sa DenseBase::setZero(), setZero(Index,Index), class CwiseNullaryOp, DenseBase::Zero()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived&
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived&
 PlainObjectBase<Derived>::setZero(Index newSize)
 {
   resize(newSize);
@@ -529,7 +529,7 @@ PlainObjectBase<Derived>::setZero(Index newSize)
   * \sa DenseBase::setZero(), setZero(Index), class CwiseNullaryOp, DenseBase::Zero()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived&
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived&
 PlainObjectBase<Derived>::setZero(Index rows, Index cols)
 {
   resize(rows, cols);
@@ -553,7 +553,7 @@ PlainObjectBase<Derived>::setZero(Index rows, Index cols)
   * \sa Ones(), Ones(Index), isOnes(), class Ones
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
 DenseBase<Derived>::Ones(Index rows, Index cols)
 {
   return Constant(rows, cols, Scalar(1));
@@ -576,7 +576,7 @@ DenseBase<Derived>::Ones(Index rows, Index cols)
   * \sa Ones(), Ones(Index,Index), isOnes(), class Ones
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
 DenseBase<Derived>::Ones(Index newSize)
 {
   return Constant(newSize, Scalar(1));
@@ -593,7 +593,7 @@ DenseBase<Derived>::Ones(Index newSize)
   * \sa Ones(Index), Ones(Index,Index), isOnes(), class Ones
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase<Derived>::ConstantReturnType
 DenseBase<Derived>::Ones()
 {
   return Constant(Scalar(1));
@@ -608,7 +608,7 @@ DenseBase<Derived>::Ones()
   * \sa class CwiseNullaryOp, Ones()
   */
 template<typename Derived>
-bool DenseBase<Derived>::isOnes
+EIGEN_DEVICE_FUNC bool DenseBase<Derived>::isOnes
 (const RealScalar& prec) const
 {
   return isApproxToConstant(Scalar(1), prec);
@@ -622,7 +622,7 @@ bool DenseBase<Derived>::isOnes
   * \sa class CwiseNullaryOp, Ones()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setOnes()
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setOnes()
 {
   return setConstant(Scalar(1));
 }
@@ -637,7 +637,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::setOnes()
   * \sa MatrixBase::setOnes(), setOnes(Index,Index), class CwiseNullaryOp, MatrixBase::Ones()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived&
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived&
 PlainObjectBase<Derived>::setOnes(Index newSize)
 {
   resize(newSize);
@@ -655,7 +655,7 @@ PlainObjectBase<Derived>::setOnes(Index newSize)
   * \sa MatrixBase::setOnes(), setOnes(Index), class CwiseNullaryOp, MatrixBase::Ones()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived&
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived&
 PlainObjectBase<Derived>::setOnes(Index rows, Index cols)
 {
   resize(rows, cols);
@@ -679,7 +679,7 @@ PlainObjectBase<Derived>::setOnes(Index rows, Index cols)
   * \sa Identity(), setIdentity(), isIdentity()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::IdentityReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::IdentityReturnType
 MatrixBase<Derived>::Identity(Index rows, Index cols)
 {
   return DenseBase<Derived>::NullaryExpr(rows, cols, internal::scalar_identity_op<Scalar>());
@@ -696,7 +696,7 @@ MatrixBase<Derived>::Identity(Index rows, Index cols)
   * \sa Identity(Index,Index), setIdentity(), isIdentity()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::IdentityReturnType
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::IdentityReturnType
 MatrixBase<Derived>::Identity()
 {
   EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived)
@@ -771,7 +771,7 @@ struct setIdentity_impl<Derived, true>
   * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), isIdentity()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::setIdentity()
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::setIdentity()
 {
   return internal::setIdentity_impl<Derived>::run(derived());
 }
@@ -787,7 +787,7 @@ EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::setIdentity()
   * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::setIdentity(Index rows, Index cols)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::setIdentity(Index rows, Index cols)
 {
   derived().resize(rows, cols);
   return setIdentity();
@@ -800,7 +800,7 @@ EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::setIdentity(Index rows, Index
   * \sa MatrixBase::Unit(Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::Unit(Index newSize, Index i)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::Unit(Index newSize, Index i)
 {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
   return BasisReturnType(SquareMatrixType::Identity(newSize,newSize), i);
@@ -815,7 +815,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBa
   * \sa MatrixBase::Unit(Index,Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::Unit(Index i)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::Unit(Index i)
 {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
   return BasisReturnType(SquareMatrixType::Identity(),i);
@@ -828,7 +828,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBa
   * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitX()
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitX()
 { return Derived::Unit(0); }
 
 /** \returns an expression of the Y axis unit vector (0,1{,0}^*)
@@ -838,7 +838,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBa
   * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitY()
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitY()
 { return Derived::Unit(1); }
 
 /** \returns an expression of the Z axis unit vector (0,0,1{,0}^*)
@@ -848,7 +848,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBa
   * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitZ()
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitZ()
 { return Derived::Unit(2); }
 
 /** \returns an expression of the W axis unit vector (0,0,0,1)
@@ -858,7 +858,7 @@ EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBa
   * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW()
   */
 template<typename Derived>
-EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitW()
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::BasisReturnType MatrixBase<Derived>::UnitW()
 { return Derived::Unit(3); }
 
 } // end namespace Eigen
diff --git a/xs/src/eigen/Eigen/src/Core/DenseBase.h b/xs/src/eigen/Eigen/src/Core/DenseBase.h
index 46fe5193c..90066ae73 100644
--- a/xs/src/eigen/Eigen/src/Core/DenseBase.h
+++ b/xs/src/eigen/Eigen/src/Core/DenseBase.h
@@ -296,7 +296,7 @@ template<typename Derived> class DenseBase
     EIGEN_DEVICE_FUNC
     Derived& operator=(const ReturnByValue<OtherDerived>& func);
 
-    /** \ínternal
+    /** \internal
       * Copies \a other into *this without evaluating other. \returns a reference to *this.
       * \deprecated */
     template<typename OtherDerived>
@@ -484,9 +484,9 @@ template<typename Derived> class DenseBase
       return derived().coeff(0,0);
     }
 
-    bool all() const;
-    bool any() const;
-    Index count() const;
+    EIGEN_DEVICE_FUNC bool all() const;
+    EIGEN_DEVICE_FUNC bool any() const;
+    EIGEN_DEVICE_FUNC Index count() const;
 
     typedef VectorwiseOp<Derived, Horizontal> RowwiseReturnType;
     typedef const VectorwiseOp<const Derived, Horizontal> ConstRowwiseReturnType;
diff --git a/xs/src/eigen/Eigen/src/Core/Diagonal.h b/xs/src/eigen/Eigen/src/Core/Diagonal.h
index 49e711257..afcaf3575 100644
--- a/xs/src/eigen/Eigen/src/Core/Diagonal.h
+++ b/xs/src/eigen/Eigen/src/Core/Diagonal.h
@@ -70,7 +70,10 @@ template<typename MatrixType, int _DiagIndex> class Diagonal
     EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal)
 
     EIGEN_DEVICE_FUNC
-    explicit inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {}
+    explicit inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index)
+    {
+      eigen_assert( a_index <= m_matrix.cols() && -a_index <= m_matrix.rows() );
+    }
 
     EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal)
 
diff --git a/xs/src/eigen/Eigen/src/Core/Dot.h b/xs/src/eigen/Eigen/src/Core/Dot.h
index 06ef18b8b..1fe7a84a4 100644
--- a/xs/src/eigen/Eigen/src/Core/Dot.h
+++ b/xs/src/eigen/Eigen/src/Core/Dot.h
@@ -31,7 +31,8 @@ struct dot_nocheck
   typedef scalar_conj_product_op<typename traits<T>::Scalar,typename traits<U>::Scalar> conj_prod;
   typedef typename conj_prod::result_type ResScalar;
   EIGEN_DEVICE_FUNC
-  static inline ResScalar run(const MatrixBase<T>& a, const MatrixBase<U>& b)
+  EIGEN_STRONG_INLINE
+  static ResScalar run(const MatrixBase<T>& a, const MatrixBase<U>& b)
   {
     return a.template binaryExpr<conj_prod>(b).sum();
   }
@@ -43,7 +44,8 @@ struct dot_nocheck<T, U, true>
   typedef scalar_conj_product_op<typename traits<T>::Scalar,typename traits<U>::Scalar> conj_prod;
   typedef typename conj_prod::result_type ResScalar;
   EIGEN_DEVICE_FUNC
-  static inline ResScalar run(const MatrixBase<T>& a, const MatrixBase<U>& b)
+  EIGEN_STRONG_INLINE
+  static ResScalar run(const MatrixBase<T>& a, const MatrixBase<U>& b)
   {
     return a.transpose().template binaryExpr<conj_prod>(b).sum();
   }
@@ -65,6 +67,7 @@ struct dot_nocheck<T, U, true>
 template<typename Derived>
 template<typename OtherDerived>
 EIGEN_DEVICE_FUNC
+EIGEN_STRONG_INLINE
 typename ScalarBinaryOpTraits<typename internal::traits<Derived>::Scalar,typename internal::traits<OtherDerived>::Scalar>::ReturnType
 MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const
 {
@@ -102,7 +105,7 @@ EIGEN_STRONG_INLINE typename NumTraits<typename internal::traits<Derived>::Scala
   * \sa lpNorm(), dot(), squaredNorm()
   */
 template<typename Derived>
-inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real MatrixBase<Derived>::norm() const
+EIGEN_STRONG_INLINE typename NumTraits<typename internal::traits<Derived>::Scalar>::Real MatrixBase<Derived>::norm() const
 {
   return numext::sqrt(squaredNorm());
 }
@@ -117,7 +120,7 @@ inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real Matr
   * \sa norm(), normalize()
   */
 template<typename Derived>
-inline const typename MatrixBase<Derived>::PlainObject
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::PlainObject
 MatrixBase<Derived>::normalized() const
 {
   typedef typename internal::nested_eval<Derived,2>::type _Nested;
@@ -139,7 +142,7 @@ MatrixBase<Derived>::normalized() const
   * \sa norm(), normalized()
   */
 template<typename Derived>
-inline void MatrixBase<Derived>::normalize()
+EIGEN_STRONG_INLINE void MatrixBase<Derived>::normalize()
 {
   RealScalar z = squaredNorm();
   // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU
@@ -160,7 +163,7 @@ inline void MatrixBase<Derived>::normalize()
   * \sa stableNorm(), stableNormalize(), normalized()
   */
 template<typename Derived>
-inline const typename MatrixBase<Derived>::PlainObject
+EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::PlainObject
 MatrixBase<Derived>::stableNormalized() const
 {
   typedef typename internal::nested_eval<Derived,3>::type _Nested;
@@ -185,7 +188,7 @@ MatrixBase<Derived>::stableNormalized() const
   * \sa stableNorm(), stableNormalized(), normalize()
   */
 template<typename Derived>
-inline void MatrixBase<Derived>::stableNormalize()
+EIGEN_STRONG_INLINE void MatrixBase<Derived>::stableNormalize()
 {
   RealScalar w = cwiseAbs().maxCoeff();
   RealScalar z = (derived()/w).squaredNorm();
diff --git a/xs/src/eigen/Eigen/src/Core/EigenBase.h b/xs/src/eigen/Eigen/src/Core/EigenBase.h
index f76995af9..b195506a9 100644
--- a/xs/src/eigen/Eigen/src/Core/EigenBase.h
+++ b/xs/src/eigen/Eigen/src/Core/EigenBase.h
@@ -14,6 +14,7 @@
 namespace Eigen {
 
 /** \class EigenBase
+  * \ingroup Core_Module
   * 
   * Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T).
   *
@@ -128,6 +129,7 @@ template<typename Derived> struct EigenBase
   */
 template<typename Derived>
 template<typename OtherDerived>
+EIGEN_DEVICE_FUNC
 Derived& DenseBase<Derived>::operator=(const EigenBase<OtherDerived> &other)
 {
   call_assignment(derived(), other.derived());
@@ -136,6 +138,7 @@ Derived& DenseBase<Derived>::operator=(const EigenBase<OtherDerived> &other)
 
 template<typename Derived>
 template<typename OtherDerived>
+EIGEN_DEVICE_FUNC
 Derived& DenseBase<Derived>::operator+=(const EigenBase<OtherDerived> &other)
 {
   call_assignment(derived(), other.derived(), internal::add_assign_op<Scalar,typename OtherDerived::Scalar>());
@@ -144,6 +147,7 @@ Derived& DenseBase<Derived>::operator+=(const EigenBase<OtherDerived> &other)
 
 template<typename Derived>
 template<typename OtherDerived>
+EIGEN_DEVICE_FUNC
 Derived& DenseBase<Derived>::operator-=(const EigenBase<OtherDerived> &other)
 {
   call_assignment(derived(), other.derived(), internal::sub_assign_op<Scalar,typename OtherDerived::Scalar>());
diff --git a/xs/src/eigen/Eigen/src/Core/GeneralProduct.h b/xs/src/eigen/Eigen/src/Core/GeneralProduct.h
index 0f16cd8e3..6f0cc80e9 100644
--- a/xs/src/eigen/Eigen/src/Core/GeneralProduct.h
+++ b/xs/src/eigen/Eigen/src/Core/GeneralProduct.h
@@ -24,12 +24,17 @@ template<int Rows, int Cols, int Depth> struct product_type_selector;
 
 template<int Size, int MaxSize> struct product_size_category
 {
-  enum { is_large = MaxSize == Dynamic ||
-                    Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD ||
-                    (Size==Dynamic && MaxSize>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD),
-         value = is_large  ? Large
-               : Size == 1 ? 1
-                           : Small
+  enum {
+    #ifndef EIGEN_CUDA_ARCH
+    is_large = MaxSize == Dynamic ||
+               Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD ||
+               (Size==Dynamic && MaxSize>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD),
+    #else
+    is_large = 0,
+    #endif
+    value = is_large  ? Large
+          : Size == 1 ? 1
+                      : Small
   };
 };
 
@@ -379,8 +384,6 @@ template<> struct gemv_dense_selector<OnTheRight,RowMajor,false>
   *
   * \sa lazyProduct(), operator*=(const MatrixBase&), Cwise::operator*()
   */
-#ifndef __CUDACC__
-
 template<typename Derived>
 template<typename OtherDerived>
 inline const Product<Derived, OtherDerived>
@@ -412,8 +415,6 @@ MatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &other) const
   return Product<Derived, OtherDerived>(derived(), other.derived());
 }
 
-#endif // __CUDACC__
-
 /** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation.
   *
   * The returned product will behave like any other expressions: the coefficients of the product will be
diff --git a/xs/src/eigen/Eigen/src/Core/GenericPacketMath.h b/xs/src/eigen/Eigen/src/Core/GenericPacketMath.h
index 27033a2dd..029f8ac36 100644
--- a/xs/src/eigen/Eigen/src/Core/GenericPacketMath.h
+++ b/xs/src/eigen/Eigen/src/Core/GenericPacketMath.h
@@ -230,7 +230,7 @@ pload1(const typename unpacket_traits<Packet>::type  *a) { return pset1<Packet>(
   * duplicated to form: {from[0],from[0],from[1],from[1],from[2],from[2],from[3],from[3]}
   * Currently, this function is only used for scalar * complex products.
   */
-template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
+template<typename Packet> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet
 ploaddup(const typename unpacket_traits<Packet>::type* from) { return *from; }
 
 /** \internal \returns a packet with elements of \a *from quadrupled.
@@ -278,7 +278,7 @@ inline void pbroadcast2(const typename unpacket_traits<Packet>::type *a,
 }
 
 /** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */
-template<typename Packet> inline Packet
+template<typename Packet> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet
 plset(const typename unpacket_traits<Packet>::type& a) { return a; }
 
 /** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */
@@ -482,7 +482,7 @@ EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void pstoret(Scalar* to, const Packet& fro
   * by the current computation.
   */
 template<typename Packet, int LoadMode>
-inline Packet ploadt_ro(const typename unpacket_traits<Packet>::type* from)
+EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet ploadt_ro(const typename unpacket_traits<Packet>::type* from)
 {
   return ploadt<Packet, LoadMode>(from);
 }
diff --git a/xs/src/eigen/Eigen/src/Core/Map.h b/xs/src/eigen/Eigen/src/Core/Map.h
index 06d196702..548bf9a2d 100644
--- a/xs/src/eigen/Eigen/src/Core/Map.h
+++ b/xs/src/eigen/Eigen/src/Core/Map.h
@@ -20,11 +20,17 @@ struct traits<Map<PlainObjectType, MapOptions, StrideType> >
 {
   typedef traits<PlainObjectType> TraitsBase;
   enum {
+    PlainObjectTypeInnerSize = ((traits<PlainObjectType>::Flags&RowMajorBit)==RowMajorBit)
+                             ? PlainObjectType::ColsAtCompileTime
+                             : PlainObjectType::RowsAtCompileTime,
+
     InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0
                              ? int(PlainObjectType::InnerStrideAtCompileTime)
                              : int(StrideType::InnerStrideAtCompileTime),
     OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0
-                             ? int(PlainObjectType::OuterStrideAtCompileTime)
+                             ? (InnerStrideAtCompileTime==Dynamic || PlainObjectTypeInnerSize==Dynamic
+                                ? Dynamic
+                                : int(InnerStrideAtCompileTime) * int(PlainObjectTypeInnerSize))
                              : int(StrideType::OuterStrideAtCompileTime),
     Alignment = int(MapOptions)&int(AlignedMask),
     Flags0 = TraitsBase::Flags & (~NestByRefBit),
@@ -107,10 +113,11 @@ template<typename PlainObjectType, int MapOptions, typename StrideType> class Ma
     EIGEN_DEVICE_FUNC
     inline Index outerStride() const
     {
-      return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer()
-           : IsVectorAtCompileTime ? this->size()
-           : int(Flags)&RowMajorBit ? this->cols()
-           : this->rows();
+      return int(StrideType::OuterStrideAtCompileTime) != 0 ? m_stride.outer()
+           : int(internal::traits<Map>::OuterStrideAtCompileTime) != Dynamic ? Index(internal::traits<Map>::OuterStrideAtCompileTime)
+           : IsVectorAtCompileTime ? (this->size() * innerStride())
+           : (int(Flags)&RowMajorBit) ? (this->cols() * innerStride())
+           : (this->rows() * innerStride());
     }
 
     /** Constructor in the fixed-size case.
diff --git a/xs/src/eigen/Eigen/src/Core/MathFunctions.h b/xs/src/eigen/Eigen/src/Core/MathFunctions.h
index 8d47fb8a4..6eb974d41 100644
--- a/xs/src/eigen/Eigen/src/Core/MathFunctions.h
+++ b/xs/src/eigen/Eigen/src/Core/MathFunctions.h
@@ -348,31 +348,7 @@ struct norm1_retval
 * Implementation of hypot                                                *
 ****************************************************************************/
 
-template<typename Scalar>
-struct hypot_impl
-{
-  typedef typename NumTraits<Scalar>::Real RealScalar;
-  static inline RealScalar run(const Scalar& x, const Scalar& y)
-  {
-    EIGEN_USING_STD_MATH(abs);
-    EIGEN_USING_STD_MATH(sqrt);
-    RealScalar _x = abs(x);
-    RealScalar _y = abs(y);
-    Scalar p, qp;
-    if(_x>_y)
-    {
-      p = _x;
-      qp = _y / p;
-    }
-    else
-    {
-      p = _y;
-      qp = _x / p;
-    }
-    if(p==RealScalar(0)) return RealScalar(0);
-    return p * sqrt(RealScalar(1) + qp*qp);
-  }
-};
+template<typename Scalar> struct hypot_impl;
 
 template<typename Scalar>
 struct hypot_retval
@@ -495,7 +471,7 @@ namespace std_fallback {
     typedef typename NumTraits<Scalar>::Real RealScalar;
     EIGEN_USING_STD_MATH(log);
     Scalar x1p = RealScalar(1) + x;
-    return ( x1p == Scalar(1) ) ? x : x * ( log(x1p) / (x1p - RealScalar(1)) );
+    return numext::equal_strict(x1p, Scalar(1)) ? x : x * ( log(x1p) / (x1p - RealScalar(1)) );
   }
 }
 
@@ -1061,11 +1037,24 @@ double log(const double &x) { return ::log(x); }
 
 template<typename T>
 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
-typename NumTraits<T>::Real abs(const T &x) {
+typename internal::enable_if<NumTraits<T>::IsSigned || NumTraits<T>::IsComplex,typename NumTraits<T>::Real>::type
+abs(const T &x) {
   EIGEN_USING_STD_MATH(abs);
   return abs(x);
 }
 
+template<typename T>
+EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
+typename internal::enable_if<!(NumTraits<T>::IsSigned || NumTraits<T>::IsComplex),typename NumTraits<T>::Real>::type
+abs(const T &x) {
+  return x;
+}
+
+#if defined(__SYCL_DEVICE_ONLY__)
+EIGEN_ALWAYS_INLINE float   abs(float x) { return cl::sycl::fabs(x); }
+EIGEN_ALWAYS_INLINE double  abs(double x) { return cl::sycl::fabs(x); }
+#endif // defined(__SYCL_DEVICE_ONLY__)
+
 #ifdef __CUDACC__
 template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
 float abs(const float &x) { return ::fabsf(x); }
diff --git a/xs/src/eigen/Eigen/src/Core/MathFunctionsImpl.h b/xs/src/eigen/Eigen/src/Core/MathFunctionsImpl.h
index 3c9ef22fa..9c1ceb0eb 100644
--- a/xs/src/eigen/Eigen/src/Core/MathFunctionsImpl.h
+++ b/xs/src/eigen/Eigen/src/Core/MathFunctionsImpl.h
@@ -71,6 +71,29 @@ T generic_fast_tanh_float(const T& a_x)
   return pdiv(p, q);
 }
 
+template<typename RealScalar>
+EIGEN_STRONG_INLINE
+RealScalar positive_real_hypot(const RealScalar& x, const RealScalar& y)
+{
+  EIGEN_USING_STD_MATH(sqrt);
+  RealScalar p, qp;
+  p = numext::maxi(x,y);
+  if(p==RealScalar(0)) return RealScalar(0);
+  qp = numext::mini(y,x) / p;    
+  return p * sqrt(RealScalar(1) + qp*qp);
+}
+
+template<typename Scalar>
+struct hypot_impl
+{
+  typedef typename NumTraits<Scalar>::Real RealScalar;
+  static inline RealScalar run(const Scalar& x, const Scalar& y)
+  {
+    EIGEN_USING_STD_MATH(abs);
+    return positive_real_hypot<RealScalar>(abs(x), abs(y));
+  }
+};
+
 } // end namespace internal
 
 } // end namespace Eigen
diff --git a/xs/src/eigen/Eigen/src/Core/MatrixBase.h b/xs/src/eigen/Eigen/src/Core/MatrixBase.h
index f7cf04cde..05db48813 100644
--- a/xs/src/eigen/Eigen/src/Core/MatrixBase.h
+++ b/xs/src/eigen/Eigen/src/Core/MatrixBase.h
@@ -160,20 +160,11 @@ template<typename Derived> class MatrixBase
     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
     Derived& operator-=(const MatrixBase<OtherDerived>& other);
 
-#ifdef __CUDACC__
     template<typename OtherDerived>
     EIGEN_DEVICE_FUNC
-    const Product<Derived,OtherDerived,LazyProduct>
-    operator*(const MatrixBase<OtherDerived> &other) const
-    { return this->lazyProduct(other); }
-#else
-
-    template<typename OtherDerived>
     const Product<Derived,OtherDerived>
     operator*(const MatrixBase<OtherDerived> &other) const;
 
-#endif
-
     template<typename OtherDerived>
     EIGEN_DEVICE_FUNC
     const Product<Derived,OtherDerived,LazyProduct>
@@ -294,7 +285,7 @@ template<typename Derived> class MatrixBase
       *          fuzzy comparison such as isApprox()
       * \sa isApprox(), operator!= */
     template<typename OtherDerived>
-    inline bool operator==(const MatrixBase<OtherDerived>& other) const
+    EIGEN_DEVICE_FUNC inline bool operator==(const MatrixBase<OtherDerived>& other) const
     { return cwiseEqual(other).all(); }
 
     /** \returns true if at least one pair of coefficients of \c *this and \a other are not exactly equal to each other.
@@ -302,7 +293,7 @@ template<typename Derived> class MatrixBase
       *          fuzzy comparison such as isApprox()
       * \sa isApprox(), operator== */
     template<typename OtherDerived>
-    inline bool operator!=(const MatrixBase<OtherDerived>& other) const
+    EIGEN_DEVICE_FUNC inline bool operator!=(const MatrixBase<OtherDerived>& other) const
     { return cwiseNotEqual(other).any(); }
 
     NoAlias<Derived,Eigen::MatrixBase > noalias();
diff --git a/xs/src/eigen/Eigen/src/Core/NumTraits.h b/xs/src/eigen/Eigen/src/Core/NumTraits.h
index dd61195bc..daf489878 100644
--- a/xs/src/eigen/Eigen/src/Core/NumTraits.h
+++ b/xs/src/eigen/Eigen/src/Core/NumTraits.h
@@ -215,6 +215,8 @@ struct NumTraits<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> >
   static inline RealScalar epsilon() { return NumTraits<RealScalar>::epsilon(); }
   EIGEN_DEVICE_FUNC
   static inline RealScalar dummy_precision() { return NumTraits<RealScalar>::dummy_precision(); }
+
+  static inline int digits10() { return NumTraits<Scalar>::digits10(); }
 };
 
 template<> struct NumTraits<std::string>
diff --git a/xs/src/eigen/Eigen/src/Core/PlainObjectBase.h b/xs/src/eigen/Eigen/src/Core/PlainObjectBase.h
index 77f4f6066..1dc7e223a 100644
--- a/xs/src/eigen/Eigen/src/Core/PlainObjectBase.h
+++ b/xs/src/eigen/Eigen/src/Core/PlainObjectBase.h
@@ -577,6 +577,10 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
       * while the AlignedMap() functions return aligned Map objects and thus should be called only with 16-byte-aligned
       * \a data pointers.
       *
+      * Here is an example using strides:
+      * \include Matrix_Map_stride.cpp
+      * Output: \verbinclude Matrix_Map_stride.out
+      *
       * \see class Map
       */
     //@{
diff --git a/xs/src/eigen/Eigen/src/Core/Product.h b/xs/src/eigen/Eigen/src/Core/Product.h
index ae0c94b38..676c48027 100644
--- a/xs/src/eigen/Eigen/src/Core/Product.h
+++ b/xs/src/eigen/Eigen/src/Core/Product.h
@@ -97,8 +97,8 @@ class Product : public ProductImpl<_Lhs,_Rhs,Option,
         && "if you wanted a coeff-wise or a dot product use the respective explicit functions");
     }
 
-    EIGEN_DEVICE_FUNC inline Index rows() const { return m_lhs.rows(); }
-    EIGEN_DEVICE_FUNC inline Index cols() const { return m_rhs.cols(); }
+    EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); }
+    EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); }
 
     EIGEN_DEVICE_FUNC const LhsNestedCleaned& lhs() const { return m_lhs; }
     EIGEN_DEVICE_FUNC const RhsNestedCleaned& rhs() const { return m_rhs; }
@@ -127,7 +127,7 @@ public:
   using Base::derived;
   typedef typename Base::Scalar Scalar;
   
-  operator const Scalar() const
+  EIGEN_STRONG_INLINE operator const Scalar() const
   {
     return internal::evaluator<ProductXpr>(derived()).coeff(0,0);
   }
@@ -162,7 +162,7 @@ class ProductImpl<Lhs,Rhs,Option,Dense>
     
   public:
   
-    EIGEN_DEVICE_FUNC Scalar coeff(Index row, Index col) const
+    EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col) const
     {
       EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS);
       eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) );
@@ -170,7 +170,7 @@ class ProductImpl<Lhs,Rhs,Option,Dense>
       return internal::evaluator<Derived>(derived()).coeff(row,col);
     }
 
-    EIGEN_DEVICE_FUNC Scalar coeff(Index i) const
+    EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index i) const
     {
       EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS);
       eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) );
diff --git a/xs/src/eigen/Eigen/src/Core/ProductEvaluators.h b/xs/src/eigen/Eigen/src/Core/ProductEvaluators.h
index 583b7f59e..9b99bd769 100644
--- a/xs/src/eigen/Eigen/src/Core/ProductEvaluators.h
+++ b/xs/src/eigen/Eigen/src/Core/ProductEvaluators.h
@@ -32,7 +32,7 @@ struct evaluator<Product<Lhs, Rhs, Options> >
   typedef Product<Lhs, Rhs, Options> XprType;
   typedef product_evaluator<XprType> Base;
   
-  EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {}
+  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {}
 };
  
 // Catch "scalar * ( A * B )" and transform it to "(A*scalar) * B"
@@ -55,7 +55,7 @@ struct evaluator<CwiseBinaryOp<internal::scalar_product_op<Scalar1,Scalar2>,
                                const Product<Lhs, Rhs, DefaultProduct> > XprType;
   typedef evaluator<Product<EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar1,Lhs,product), Rhs, DefaultProduct> > Base;
 
-  EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr)
+  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr)
     : Base(xpr.lhs().functor().m_other * xpr.rhs().lhs() * xpr.rhs().rhs())
   {}
 };
@@ -68,7 +68,7 @@ struct evaluator<Diagonal<const Product<Lhs, Rhs, DefaultProduct>, DiagIndex> >
   typedef Diagonal<const Product<Lhs, Rhs, DefaultProduct>, DiagIndex> XprType;
   typedef evaluator<Diagonal<const Product<Lhs, Rhs, LazyProduct>, DiagIndex> > Base;
   
-  EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr)
+  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr)
     : Base(Diagonal<const Product<Lhs, Rhs, LazyProduct>, DiagIndex>(
         Product<Lhs, Rhs, LazyProduct>(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()),
         xpr.index() ))
@@ -207,6 +207,12 @@ struct evaluator_assume_aliasing<CwiseBinaryOp<internal::scalar_sum_op<typename
   static const bool value = true;
 };
 
+template<typename OtherXpr, typename Lhs, typename Rhs>
+struct evaluator_assume_aliasing<CwiseBinaryOp<internal::scalar_difference_op<typename OtherXpr::Scalar,typename Product<Lhs,Rhs,DefaultProduct>::Scalar>, const OtherXpr,
+                                               const Product<Lhs,Rhs,DefaultProduct> >, DenseShape > {
+  static const bool value = true;
+};
+
 template<typename DstXprType, typename OtherXpr, typename ProductType, typename Func1, typename Func2>
 struct assignment_from_xpr_op_product
 {
@@ -240,19 +246,19 @@ template<typename Lhs, typename Rhs>
 struct generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,InnerProduct>
 {
   template<typename Dst>
-  static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
+  static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
   {
     dst.coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum();
   }
   
   template<typename Dst>
-  static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
+  static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
   {
     dst.coeffRef(0,0) += (lhs.transpose().cwiseProduct(rhs)).sum();
   }
   
   template<typename Dst>
-  static void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
+  static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
   { dst.coeffRef(0,0) -= (lhs.transpose().cwiseProduct(rhs)).sum(); }
 };
 
@@ -306,25 +312,25 @@ struct generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,OuterProduct>
   };
   
   template<typename Dst>
-  static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
+  static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
   {
     internal::outer_product_selector_run(dst, lhs, rhs, set(), is_row_major<Dst>());
   }
   
   template<typename Dst>
-  static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
+  static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
   {
     internal::outer_product_selector_run(dst, lhs, rhs, add(), is_row_major<Dst>());
   }
   
   template<typename Dst>
-  static inline void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
+  static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
   {
     internal::outer_product_selector_run(dst, lhs, rhs, sub(), is_row_major<Dst>());
   }
   
   template<typename Dst>
-  static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
+  static EIGEN_STRONG_INLINE void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
   {
     internal::outer_product_selector_run(dst, lhs, rhs, adds(alpha), is_row_major<Dst>());
   }
@@ -779,7 +785,11 @@ public:
     _Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagFlags)&PacketAccessBit))),
     _LinearAccessMask = (MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1) ? LinearAccessBit : 0,
     Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixFlags)) | (_Vectorizable ? PacketAccessBit : 0),
-    Alignment = evaluator<MatrixType>::Alignment
+    Alignment = evaluator<MatrixType>::Alignment,
+
+    AsScalarProduct =     (DiagonalType::SizeAtCompileTime==1)
+                      ||  (DiagonalType::SizeAtCompileTime==Dynamic && MatrixType::RowsAtCompileTime==1 && ProductOrder==OnTheLeft)
+                      ||  (DiagonalType::SizeAtCompileTime==Dynamic && MatrixType::ColsAtCompileTime==1 && ProductOrder==OnTheRight)
   };
   
   diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag)
@@ -791,7 +801,10 @@ public:
   
   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const
   {
-    return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx);
+    if(AsScalarProduct)
+      return m_diagImpl.coeff(0) * m_matImpl.coeff(idx);
+    else
+      return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx);
   }
   
 protected:
diff --git a/xs/src/eigen/Eigen/src/Core/Redux.h b/xs/src/eigen/Eigen/src/Core/Redux.h
index b6e8f8887..760e9f861 100644
--- a/xs/src/eigen/Eigen/src/Core/Redux.h
+++ b/xs/src/eigen/Eigen/src/Core/Redux.h
@@ -407,7 +407,7 @@ protected:
   */
 template<typename Derived>
 template<typename Func>
-typename internal::traits<Derived>::Scalar
+EIGEN_STRONG_INLINE typename internal::traits<Derived>::Scalar
 DenseBase<Derived>::redux(const Func& func) const
 {
   eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix");
diff --git a/xs/src/eigen/Eigen/src/Core/Ref.h b/xs/src/eigen/Eigen/src/Core/Ref.h
index bdf24f52a..9c6e3c5d9 100644
--- a/xs/src/eigen/Eigen/src/Core/Ref.h
+++ b/xs/src/eigen/Eigen/src/Core/Ref.h
@@ -95,6 +95,8 @@ protected:
   template<typename Expression>
   EIGEN_DEVICE_FUNC void construct(Expression& expr)
   {
+    EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(PlainObjectType,Expression);
+
     if(PlainObjectType::RowsAtCompileTime==1)
     {
       eigen_assert(expr.rows()==1 || expr.cols()==1);
diff --git a/xs/src/eigen/Eigen/src/Core/SelfAdjointView.h b/xs/src/eigen/Eigen/src/Core/SelfAdjointView.h
index 504c98f0e..b2e51f37a 100644
--- a/xs/src/eigen/Eigen/src/Core/SelfAdjointView.h
+++ b/xs/src/eigen/Eigen/src/Core/SelfAdjointView.h
@@ -71,7 +71,9 @@ template<typename _MatrixType, unsigned int UpLo> class SelfAdjointView
 
     EIGEN_DEVICE_FUNC
     explicit inline SelfAdjointView(MatrixType& matrix) : m_matrix(matrix)
-    {}
+    {
+      EIGEN_STATIC_ASSERT(UpLo==Lower || UpLo==Upper,SELFADJOINTVIEW_ACCEPTS_UPPER_AND_LOWER_MODE_ONLY);
+    }
 
     EIGEN_DEVICE_FUNC
     inline Index rows() const { return m_matrix.rows(); }
@@ -189,7 +191,7 @@ template<typename _MatrixType, unsigned int UpLo> class SelfAdjointView
                                    TriangularView<typename MatrixType::AdjointReturnType,TriMode> >::type(tmp2);
     }
 
-    typedef SelfAdjointView<const MatrixConjugateReturnType,Mode> ConjugateReturnType;
+    typedef SelfAdjointView<const MatrixConjugateReturnType,UpLo> ConjugateReturnType;
     /** \sa MatrixBase::conjugate() const */
     EIGEN_DEVICE_FUNC
     inline const ConjugateReturnType conjugate() const
diff --git a/xs/src/eigen/Eigen/src/Core/SelfCwiseBinaryOp.h b/xs/src/eigen/Eigen/src/Core/SelfCwiseBinaryOp.h
index 719ed72a5..7c89c2e23 100644
--- a/xs/src/eigen/Eigen/src/Core/SelfCwiseBinaryOp.h
+++ b/xs/src/eigen/Eigen/src/Core/SelfCwiseBinaryOp.h
@@ -15,33 +15,29 @@ namespace Eigen {
 // TODO generalize the scalar type of 'other'
 
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator*=(const Scalar& other)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator*=(const Scalar& other)
 {
-  typedef typename Derived::PlainObject PlainObject;
   internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::mul_assign_op<Scalar,Scalar>());
   return derived();
 }
 
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& ArrayBase<Derived>::operator+=(const Scalar& other)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& ArrayBase<Derived>::operator+=(const Scalar& other)
 {
-  typedef typename Derived::PlainObject PlainObject;
   internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::add_assign_op<Scalar,Scalar>());
   return derived();
 }
 
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& ArrayBase<Derived>::operator-=(const Scalar& other)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& ArrayBase<Derived>::operator-=(const Scalar& other)
 {
-  typedef typename Derived::PlainObject PlainObject;
   internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::sub_assign_op<Scalar,Scalar>());
   return derived();
 }
 
 template<typename Derived>
-EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator/=(const Scalar& other)
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator/=(const Scalar& other)
 {
-  typedef typename Derived::PlainObject PlainObject;
   internal::call_assignment(this->derived(), PlainObject::Constant(rows(),cols(),other), internal::div_assign_op<Scalar,Scalar>());
   return derived();
 }
diff --git a/xs/src/eigen/Eigen/src/Core/Solve.h b/xs/src/eigen/Eigen/src/Core/Solve.h
index 960a58597..a8daea511 100644
--- a/xs/src/eigen/Eigen/src/Core/Solve.h
+++ b/xs/src/eigen/Eigen/src/Core/Solve.h
@@ -34,12 +34,12 @@ template<typename Decomposition, typename RhsType,typename StorageKind> struct s
 template<typename Decomposition, typename RhsType>
 struct solve_traits<Decomposition,RhsType,Dense>
 {
-  typedef Matrix<typename RhsType::Scalar,
+  typedef typename make_proper_matrix_type<typename RhsType::Scalar,
                  Decomposition::ColsAtCompileTime,
                  RhsType::ColsAtCompileTime,
                  RhsType::PlainObject::Options,
                  Decomposition::MaxColsAtCompileTime,
-                 RhsType::MaxColsAtCompileTime> PlainObject;  
+                 RhsType::MaxColsAtCompileTime>::type PlainObject;
 };
 
 template<typename Decomposition, typename RhsType>
diff --git a/xs/src/eigen/Eigen/src/Core/StableNorm.h b/xs/src/eigen/Eigen/src/Core/StableNorm.h
index d2fe1e199..88c8d9890 100644
--- a/xs/src/eigen/Eigen/src/Core/StableNorm.h
+++ b/xs/src/eigen/Eigen/src/Core/StableNorm.h
@@ -165,12 +165,13 @@ MatrixBase<Derived>::stableNorm() const
   
   typedef typename internal::nested_eval<Derived,2>::type DerivedCopy;
   typedef typename internal::remove_all<DerivedCopy>::type DerivedCopyClean;
-  DerivedCopy copy(derived());
+  const DerivedCopy copy(derived());
   
   enum {
     CanAlign = (   (int(DerivedCopyClean::Flags)&DirectAccessBit)
                 || (int(internal::evaluator<DerivedCopyClean>::Alignment)>0) // FIXME Alignment)>0 might not be enough
-               ) && (blockSize*sizeof(Scalar)*2<EIGEN_STACK_ALLOCATION_LIMIT) // ifwe cannot allocate on the stack, then let's not bother about this optimization
+               ) && (blockSize*sizeof(Scalar)*2<EIGEN_STACK_ALLOCATION_LIMIT)
+                 && (EIGEN_MAX_STATIC_ALIGN_BYTES>0) // if we cannot allocate on the stack, then let's not bother about this optimization
   };
   typedef typename internal::conditional<CanAlign, Ref<const Matrix<Scalar,Dynamic,1,0,blockSize,1>, internal::evaluator<DerivedCopyClean>::Alignment>,
                                                    typename DerivedCopyClean::ConstSegmentReturnType>::type SegmentWrapper;
diff --git a/xs/src/eigen/Eigen/src/Core/Transpositions.h b/xs/src/eigen/Eigen/src/Core/Transpositions.h
index 19c17bb4a..86da5af59 100644
--- a/xs/src/eigen/Eigen/src/Core/Transpositions.h
+++ b/xs/src/eigen/Eigen/src/Core/Transpositions.h
@@ -384,7 +384,7 @@ class Transpose<TranspositionsBase<TranspositionsDerived> >
     const Product<OtherDerived, Transpose, AliasFreeProduct>
     operator*(const MatrixBase<OtherDerived>& matrix, const Transpose& trt)
     {
-      return Product<OtherDerived, Transpose, AliasFreeProduct>(matrix.derived(), trt.derived());
+      return Product<OtherDerived, Transpose, AliasFreeProduct>(matrix.derived(), trt);
     }
 
     /** \returns the \a matrix with the inverse transpositions applied to the rows.
diff --git a/xs/src/eigen/Eigen/src/Core/arch/AVX/Complex.h b/xs/src/eigen/Eigen/src/Core/arch/AVX/Complex.h
index 99439c8aa..7fa61969d 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/AVX/Complex.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/AVX/Complex.h
@@ -204,23 +204,7 @@ template<> struct conj_helper<Packet4cf, Packet4cf, true,true>
   }
 };
 
-template<> struct conj_helper<Packet8f, Packet4cf, false,false>
-{
-  EIGEN_STRONG_INLINE Packet4cf pmadd(const Packet8f& x, const Packet4cf& y, const Packet4cf& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet4cf pmul(const Packet8f& x, const Packet4cf& y) const
-  { return Packet4cf(Eigen::internal::pmul(x, y.v)); }
-};
-
-template<> struct conj_helper<Packet4cf, Packet8f, false,false>
-{
-  EIGEN_STRONG_INLINE Packet4cf pmadd(const Packet4cf& x, const Packet8f& y, const Packet4cf& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet4cf pmul(const Packet4cf& x, const Packet8f& y) const
-  { return Packet4cf(Eigen::internal::pmul(x.v, y)); }
-};
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet4cf,Packet8f)
 
 template<> EIGEN_STRONG_INLINE Packet4cf pdiv<Packet4cf>(const Packet4cf& a, const Packet4cf& b)
 {
@@ -400,23 +384,7 @@ template<> struct conj_helper<Packet2cd, Packet2cd, true,true>
   }
 };
 
-template<> struct conj_helper<Packet4d, Packet2cd, false,false>
-{
-  EIGEN_STRONG_INLINE Packet2cd pmadd(const Packet4d& x, const Packet2cd& y, const Packet2cd& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet2cd pmul(const Packet4d& x, const Packet2cd& y) const
-  { return Packet2cd(Eigen::internal::pmul(x, y.v)); }
-};
-
-template<> struct conj_helper<Packet2cd, Packet4d, false,false>
-{
-  EIGEN_STRONG_INLINE Packet2cd pmadd(const Packet2cd& x, const Packet4d& y, const Packet2cd& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet2cd pmul(const Packet2cd& x, const Packet4d& y) const
-  { return Packet2cd(Eigen::internal::pmul(x.v, y)); }
-};
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet2cd,Packet4d)
 
 template<> EIGEN_STRONG_INLINE Packet2cd pdiv<Packet2cd>(const Packet2cd& a, const Packet2cd& b)
 {
diff --git a/xs/src/eigen/Eigen/src/Core/arch/AVX/PacketMath.h b/xs/src/eigen/Eigen/src/Core/arch/AVX/PacketMath.h
index 195d40fb4..61c3dfcab 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/AVX/PacketMath.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/AVX/PacketMath.h
@@ -308,9 +308,9 @@ template<> EIGEN_STRONG_INLINE void pstore1<Packet8i>(int* to, const int& a)
 }
 
 #ifndef EIGEN_VECTORIZE_AVX512
-template<> EIGEN_STRONG_INLINE void prefetch<float>(const float*   addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
-template<> EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
-template<> EIGEN_STRONG_INLINE void prefetch<int>(const int*       addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<float>(const float*   addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<int>(const int*       addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
 #endif
 
 template<> EIGEN_STRONG_INLINE float  pfirst<Packet8f>(const Packet8f& a) {
@@ -333,9 +333,12 @@ template<> EIGEN_STRONG_INLINE Packet4d preverse(const Packet4d& a)
 {
    __m256d tmp = _mm256_shuffle_pd(a,a,5);
   return _mm256_permute2f128_pd(tmp, tmp, 1);
-
+  #if 0
+  // This version is unlikely to be faster as _mm256_shuffle_ps and _mm256_permute_pd
+  // exhibit the same latency/throughput, but it is here for future reference/benchmarking...
   __m256d swap_halves = _mm256_permute2f128_pd(a,a,1);
     return _mm256_permute_pd(swap_halves,5);
+  #endif
 }
 
 // pabs should be ok
diff --git a/xs/src/eigen/Eigen/src/Core/arch/AVX512/MathFunctions.h b/xs/src/eigen/Eigen/src/Core/arch/AVX512/MathFunctions.h
index 399be0ee4..9c1717f76 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/AVX512/MathFunctions.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/AVX512/MathFunctions.h
@@ -88,9 +88,9 @@ plog<Packet16f>(const Packet16f& _x) {
   //     x = x + x - 1.0;
   //   } else { x = x - 1.0; }
   __mmask16 mask = _mm512_cmp_ps_mask(x, p16f_cephes_SQRTHF, _CMP_LT_OQ);
-  Packet16f tmp = _mm512_mask_blend_ps(mask, x, _mm512_setzero_ps());
+  Packet16f tmp = _mm512_mask_blend_ps(mask, _mm512_setzero_ps(), x);
   x = psub(x, p16f_1);
-  e = psub(e, _mm512_mask_blend_ps(mask, p16f_1, _mm512_setzero_ps()));
+  e = psub(e, _mm512_mask_blend_ps(mask, _mm512_setzero_ps(), p16f_1));
   x = padd(x, tmp);
 
   Packet16f x2 = pmul(x, x);
@@ -119,8 +119,9 @@ plog<Packet16f>(const Packet16f& _x) {
   x = padd(x, y2);
 
   // Filter out invalid inputs, i.e. negative arg will be NAN, 0 will be -INF.
-  return _mm512_mask_blend_ps(iszero_mask, p16f_minus_inf,
-                              _mm512_mask_blend_ps(invalid_mask, p16f_nan, x));
+  return _mm512_mask_blend_ps(iszero_mask,
+                              _mm512_mask_blend_ps(invalid_mask, x, p16f_nan),
+                              p16f_minus_inf);
 }
 #endif
 
@@ -266,8 +267,7 @@ psqrt<Packet16f>(const Packet16f& _x) {
   // select only the inverse sqrt of positive normal inputs (denormals are
   // flushed to zero and cause infs as well).
   __mmask16 non_zero_mask = _mm512_cmp_ps_mask(_x, p16f_flt_min, _CMP_GE_OQ);
-  Packet16f x = _mm512_mask_blend_ps(non_zero_mask, _mm512_rsqrt14_ps(_x),
-                                     _mm512_setzero_ps());
+  Packet16f x = _mm512_mask_blend_ps(non_zero_mask, _mm512_setzero_ps(), _mm512_rsqrt14_ps(_x));
 
   // Do a single step of Newton's iteration.
   x = pmul(x, pmadd(neg_half, pmul(x, x), p16f_one_point_five));
@@ -289,8 +289,7 @@ psqrt<Packet8d>(const Packet8d& _x) {
   // select only the inverse sqrt of positive normal inputs (denormals are
   // flushed to zero and cause infs as well).
   __mmask8 non_zero_mask = _mm512_cmp_pd_mask(_x, p8d_dbl_min, _CMP_GE_OQ);
-  Packet8d x = _mm512_mask_blend_pd(non_zero_mask, _mm512_rsqrt14_pd(_x),
-                                    _mm512_setzero_pd());
+  Packet8d x = _mm512_mask_blend_pd(non_zero_mask, _mm512_setzero_pd(), _mm512_rsqrt14_pd(_x));
 
   // Do a first step of Newton's iteration.
   x = pmul(x, pmadd(neg_half, pmul(x, x), p8d_one_point_five));
@@ -333,20 +332,18 @@ prsqrt<Packet16f>(const Packet16f& _x) {
   // select only the inverse sqrt of positive normal inputs (denormals are
   // flushed to zero and cause infs as well).
   __mmask16 le_zero_mask = _mm512_cmp_ps_mask(_x, p16f_flt_min, _CMP_LT_OQ);
-  Packet16f x = _mm512_mask_blend_ps(le_zero_mask, _mm512_setzero_ps(),
-                                     _mm512_rsqrt14_ps(_x));
+  Packet16f x = _mm512_mask_blend_ps(le_zero_mask, _mm512_rsqrt14_ps(_x), _mm512_setzero_ps());
 
   // Fill in NaNs and Infs for the negative/zero entries.
   __mmask16 neg_mask = _mm512_cmp_ps_mask(_x, _mm512_setzero_ps(), _CMP_LT_OQ);
   Packet16f infs_and_nans = _mm512_mask_blend_ps(
-      neg_mask, p16f_nan,
-      _mm512_mask_blend_ps(le_zero_mask, p16f_inf, _mm512_setzero_ps()));
+      neg_mask, _mm512_mask_blend_ps(le_zero_mask, _mm512_setzero_ps(), p16f_inf), p16f_nan);
 
   // Do a single step of Newton's iteration.
   x = pmul(x, pmadd(neg_half, pmul(x, x), p16f_one_point_five));
 
   // Insert NaNs and Infs in all the right places.
-  return _mm512_mask_blend_ps(le_zero_mask, infs_and_nans, x);
+  return _mm512_mask_blend_ps(le_zero_mask, x, infs_and_nans);
 }
 
 template <>
@@ -363,14 +360,12 @@ prsqrt<Packet8d>(const Packet8d& _x) {
   // select only the inverse sqrt of positive normal inputs (denormals are
   // flushed to zero and cause infs as well).
   __mmask8 le_zero_mask = _mm512_cmp_pd_mask(_x, p8d_dbl_min, _CMP_LT_OQ);
-  Packet8d x = _mm512_mask_blend_pd(le_zero_mask, _mm512_setzero_pd(),
-                                    _mm512_rsqrt14_pd(_x));
+  Packet8d x = _mm512_mask_blend_pd(le_zero_mask, _mm512_rsqrt14_pd(_x), _mm512_setzero_pd());
 
   // Fill in NaNs and Infs for the negative/zero entries.
   __mmask8 neg_mask = _mm512_cmp_pd_mask(_x, _mm512_setzero_pd(), _CMP_LT_OQ);
   Packet8d infs_and_nans = _mm512_mask_blend_pd(
-      neg_mask, p8d_nan,
-      _mm512_mask_blend_pd(le_zero_mask, p8d_inf, _mm512_setzero_pd()));
+      neg_mask, _mm512_mask_blend_pd(le_zero_mask, _mm512_setzero_pd(), p8d_inf), p8d_nan);
 
   // Do a first step of Newton's iteration.
   x = pmul(x, pmadd(neg_half, pmul(x, x), p8d_one_point_five));
@@ -379,9 +374,9 @@ prsqrt<Packet8d>(const Packet8d& _x) {
   x = pmul(x, pmadd(neg_half, pmul(x, x), p8d_one_point_five));
 
   // Insert NaNs and Infs in all the right places.
-  return _mm512_mask_blend_pd(le_zero_mask, infs_and_nans, x);
+  return _mm512_mask_blend_pd(le_zero_mask, x, infs_and_nans);
 }
-#else
+#elif defined(EIGEN_VECTORIZE_AVX512ER)
 template <>
 EIGEN_STRONG_INLINE Packet16f prsqrt<Packet16f>(const Packet16f& x) {
   return _mm512_rsqrt28_ps(x);
diff --git a/xs/src/eigen/Eigen/src/Core/arch/AVX512/PacketMath.h b/xs/src/eigen/Eigen/src/Core/arch/AVX512/PacketMath.h
index f6500a16e..89705248a 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/AVX512/PacketMath.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/AVX512/PacketMath.h
@@ -618,9 +618,9 @@ EIGEN_STRONG_INLINE void pstore1<Packet16i>(int* to, const int& a) {
   pstore(to, pa);
 }
 
-template<> EIGEN_STRONG_INLINE void prefetch<float>(const float*   addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
-template<> EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
-template<> EIGEN_STRONG_INLINE void prefetch<int>(const int*       addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<float>(const float*   addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<int>(const int*       addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
 
 template <>
 EIGEN_STRONG_INLINE float pfirst<Packet16f>(const Packet16f& a) {
diff --git a/xs/src/eigen/Eigen/src/Core/arch/AltiVec/Complex.h b/xs/src/eigen/Eigen/src/Core/arch/AltiVec/Complex.h
index 67db2f8ee..3e665730c 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/AltiVec/Complex.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/AltiVec/Complex.h
@@ -224,23 +224,7 @@ template<> struct conj_helper<Packet2cf, Packet2cf, true,true>
   }
 };
 
-template<> struct conj_helper<Packet4f, Packet2cf, false,false>
-{
-  EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet4f& x, const Packet2cf& y, const Packet2cf& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet2cf pmul(const Packet4f& x, const Packet2cf& y) const
-  { return Packet2cf(internal::pmul<Packet4f>(x, y.v)); }
-};
-
-template<> struct conj_helper<Packet2cf, Packet4f, false,false>
-{
-  EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet4f& y, const Packet2cf& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& x, const Packet4f& y) const
-  { return Packet2cf(internal::pmul<Packet4f>(x.v, y)); }
-};
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet2cf,Packet4f)
 
 template<> EIGEN_STRONG_INLINE Packet2cf pdiv<Packet2cf>(const Packet2cf& a, const Packet2cf& b)
 {
@@ -416,23 +400,8 @@ template<> struct conj_helper<Packet1cd, Packet1cd, true,true>
     return pconj(internal::pmul(a, b));
   }
 };
-template<> struct conj_helper<Packet2d, Packet1cd, false,false>
-{
-  EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet2d& x, const Packet1cd& y, const Packet1cd& c) const
-  { return padd(c, pmul(x,y)); }
 
-  EIGEN_STRONG_INLINE Packet1cd pmul(const Packet2d& x, const Packet1cd& y) const
-  { return Packet1cd(internal::pmul<Packet2d>(x, y.v)); }
-};
-
-template<> struct conj_helper<Packet1cd, Packet2d, false,false>
-{
-  EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet2d& y, const Packet1cd& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& x, const Packet2d& y) const
-  { return Packet1cd(internal::pmul<Packet2d>(x.v, y)); }
-};
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet1cd,Packet2d)
 
 template<> EIGEN_STRONG_INLINE Packet1cd pdiv<Packet1cd>(const Packet1cd& a, const Packet1cd& b)
 {
diff --git a/xs/src/eigen/Eigen/src/Core/arch/AltiVec/PacketMath.h b/xs/src/eigen/Eigen/src/Core/arch/AltiVec/PacketMath.h
index b3f1ea199..08a27d153 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/AltiVec/PacketMath.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/AltiVec/PacketMath.h
@@ -103,7 +103,7 @@ static Packet16uc p16uc_PSET32_WODD   = vec_sld((Packet16uc) vec_splat((Packet4u
 static Packet16uc p16uc_PSET32_WEVEN  = vec_sld(p16uc_DUPLICATE32_HI, (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 };
 static Packet16uc p16uc_HALF64_0_16 = vec_sld((Packet16uc)p4i_ZERO, vec_splat((Packet16uc) vec_abs(p4i_MINUS16), 3), 8);      //{ 0,0,0,0, 0,0,0,0, 16,16,16,16, 16,16,16,16};
 #else
-static Packet16uc p16uc_FORWARD = p16uc_REVERSE32; 
+static Packet16uc p16uc_FORWARD = p16uc_REVERSE32;
 static Packet16uc p16uc_REVERSE64 = { 8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7 };
 static Packet16uc p16uc_PSET32_WODD = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 1), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 3), 8);//{ 0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11 };
 static Packet16uc p16uc_PSET32_WEVEN = vec_sld((Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 0), (Packet16uc) vec_splat((Packet4ui)p16uc_FORWARD, 2), 8);//{ 4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15 };
@@ -388,10 +388,28 @@ template<> EIGEN_STRONG_INLINE Packet4i pdiv<Packet4i>(const Packet4i& /*a*/, co
 template<> EIGEN_STRONG_INLINE Packet4f pmadd(const Packet4f& a, const Packet4f& b, const Packet4f& c) { return vec_madd(a,b,c); }
 template<> EIGEN_STRONG_INLINE Packet4i pmadd(const Packet4i& a, const Packet4i& b, const Packet4i& c) { return a*b + c; }
 
-template<> EIGEN_STRONG_INLINE Packet4f pmin<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_min(a, b); }
+template<> EIGEN_STRONG_INLINE Packet4f pmin<Packet4f>(const Packet4f& a, const Packet4f& b)
+{
+  #ifdef __VSX__
+  Packet4f ret;
+  __asm__ ("xvcmpgesp %x0,%x1,%x2\n\txxsel %x0,%x1,%x2,%x0" : "=&wa" (ret) : "wa" (a), "wa" (b));
+  return ret;
+  #else
+  return vec_min(a, b);
+  #endif
+}
 template<> EIGEN_STRONG_INLINE Packet4i pmin<Packet4i>(const Packet4i& a, const Packet4i& b) { return vec_min(a, b); }
 
-template<> EIGEN_STRONG_INLINE Packet4f pmax<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_max(a, b); }
+template<> EIGEN_STRONG_INLINE Packet4f pmax<Packet4f>(const Packet4f& a, const Packet4f& b)
+{
+  #ifdef __VSX__
+  Packet4f ret;
+  __asm__ ("xvcmpgtsp %x0,%x2,%x1\n\txxsel %x0,%x1,%x2,%x0" : "=&wa" (ret) : "wa" (a), "wa" (b));
+  return ret;
+  #else
+  return vec_max(a, b);
+  #endif
+}
 template<> EIGEN_STRONG_INLINE Packet4i pmax<Packet4i>(const Packet4i& a, const Packet4i& b) { return vec_max(a, b); }
 
 template<> EIGEN_STRONG_INLINE Packet4f pand<Packet4f>(const Packet4f& a, const Packet4f& b) { return vec_and(a, b); }
@@ -764,7 +782,7 @@ typedef __vector __bool long         Packet2bl;
 
 static Packet2l  p2l_ONE  = { 1, 1 };
 static Packet2l  p2l_ZERO = reinterpret_cast<Packet2l>(p4i_ZERO);
-static Packet2d  p2d_ONE  = { 1.0, 1.0 }; 
+static Packet2d  p2d_ONE  = { 1.0, 1.0 };
 static Packet2d  p2d_ZERO = reinterpret_cast<Packet2d>(p4f_ZERO);
 static Packet2d  p2d_MZERO = { -0.0, -0.0 };
 
@@ -910,9 +928,19 @@ template<> EIGEN_STRONG_INLINE Packet2d pdiv<Packet2d>(const Packet2d& a, const
 // for some weird raisons, it has to be overloaded for packet of integers
 template<> EIGEN_STRONG_INLINE Packet2d pmadd(const Packet2d& a, const Packet2d& b, const Packet2d& c) { return vec_madd(a, b, c); }
 
-template<> EIGEN_STRONG_INLINE Packet2d pmin<Packet2d>(const Packet2d& a, const Packet2d& b) { return vec_min(a, b); }
+template<> EIGEN_STRONG_INLINE Packet2d pmin<Packet2d>(const Packet2d& a, const Packet2d& b)
+{
+  Packet2d ret;
+  __asm__ ("xvcmpgedp %x0,%x1,%x2\n\txxsel %x0,%x1,%x2,%x0" : "=&wa" (ret) : "wa" (a), "wa" (b));
+  return ret;
+ }
 
-template<> EIGEN_STRONG_INLINE Packet2d pmax<Packet2d>(const Packet2d& a, const Packet2d& b) { return vec_max(a, b); }
+template<> EIGEN_STRONG_INLINE Packet2d pmax<Packet2d>(const Packet2d& a, const Packet2d& b)
+{
+  Packet2d ret;
+  __asm__ ("xvcmpgtdp %x0,%x2,%x1\n\txxsel %x0,%x1,%x2,%x0" : "=&wa" (ret) : "wa" (a), "wa" (b));
+  return ret;
+}
 
 template<> EIGEN_STRONG_INLINE Packet2d pand<Packet2d>(const Packet2d& a, const Packet2d& b) { return vec_and(a, b); }
 
@@ -969,7 +997,7 @@ template<> EIGEN_STRONG_INLINE Packet2d preduxp<Packet2d>(const Packet2d* vecs)
   Packet2d v[2], sum;
   v[0] = vecs[0] + reinterpret_cast<Packet2d>(vec_sld(reinterpret_cast<Packet4f>(vecs[0]), reinterpret_cast<Packet4f>(vecs[0]), 8));
   v[1] = vecs[1] + reinterpret_cast<Packet2d>(vec_sld(reinterpret_cast<Packet4f>(vecs[1]), reinterpret_cast<Packet4f>(vecs[1]), 8));
- 
+
 #ifdef _BIG_ENDIAN
   sum = reinterpret_cast<Packet2d>(vec_sld(reinterpret_cast<Packet4f>(v[0]), reinterpret_cast<Packet4f>(v[1]), 8));
 #else
@@ -1022,7 +1050,7 @@ ptranspose(PacketBlock<Packet2d,2>& kernel) {
 
 template<> EIGEN_STRONG_INLINE Packet2d pblend(const Selector<2>& ifPacket, const Packet2d& thenPacket, const Packet2d& elsePacket) {
   Packet2l select = { ifPacket.select[0], ifPacket.select[1] };
-  Packet2bl mask = vec_cmpeq(reinterpret_cast<Packet2d>(select), reinterpret_cast<Packet2d>(p2l_ONE));
+  Packet2bl mask = reinterpret_cast<Packet2bl>( vec_cmpeq(reinterpret_cast<Packet2d>(select), reinterpret_cast<Packet2d>(p2l_ONE)) );
   return vec_sel(elsePacket, thenPacket, mask);
 }
 #endif // __VSX__
diff --git a/xs/src/eigen/Eigen/src/Core/arch/CUDA/Half.h b/xs/src/eigen/Eigen/src/Core/arch/CUDA/Half.h
index 52892db38..02ac0c23a 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/CUDA/Half.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/CUDA/Half.h
@@ -13,7 +13,7 @@
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted.
 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
@@ -147,55 +147,55 @@ namespace half_impl {
 // versions to get the ALU speed increased), but you do save the
 // conversion steps back and forth.
 
-__device__ half operator + (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ half operator + (const half& a, const half& b) {
   return __hadd(a, b);
 }
-__device__ half operator * (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ half operator * (const half& a, const half& b) {
   return __hmul(a, b);
 }
-__device__ half operator - (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ half operator - (const half& a, const half& b) {
   return __hsub(a, b);
 }
-__device__ half operator / (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ half operator / (const half& a, const half& b) {
   float num = __half2float(a);
   float denom = __half2float(b);
   return __float2half(num / denom);
 }
-__device__ half operator - (const half& a) {
+EIGEN_STRONG_INLINE __device__ half operator - (const half& a) {
   return __hneg(a);
 }
-__device__ half& operator += (half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ half& operator += (half& a, const half& b) {
   a = a + b;
   return a;
 }
-__device__ half& operator *= (half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ half& operator *= (half& a, const half& b) {
   a = a * b;
   return a;
 }
-__device__ half& operator -= (half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ half& operator -= (half& a, const half& b) {
   a = a - b;
   return a;
 }
-__device__ half& operator /= (half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ half& operator /= (half& a, const half& b) {
   a = a / b;
   return a;
 }
-__device__ bool operator == (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ bool operator == (const half& a, const half& b) {
   return __heq(a, b);
 }
-__device__ bool operator != (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ bool operator != (const half& a, const half& b) {
   return __hne(a, b);
 }
-__device__ bool operator < (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ bool operator < (const half& a, const half& b) {
   return __hlt(a, b);
 }
-__device__ bool operator <= (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ bool operator <= (const half& a, const half& b) {
   return __hle(a, b);
 }
-__device__ bool operator > (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ bool operator > (const half& a, const half& b) {
   return __hgt(a, b);
 }
-__device__ bool operator >= (const half& a, const half& b) {
+EIGEN_STRONG_INLINE __device__ bool operator >= (const half& a, const half& b) {
   return __hge(a, b);
 }
 
@@ -238,10 +238,10 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half& operator /= (half& a, const half& b)
   return a;
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator == (const half& a, const half& b) {
-  return float(a) == float(b);
+  return numext::equal_strict(float(a),float(b));
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator != (const half& a, const half& b) {
-  return float(a) != float(b);
+  return numext::not_equal_strict(float(a), float(b));
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator < (const half& a, const half& b) {
   return float(a) < float(b);
@@ -386,11 +386,15 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half abs(const half& a) {
   return result;
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half exp(const half& a) {
-  return half(::expf(float(a)));
+#if EIGEN_CUDACC_VER >= 80000 && defined EIGEN_CUDA_ARCH && EIGEN_CUDA_ARCH >= 530
+  return half(hexp(a));
+#else
+   return half(::expf(float(a)));
+#endif
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half log(const half& a) {
-#if defined(EIGEN_HAS_CUDA_FP16) && defined __CUDACC_VER__ && __CUDACC_VER__ >= 80000 && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
-  return Eigen::half(::hlog(a));
+#if defined(EIGEN_HAS_CUDA_FP16) && EIGEN_CUDACC_VER >= 80000 && defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 530
+  return half(::hlog(a));
 #else
   return half(::logf(float(a)));
 #endif
@@ -402,7 +406,11 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half log10(const half& a) {
   return half(::log10f(float(a)));
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half sqrt(const half& a) {
-  return half(::sqrtf(float(a)));
+#if EIGEN_CUDACC_VER >= 80000 && defined EIGEN_CUDA_ARCH && EIGEN_CUDA_ARCH >= 530
+  return half(hsqrt(a));
+#else
+    return half(::sqrtf(float(a)));
+#endif
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half pow(const half& a, const half& b) {
   return half(::powf(float(a), float(b)));
@@ -420,10 +428,18 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half tanh(const half& a) {
   return half(::tanhf(float(a)));
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half floor(const half& a) {
+#if EIGEN_CUDACC_VER >= 80000 && defined EIGEN_CUDA_ARCH && EIGEN_CUDA_ARCH >= 300
+  return half(hfloor(a));
+#else
   return half(::floorf(float(a)));
+#endif
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half ceil(const half& a) {
+#if EIGEN_CUDACC_VER >= 80000 && defined EIGEN_CUDA_ARCH && EIGEN_CUDA_ARCH >= 300
+  return half(hceil(a));
+#else
   return half(::ceilf(float(a)));
+#endif
 }
 
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half (min)(const half& a, const half& b) {
@@ -474,9 +490,59 @@ template<> struct is_arithmetic<half> { enum { value = true }; };
 
 } // end namespace internal
 
+}  // end namespace Eigen
+
+namespace std {
+template<>
+struct numeric_limits<Eigen::half> {
+  static const bool is_specialized = true;
+  static const bool is_signed = true;
+  static const bool is_integer = false;
+  static const bool is_exact = false;
+  static const bool has_infinity = true;
+  static const bool has_quiet_NaN = true;
+  static const bool has_signaling_NaN = true;
+  static const float_denorm_style has_denorm = denorm_present;
+  static const bool has_denorm_loss = false;
+  static const std::float_round_style round_style = std::round_to_nearest;
+  static const bool is_iec559 = false;
+  static const bool is_bounded = false;
+  static const bool is_modulo = false;
+  static const int digits = 11;
+  static const int digits10 = 3;      // according to http://half.sourceforge.net/structstd_1_1numeric__limits_3_01half__float_1_1half_01_4.html
+  static const int max_digits10 = 5;  // according to http://half.sourceforge.net/structstd_1_1numeric__limits_3_01half__float_1_1half_01_4.html
+  static const int radix = 2;
+  static const int min_exponent = -13;
+  static const int min_exponent10 = -4;
+  static const int max_exponent = 16;
+  static const int max_exponent10 = 4;
+  static const bool traps = true;
+  static const bool tinyness_before = false;
+
+  static Eigen::half (min)() { return Eigen::half_impl::raw_uint16_to_half(0x400); }
+  static Eigen::half lowest() { return Eigen::half_impl::raw_uint16_to_half(0xfbff); }
+  static Eigen::half (max)() { return Eigen::half_impl::raw_uint16_to_half(0x7bff); }
+  static Eigen::half epsilon() { return Eigen::half_impl::raw_uint16_to_half(0x0800); }
+  static Eigen::half round_error() { return Eigen::half(0.5); }
+  static Eigen::half infinity() { return Eigen::half_impl::raw_uint16_to_half(0x7c00); }
+  static Eigen::half quiet_NaN() { return Eigen::half_impl::raw_uint16_to_half(0x7e00); }
+  static Eigen::half signaling_NaN() { return Eigen::half_impl::raw_uint16_to_half(0x7e00); }
+  static Eigen::half denorm_min() { return Eigen::half_impl::raw_uint16_to_half(0x1); }
+};
+}
+
+namespace Eigen {
+
 template<> struct NumTraits<Eigen::half>
     : GenericNumTraits<Eigen::half>
 {
+  enum {
+    IsSigned = true,
+    IsInteger = false,
+    IsComplex = false,
+    RequireInitialization = false
+  };
+
   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Eigen::half epsilon() {
     return half_impl::raw_uint16_to_half(0x0800);
   }
@@ -507,7 +573,7 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half exph(const Eigen::half& a) {
   return Eigen::half(::expf(float(a)));
 }
 EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Eigen::half logh(const Eigen::half& a) {
-#if defined __CUDACC_VER__ && __CUDACC_VER__ >= 80000 && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+#if EIGEN_CUDACC_VER >= 80000 && defined(EIGEN_CUDA_ARCH) && EIGEN_CUDA_ARCH >= 530
   return Eigen::half(::hlog(a));
 #else
   return Eigen::half(::logf(float(a)));
diff --git a/xs/src/eigen/Eigen/src/Core/arch/CUDA/PacketMath.h b/xs/src/eigen/Eigen/src/Core/arch/CUDA/PacketMath.h
index ad66399e0..4dda63188 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/CUDA/PacketMath.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/CUDA/PacketMath.h
@@ -291,7 +291,7 @@ template<> EIGEN_DEVICE_FUNC inline double2 pabs<double2>(const double2& a) {
 
 EIGEN_DEVICE_FUNC inline void
 ptranspose(PacketBlock<float4,4>& kernel) {
-  double tmp = kernel.packet[0].y;
+  float tmp = kernel.packet[0].y;
   kernel.packet[0].y = kernel.packet[1].x;
   kernel.packet[1].x = tmp;
 
diff --git a/xs/src/eigen/Eigen/src/Core/arch/CUDA/PacketMathHalf.h b/xs/src/eigen/Eigen/src/Core/arch/CUDA/PacketMathHalf.h
index ae54225f8..943e0b06d 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/CUDA/PacketMathHalf.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/CUDA/PacketMathHalf.h
@@ -275,7 +275,7 @@ template<> __device__ EIGEN_STRONG_INLINE half2 plog1p<half2>(const half2& a) {
   return __floats2half2_rn(r1, r2);
 }
 
-#if defined __CUDACC_VER__ && __CUDACC_VER__ >= 80000 && defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 530
+#if EIGEN_CUDACC_VER >= 80000 && defined EIGEN_CUDA_ARCH && EIGEN_CUDA_ARCH >= 530
 
 template<>  __device__ EIGEN_STRONG_INLINE
 half2 plog<half2>(const half2& a) {
diff --git a/xs/src/eigen/Eigen/src/Core/arch/Default/ConjHelper.h b/xs/src/eigen/Eigen/src/Core/arch/Default/ConjHelper.h
new file mode 100644
index 000000000..4cfe34e05
--- /dev/null
+++ b/xs/src/eigen/Eigen/src/Core/arch/Default/ConjHelper.h
@@ -0,0 +1,29 @@
+
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2017 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_ARCH_CONJ_HELPER_H
+#define EIGEN_ARCH_CONJ_HELPER_H
+
+#define EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(PACKET_CPLX, PACKET_REAL)                                                          \
+  template<> struct conj_helper<PACKET_REAL, PACKET_CPLX, false,false> {                                          \
+    EIGEN_STRONG_INLINE PACKET_CPLX pmadd(const PACKET_REAL& x, const PACKET_CPLX& y, const PACKET_CPLX& c) const \
+    { return padd(c, pmul(x,y)); }                                                                                \
+    EIGEN_STRONG_INLINE PACKET_CPLX pmul(const PACKET_REAL& x, const PACKET_CPLX& y) const                        \
+    { return PACKET_CPLX(Eigen::internal::pmul<PACKET_REAL>(x, y.v)); }                                           \
+  };                                                                                                              \
+                                                                                                                  \
+  template<> struct conj_helper<PACKET_CPLX, PACKET_REAL, false,false> {                                          \
+    EIGEN_STRONG_INLINE PACKET_CPLX pmadd(const PACKET_CPLX& x, const PACKET_REAL& y, const PACKET_CPLX& c) const \
+    { return padd(c, pmul(x,y)); }                                                                                \
+    EIGEN_STRONG_INLINE PACKET_CPLX pmul(const PACKET_CPLX& x, const PACKET_REAL& y) const                        \
+    { return PACKET_CPLX(Eigen::internal::pmul<PACKET_REAL>(x.v, y)); }                                           \
+  };
+
+#endif // EIGEN_ARCH_CONJ_HELPER_H
diff --git a/xs/src/eigen/Eigen/src/Core/arch/NEON/Complex.h b/xs/src/eigen/Eigen/src/Core/arch/NEON/Complex.h
index 57e9b431f..306a309be 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/NEON/Complex.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/NEON/Complex.h
@@ -67,7 +67,7 @@ template<> struct unpacket_traits<Packet2cf> { typedef std::complex<float> type;
 template<> EIGEN_STRONG_INLINE Packet2cf pset1<Packet2cf>(const std::complex<float>&  from)
 {
   float32x2_t r64;
-  r64 = vld1_f32((float *)&from);
+  r64 = vld1_f32((const float *)&from);
 
   return Packet2cf(vcombine_f32(r64, r64));
 }
@@ -142,7 +142,7 @@ template<> EIGEN_DEVICE_FUNC inline void pscatter<std::complex<float>, Packet2cf
   to[stride*1] = std::complex<float>(vgetq_lane_f32(from.v, 2), vgetq_lane_f32(from.v, 3));
 }
 
-template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> *   addr) { EIGEN_ARM_PREFETCH((float *)addr); }
+template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> *   addr) { EIGEN_ARM_PREFETCH((const float *)addr); }
 
 template<> EIGEN_STRONG_INLINE std::complex<float>  pfirst<Packet2cf>(const Packet2cf& a)
 {
@@ -265,6 +265,8 @@ template<> struct conj_helper<Packet2cf, Packet2cf, true,true>
   }
 };
 
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet2cf,Packet4f)
+
 template<> EIGEN_STRONG_INLINE Packet2cf pdiv<Packet2cf>(const Packet2cf& a, const Packet2cf& b)
 {
   // TODO optimize it for NEON
@@ -275,7 +277,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf pdiv<Packet2cf>(const Packet2cf& a, con
   s = vmulq_f32(b.v, b.v);
   rev_s = vrev64q_f32(s);
 
-  return Packet2cf(pdiv(res.v, vaddq_f32(s,rev_s)));
+  return Packet2cf(pdiv<Packet4f>(res.v, vaddq_f32(s,rev_s)));
 }
 
 EIGEN_DEVICE_FUNC inline void
@@ -381,7 +383,7 @@ template<> EIGEN_STRONG_INLINE Packet1cd ploaddup<Packet1cd>(const std::complex<
 template<> EIGEN_STRONG_INLINE void pstore <std::complex<double> >(std::complex<double> *   to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); }
 template<> EIGEN_STRONG_INLINE void pstoreu<std::complex<double> >(std::complex<double> *   to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); }
 
-template<> EIGEN_STRONG_INLINE void prefetch<std::complex<double> >(const std::complex<double> *   addr) { EIGEN_ARM_PREFETCH((double *)addr); }
+template<> EIGEN_STRONG_INLINE void prefetch<std::complex<double> >(const std::complex<double> *   addr) { EIGEN_ARM_PREFETCH((const double *)addr); }
 
 template<> EIGEN_DEVICE_FUNC inline Packet1cd pgather<std::complex<double>, Packet1cd>(const std::complex<double>* from, Index stride)
 {
@@ -456,6 +458,8 @@ template<> struct conj_helper<Packet1cd, Packet1cd, true,true>
   }
 };
 
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet1cd,Packet2d)
+
 template<> EIGEN_STRONG_INLINE Packet1cd pdiv<Packet1cd>(const Packet1cd& a, const Packet1cd& b)
 {
   // TODO optimize it for NEON
diff --git a/xs/src/eigen/Eigen/src/Core/arch/NEON/PacketMath.h b/xs/src/eigen/Eigen/src/Core/arch/NEON/PacketMath.h
index 84a56bdcc..3d5ed0d24 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/NEON/PacketMath.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/NEON/PacketMath.h
@@ -36,12 +36,43 @@ namespace internal {
 #endif
 #endif
 
+#if EIGEN_COMP_MSVC
+
+// In MSVC's arm_neon.h header file, all NEON vector types
+// are aliases to the same underlying type __n128.
+// We thus have to wrap them to make them different C++ types.
+// (See also bug 1428)
+
+template<typename T,int unique_id>
+struct eigen_packet_wrapper
+{
+  operator T&() { return m_val; }
+  operator const T&() const { return m_val; }
+  eigen_packet_wrapper() {}
+  eigen_packet_wrapper(const T &v) : m_val(v) {}
+  eigen_packet_wrapper& operator=(const T &v) {
+    m_val = v;
+    return *this;
+  }
+
+  T m_val;
+};
+typedef eigen_packet_wrapper<float32x2_t,0> Packet2f;
+typedef eigen_packet_wrapper<float32x4_t,1> Packet4f;
+typedef eigen_packet_wrapper<int32x4_t  ,2> Packet4i;
+typedef eigen_packet_wrapper<int32x2_t  ,3> Packet2i;
+typedef eigen_packet_wrapper<uint32x4_t ,4> Packet4ui;
+
+#else
+
 typedef float32x2_t Packet2f;
 typedef float32x4_t Packet4f;
 typedef int32x4_t   Packet4i;
 typedef int32x2_t   Packet2i;
 typedef uint32x4_t  Packet4ui;
 
+#endif // EIGEN_COMP_MSVC
+
 #define _EIGEN_DECLARE_CONST_Packet4f(NAME,X) \
   const Packet4f p4f_##NAME = pset1<Packet4f>(X)
 
@@ -51,14 +82,17 @@ typedef uint32x4_t  Packet4ui;
 #define _EIGEN_DECLARE_CONST_Packet4i(NAME,X) \
   const Packet4i p4i_##NAME = pset1<Packet4i>(X)
 
-// arm64 does have the pld instruction. If available, let's trust the __builtin_prefetch built-in function
-// which available on LLVM and GCC (at least)
-#if EIGEN_HAS_BUILTIN(__builtin_prefetch) || EIGEN_COMP_GNUC
+#if EIGEN_ARCH_ARM64
+  // __builtin_prefetch tends to do nothing on ARM64 compilers because the
+  // prefetch instructions there are too detailed for __builtin_prefetch to map
+  // meaningfully to them.
+  #define EIGEN_ARM_PREFETCH(ADDR)  __asm__ __volatile__("prfm pldl1keep, [%[addr]]\n" ::[addr] "r"(ADDR) : );
+#elif EIGEN_HAS_BUILTIN(__builtin_prefetch) || EIGEN_COMP_GNUC
   #define EIGEN_ARM_PREFETCH(ADDR) __builtin_prefetch(ADDR);
 #elif defined __pld
   #define EIGEN_ARM_PREFETCH(ADDR) __pld(ADDR)
-#elif !EIGEN_ARCH_ARM64
-  #define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__ ( "   pld [%[addr]]\n" :: [addr] "r" (ADDR) : "cc" );
+#elif EIGEN_ARCH_ARM32
+  #define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__ ("pld [%[addr]]\n" :: [addr] "r" (ADDR) : );
 #else
   // by default no explicit prefetching
   #define EIGEN_ARM_PREFETCH(ADDR)
@@ -113,7 +147,7 @@ template<> EIGEN_STRONG_INLINE Packet4i pset1<Packet4i>(const int32_t&    from)
 
 template<> EIGEN_STRONG_INLINE Packet4f plset<Packet4f>(const float& a)
 {
-  const float32_t f[] = {0, 1, 2, 3};
+  const float f[] = {0, 1, 2, 3};
   Packet4f countdown = vld1q_f32(f);
   return vaddq_f32(pset1<Packet4f>(a), countdown);
 }
diff --git a/xs/src/eigen/Eigen/src/Core/arch/SSE/Complex.h b/xs/src/eigen/Eigen/src/Core/arch/SSE/Complex.h
index 5607fe0ab..d075043ce 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/SSE/Complex.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/SSE/Complex.h
@@ -128,7 +128,7 @@ template<> EIGEN_DEVICE_FUNC inline void pscatter<std::complex<float>, Packet2cf
                                      _mm_cvtss_f32(_mm_shuffle_ps(from.v, from.v, 3)));
 }
 
-template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> *   addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> *   addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
 
 template<> EIGEN_STRONG_INLINE std::complex<float>  pfirst<Packet2cf>(const Packet2cf& a)
 {
@@ -229,23 +229,7 @@ template<> struct conj_helper<Packet2cf, Packet2cf, true,true>
   }
 };
 
-template<> struct conj_helper<Packet4f, Packet2cf, false,false>
-{
-  EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet4f& x, const Packet2cf& y, const Packet2cf& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet2cf pmul(const Packet4f& x, const Packet2cf& y) const
-  { return Packet2cf(Eigen::internal::pmul<Packet4f>(x, y.v)); }
-};
-
-template<> struct conj_helper<Packet2cf, Packet4f, false,false>
-{
-  EIGEN_STRONG_INLINE Packet2cf pmadd(const Packet2cf& x, const Packet4f& y, const Packet2cf& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet2cf pmul(const Packet2cf& x, const Packet4f& y) const
-  { return Packet2cf(Eigen::internal::pmul<Packet4f>(x.v, y)); }
-};
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet2cf,Packet4f)
 
 template<> EIGEN_STRONG_INLINE Packet2cf pdiv<Packet2cf>(const Packet2cf& a, const Packet2cf& b)
 {
@@ -340,7 +324,7 @@ template<> EIGEN_STRONG_INLINE Packet1cd ploaddup<Packet1cd>(const std::complex<
 template<> EIGEN_STRONG_INLINE void pstore <std::complex<double> >(std::complex<double> *   to, const Packet1cd& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, Packet2d(from.v)); }
 template<> EIGEN_STRONG_INLINE void pstoreu<std::complex<double> >(std::complex<double> *   to, const Packet1cd& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, Packet2d(from.v)); }
 
-template<> EIGEN_STRONG_INLINE void prefetch<std::complex<double> >(const std::complex<double> *   addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<std::complex<double> >(const std::complex<double> *   addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
 
 template<> EIGEN_STRONG_INLINE std::complex<double>  pfirst<Packet1cd>(const Packet1cd& a)
 {
@@ -430,23 +414,7 @@ template<> struct conj_helper<Packet1cd, Packet1cd, true,true>
   }
 };
 
-template<> struct conj_helper<Packet2d, Packet1cd, false,false>
-{
-  EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet2d& x, const Packet1cd& y, const Packet1cd& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet1cd pmul(const Packet2d& x, const Packet1cd& y) const
-  { return Packet1cd(Eigen::internal::pmul<Packet2d>(x, y.v)); }
-};
-
-template<> struct conj_helper<Packet1cd, Packet2d, false,false>
-{
-  EIGEN_STRONG_INLINE Packet1cd pmadd(const Packet1cd& x, const Packet2d& y, const Packet1cd& c) const
-  { return padd(c, pmul(x,y)); }
-
-  EIGEN_STRONG_INLINE Packet1cd pmul(const Packet1cd& x, const Packet2d& y) const
-  { return Packet1cd(Eigen::internal::pmul<Packet2d>(x.v, y)); }
-};
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet1cd,Packet2d)
 
 template<> EIGEN_STRONG_INLINE Packet1cd pdiv<Packet1cd>(const Packet1cd& a, const Packet1cd& b)
 {
diff --git a/xs/src/eigen/Eigen/src/Core/arch/SSE/PacketMath.h b/xs/src/eigen/Eigen/src/Core/arch/SSE/PacketMath.h
index 3832de147..5e652cc79 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/SSE/PacketMath.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/SSE/PacketMath.h
@@ -409,10 +409,16 @@ template<> EIGEN_STRONG_INLINE void pstore1<Packet2d>(double* to, const double&
   pstore(to, Packet2d(vec2d_swizzle1(pa,0,0)));
 }
 
+#if EIGEN_COMP_PGI
+typedef const void * SsePrefetchPtrType;
+#else
+typedef const char * SsePrefetchPtrType;
+#endif
+
 #ifndef EIGEN_VECTORIZE_AVX
-template<> EIGEN_STRONG_INLINE void prefetch<float>(const float*   addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
-template<> EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
-template<> EIGEN_STRONG_INLINE void prefetch<int>(const int*       addr) { _mm_prefetch((const char*)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<float>(const float*   addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<double>(const double* addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
+template<> EIGEN_STRONG_INLINE void prefetch<int>(const int*       addr) { _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
 #endif
 
 #if EIGEN_COMP_MSVC_STRICT && EIGEN_OS_WIN64
@@ -876,4 +882,14 @@ template<> EIGEN_STRONG_INLINE double pmadd(const double& a, const double& b, co
 
 } // end namespace Eigen
 
+#if EIGEN_COMP_PGI
+// PGI++ does not define the following intrinsics in C++ mode.
+static inline __m128  _mm_castpd_ps   (__m128d x) { return reinterpret_cast<__m128&>(x);  }
+static inline __m128i _mm_castpd_si128(__m128d x) { return reinterpret_cast<__m128i&>(x); }
+static inline __m128d _mm_castps_pd   (__m128  x) { return reinterpret_cast<__m128d&>(x); }
+static inline __m128i _mm_castps_si128(__m128  x) { return reinterpret_cast<__m128i&>(x); }
+static inline __m128  _mm_castsi128_ps(__m128i x) { return reinterpret_cast<__m128&>(x);  }
+static inline __m128d _mm_castsi128_pd(__m128i x) { return reinterpret_cast<__m128d&>(x); }
+#endif
+
 #endif // EIGEN_PACKET_MATH_SSE_H
diff --git a/xs/src/eigen/Eigen/src/Core/arch/SSE/TypeCasting.h b/xs/src/eigen/Eigen/src/Core/arch/SSE/TypeCasting.h
index c84893230..c6ca8c716 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/SSE/TypeCasting.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/SSE/TypeCasting.h
@@ -14,6 +14,7 @@ namespace Eigen {
 
 namespace internal {
 
+#ifndef EIGEN_VECTORIZE_AVX
 template <>
 struct type_casting_traits<float, int> {
   enum {
@@ -23,11 +24,6 @@ struct type_casting_traits<float, int> {
   };
 };
 
-template<> EIGEN_STRONG_INLINE Packet4i pcast<Packet4f, Packet4i>(const Packet4f& a) {
-  return _mm_cvttps_epi32(a);
-}
-
-
 template <>
 struct type_casting_traits<int, float> {
   enum {
@@ -37,11 +33,6 @@ struct type_casting_traits<int, float> {
   };
 };
 
-template<> EIGEN_STRONG_INLINE Packet4f pcast<Packet4i, Packet4f>(const Packet4i& a) {
-  return _mm_cvtepi32_ps(a);
-}
-
-
 template <>
 struct type_casting_traits<double, float> {
   enum {
@@ -51,10 +42,6 @@ struct type_casting_traits<double, float> {
   };
 };
 
-template<> EIGEN_STRONG_INLINE Packet4f pcast<Packet2d, Packet4f>(const Packet2d& a, const Packet2d& b) {
-  return _mm_shuffle_ps(_mm_cvtpd_ps(a), _mm_cvtpd_ps(b), (1 << 2) | (1 << 6));
-}
-
 template <>
 struct type_casting_traits<float, double> {
   enum {
@@ -63,6 +50,19 @@ struct type_casting_traits<float, double> {
     TgtCoeffRatio = 2
   };
 };
+#endif
+
+template<> EIGEN_STRONG_INLINE Packet4i pcast<Packet4f, Packet4i>(const Packet4f& a) {
+  return _mm_cvttps_epi32(a);
+}
+
+template<> EIGEN_STRONG_INLINE Packet4f pcast<Packet4i, Packet4f>(const Packet4i& a) {
+  return _mm_cvtepi32_ps(a);
+}
+
+template<> EIGEN_STRONG_INLINE Packet4f pcast<Packet2d, Packet4f>(const Packet2d& a, const Packet2d& b) {
+  return _mm_shuffle_ps(_mm_cvtpd_ps(a), _mm_cvtpd_ps(b), (1 << 2) | (1 << 6));
+}
 
 template<> EIGEN_STRONG_INLINE Packet2d pcast<Packet4f, Packet2d>(const Packet4f& a) {
   // Simply discard the second half of the input
diff --git a/xs/src/eigen/Eigen/src/Core/arch/ZVector/Complex.h b/xs/src/eigen/Eigen/src/Core/arch/ZVector/Complex.h
index d39d2d105..1bfb73397 100644
--- a/xs/src/eigen/Eigen/src/Core/arch/ZVector/Complex.h
+++ b/xs/src/eigen/Eigen/src/Core/arch/ZVector/Complex.h
@@ -336,6 +336,9 @@ template<> struct conj_helper<Packet2cf, Packet2cf, true,true>
   }
 };
 
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet2cf,Packet4f)
+EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet1cd,Packet2d)
+
 template<> EIGEN_STRONG_INLINE Packet1cd pdiv<Packet1cd>(const Packet1cd& a, const Packet1cd& b)
 {
   // TODO optimize it for AltiVec
diff --git a/xs/src/eigen/Eigen/src/Core/functors/BinaryFunctors.h b/xs/src/eigen/Eigen/src/Core/functors/BinaryFunctors.h
index 96747bac7..3eae6b8ca 100644
--- a/xs/src/eigen/Eigen/src/Core/functors/BinaryFunctors.h
+++ b/xs/src/eigen/Eigen/src/Core/functors/BinaryFunctors.h
@@ -255,7 +255,7 @@ struct scalar_cmp_op<LhsScalar,RhsScalar, cmp_NEQ> : binary_op_base<LhsScalar,Rh
 
 
 /** \internal
-  * \brief Template functor to compute the hypot of two scalars
+  * \brief Template functor to compute the hypot of two \b positive \b and \b real scalars
   *
   * \sa MatrixBase::stableNorm(), class Redux
   */
@@ -263,22 +263,15 @@ template<typename Scalar>
 struct scalar_hypot_op<Scalar,Scalar> : binary_op_base<Scalar,Scalar>
 {
   EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op)
-//   typedef typename NumTraits<Scalar>::Real result_type;
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const
+
+  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar &x, const Scalar &y) const
   {
-    EIGEN_USING_STD_MATH(sqrt)
-    Scalar p, qp;
-    if(_x>_y)
-    {
-      p = _x;
-      qp = _y / p;
-    }
-    else
-    {
-      p = _y;
-      qp = _x / p;
-    }
-    return p * sqrt(Scalar(1) + qp*qp);
+    // This functor is used by hypotNorm only for which it is faster to first apply abs
+    // on all coefficients prior to reduction through hypot.
+    // This way we avoid calling abs on positive and real entries, and this also permits
+    // to seamlessly handle complexes. Otherwise we would have to handle both real and complexes
+    // through the same functor...
+    return internal::positive_real_hypot(x,y);
   }
 };
 template<typename Scalar>
diff --git a/xs/src/eigen/Eigen/src/Core/functors/NullaryFunctors.h b/xs/src/eigen/Eigen/src/Core/functors/NullaryFunctors.h
index 6a30466fb..b03be0269 100644
--- a/xs/src/eigen/Eigen/src/Core/functors/NullaryFunctors.h
+++ b/xs/src/eigen/Eigen/src/Core/functors/NullaryFunctors.h
@@ -44,16 +44,16 @@ struct linspaced_op_impl<Scalar,Packet,/*IsInteger*/false>
 {
   linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps) :
     m_low(low), m_high(high), m_size1(num_steps==1 ? 1 : num_steps-1), m_step(num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1)),
-    m_interPacket(plset<Packet>(0)),
     m_flip(numext::abs(high)<numext::abs(low))
   {}
 
   template<typename IndexType>
   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (IndexType i) const {
+    typedef typename NumTraits<Scalar>::Real RealScalar;
     if(m_flip)
-      return (i==0)? m_low : (m_high - (m_size1-i)*m_step);
+      return (i==0)? m_low : (m_high - RealScalar(m_size1-i)*m_step);
     else
-      return (i==m_size1)? m_high : (m_low + i*m_step);
+      return (i==m_size1)? m_high : (m_low + RealScalar(i)*m_step);
   }
 
   template<typename IndexType>
@@ -63,7 +63,7 @@ struct linspaced_op_impl<Scalar,Packet,/*IsInteger*/false>
     // [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) )
     if(m_flip)
     {
-      Packet pi = padd(pset1<Packet>(Scalar(i-m_size1)),m_interPacket);
+      Packet pi = plset<Packet>(Scalar(i-m_size1));
       Packet res = padd(pset1<Packet>(m_high), pmul(pset1<Packet>(m_step), pi));
       if(i==0)
         res = pinsertfirst(res, m_low);
@@ -71,7 +71,7 @@ struct linspaced_op_impl<Scalar,Packet,/*IsInteger*/false>
     }
     else
     {
-      Packet pi = padd(pset1<Packet>(Scalar(i)),m_interPacket);
+      Packet pi = plset<Packet>(Scalar(i));
       Packet res = padd(pset1<Packet>(m_low), pmul(pset1<Packet>(m_step), pi));
       if(i==m_size1-unpacket_traits<Packet>::size+1)
         res = pinsertlast(res, m_high);
@@ -83,7 +83,6 @@ struct linspaced_op_impl<Scalar,Packet,/*IsInteger*/false>
   const Scalar m_high;
   const Index m_size1;
   const Scalar m_step;
-  const Packet m_interPacket;
   const bool m_flip;
 };
 
diff --git a/xs/src/eigen/Eigen/src/Core/functors/StlFunctors.h b/xs/src/eigen/Eigen/src/Core/functors/StlFunctors.h
index 6df3fa501..9c1d75850 100644
--- a/xs/src/eigen/Eigen/src/Core/functors/StlFunctors.h
+++ b/xs/src/eigen/Eigen/src/Core/functors/StlFunctors.h
@@ -83,13 +83,17 @@ struct functor_traits<std::binder1st<T> >
 { enum { Cost = functor_traits<T>::Cost, PacketAccess = false }; };
 #endif
 
+#if (__cplusplus < 201703L) && (EIGEN_COMP_MSVC < 1910)
+// std::unary_negate is deprecated since c++17 and will be removed in c++20
 template<typename T>
 struct functor_traits<std::unary_negate<T> >
 { enum { Cost = 1 + functor_traits<T>::Cost, PacketAccess = false }; };
 
+// std::binary_negate is deprecated since c++17 and will be removed in c++20
 template<typename T>
 struct functor_traits<std::binary_negate<T> >
 { enum { Cost = 1 + functor_traits<T>::Cost, PacketAccess = false }; };
+#endif
 
 #ifdef EIGEN_STDEXT_SUPPORT
 
diff --git a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h
index 7122efa60..e844e37d1 100644
--- a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h
+++ b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h
@@ -269,10 +269,13 @@ struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,false>
     enum {
       IsRowMajor = (internal::traits<MatrixType>::Flags&RowMajorBit) ? 1 : 0,
       LhsIsRowMajor = _ActualLhs::Flags&RowMajorBit ? 1 : 0,
-      RhsIsRowMajor = _ActualRhs::Flags&RowMajorBit ? 1 : 0
+      RhsIsRowMajor = _ActualRhs::Flags&RowMajorBit ? 1 : 0,
+      SkipDiag = (UpLo&(UnitDiag|ZeroDiag))!=0
     };
 
     Index size = mat.cols();
+    if(SkipDiag)
+      size--;
     Index depth = actualLhs.cols();
 
     typedef internal::gemm_blocking_space<IsRowMajor ? RowMajor : ColMajor,typename Lhs::Scalar,typename Rhs::Scalar,
@@ -283,10 +286,11 @@ struct general_product_to_triangular_selector<MatrixType,ProductType,UpLo,false>
     internal::general_matrix_matrix_triangular_product<Index,
       typename Lhs::Scalar, LhsIsRowMajor ? RowMajor : ColMajor, LhsBlasTraits::NeedToConjugate,
       typename Rhs::Scalar, RhsIsRowMajor ? RowMajor : ColMajor, RhsBlasTraits::NeedToConjugate,
-      IsRowMajor ? RowMajor : ColMajor, UpLo>
+      IsRowMajor ? RowMajor : ColMajor, UpLo&(Lower|Upper)>
       ::run(size, depth,
-            &actualLhs.coeffRef(0,0), actualLhs.outerStride(), &actualRhs.coeffRef(0,0), actualRhs.outerStride(),
-            mat.data(), mat.outerStride(), actualAlpha, blocking);
+            &actualLhs.coeffRef(SkipDiag&&(UpLo&Lower)==Lower ? 1 : 0,0), actualLhs.outerStride(),
+            &actualRhs.coeffRef(0,SkipDiag&&(UpLo&Upper)==Upper ? 1 : 0), actualRhs.outerStride(),
+            mat.data() + (SkipDiag ? (bool(IsRowMajor) != ((UpLo&Lower)==Lower) ? 1 : mat.outerStride() ) : 0), mat.outerStride(), actualAlpha, blocking);
   }
 };
 
@@ -294,6 +298,7 @@ template<typename MatrixType, unsigned int UpLo>
 template<typename ProductType>
 TriangularView<MatrixType,UpLo>& TriangularViewImpl<MatrixType,UpLo,Dense>::_assignProduct(const ProductType& prod, const Scalar& alpha, bool beta)
 {
+  EIGEN_STATIC_ASSERT((UpLo&UnitDiag)==0, WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED);
   eigen_assert(derived().nestedExpression().rows() == prod.rows() && derived().cols() == prod.cols());
   
   general_product_to_triangular_selector<MatrixType, ProductType, UpLo, internal::traits<ProductType>::InnerSize==1>::run(derived().nestedExpression().const_cast_derived(), prod, alpha, beta);
diff --git a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h
index 5b7c15cca..9176a1382 100644
--- a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h
+++ b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h
@@ -52,7 +52,7 @@ struct general_matrix_matrix_triangular_product<Index,Scalar,LhsStorageOrder,Con
   static EIGEN_STRONG_INLINE void run(Index size, Index depth,const Scalar* lhs, Index lhsStride, \
                           const Scalar* rhs, Index rhsStride, Scalar* res, Index resStride, Scalar alpha, level3_blocking<Scalar, Scalar>& blocking) \
   { \
-    if (lhs==rhs) { \
+    if ( lhs==rhs && ((UpLo&(Lower|Upper)==UpLo)) ) { \
       general_matrix_matrix_rankupdate<Index,Scalar,LhsStorageOrder,ConjugateLhs,ColMajor,UpLo> \
       ::run(size,depth,lhs,lhsStride,rhs,rhsStride,res,resStride,alpha,blocking); \
     } else { \
@@ -88,7 +88,7 @@ struct general_matrix_matrix_rankupdate<Index,EIGTYPE,AStorageOrder,ConjugateA,C
    BlasIndex lda=convert_index<BlasIndex>(lhsStride), ldc=convert_index<BlasIndex>(resStride), n=convert_index<BlasIndex>(size), k=convert_index<BlasIndex>(depth); \
    char uplo=((IsLower) ? 'L' : 'U'), trans=((AStorageOrder==RowMajor) ? 'T':'N'); \
    EIGTYPE beta(1); \
-   BLASFUNC(&uplo, &trans, &n, &k, &numext::real_ref(alpha), lhs, &lda, &numext::real_ref(beta), res, &ldc); \
+   BLASFUNC(&uplo, &trans, &n, &k, (const BLASTYPE*)&numext::real_ref(alpha), lhs, &lda, (const BLASTYPE*)&numext::real_ref(beta), res, &ldc); \
   } \
 };
 
@@ -125,9 +125,13 @@ struct general_matrix_matrix_rankupdate<Index,EIGTYPE,AStorageOrder,ConjugateA,C
   } \
 };
 
-
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_RANKUPDATE_R(double, double, dsyrk)
+EIGEN_BLAS_RANKUPDATE_R(float,  float,  ssyrk)
+#else
 EIGEN_BLAS_RANKUPDATE_R(double, double, dsyrk_)
 EIGEN_BLAS_RANKUPDATE_R(float,  float,  ssyrk_)
+#endif
 
 // TODO hanlde complex cases
 // EIGEN_BLAS_RANKUPDATE_C(dcomplex, double, double, zherk_)
diff --git a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrix_BLAS.h b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrix_BLAS.h
index 7a3bdbf20..b0f6b0d5b 100644
--- a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrix_BLAS.h
+++ b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixMatrix_BLAS.h
@@ -46,7 +46,7 @@ namespace internal {
 
 // gemm specialization
 
-#define GEMM_SPECIALIZATION(EIGTYPE, EIGPREFIX, BLASTYPE, BLASPREFIX) \
+#define GEMM_SPECIALIZATION(EIGTYPE, EIGPREFIX, BLASTYPE, BLASFUNC) \
 template< \
   typename Index, \
   int LhsStorageOrder, bool ConjugateLhs, \
@@ -100,13 +100,20 @@ static void run(Index rows, Index cols, Index depth, \
     ldb = convert_index<BlasIndex>(b_tmp.outerStride()); \
   } else b = _rhs; \
 \
-  BLASPREFIX##gemm_(&transa, &transb, &m, &n, &k, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
+  BLASFUNC(&transa, &transb, &m, &n, &k, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, (const BLASTYPE*)&numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
 }};
 
-GEMM_SPECIALIZATION(double,   d,  double, d)
-GEMM_SPECIALIZATION(float,    f,  float,  s)
-GEMM_SPECIALIZATION(dcomplex, cd, double, z)
-GEMM_SPECIALIZATION(scomplex, cf, float,  c)
+#ifdef EIGEN_USE_MKL
+GEMM_SPECIALIZATION(double,   d,  double, dgemm)
+GEMM_SPECIALIZATION(float,    f,  float,  sgemm)
+GEMM_SPECIALIZATION(dcomplex, cd, MKL_Complex16, zgemm)
+GEMM_SPECIALIZATION(scomplex, cf, MKL_Complex8,  cgemm)
+#else
+GEMM_SPECIALIZATION(double,   d,  double, dgemm_)
+GEMM_SPECIALIZATION(float,    f,  float,  sgemm_)
+GEMM_SPECIALIZATION(dcomplex, cd, double, zgemm_)
+GEMM_SPECIALIZATION(scomplex, cf, float,  cgemm_)
+#endif
 
 } // end namespase internal
 
diff --git a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixVector.h b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixVector.h
index 3c1a7fc40..a597c1f4e 100644
--- a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixVector.h
+++ b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixVector.h
@@ -183,8 +183,8 @@ EIGEN_DONT_INLINE void general_matrix_vector_product<Index,LhsScalar,LhsMapper,C
     alignmentPattern = AllAligned;
   }
 
-  const Index offset1 = (FirstAligned && alignmentStep==1)?3:1;
-  const Index offset3 = (FirstAligned && alignmentStep==1)?1:3;
+  const Index offset1 = (alignmentPattern==FirstAligned && alignmentStep==1)?3:1;
+  const Index offset3 = (alignmentPattern==FirstAligned && alignmentStep==1)?1:3;
 
   Index columnBound = ((cols-skipColumns)/columnsAtOnce)*columnsAtOnce + skipColumns;
   for (Index i=skipColumns; i<columnBound; i+=columnsAtOnce)
@@ -457,8 +457,8 @@ EIGEN_DONT_INLINE void general_matrix_vector_product<Index,LhsScalar,LhsMapper,R
     alignmentPattern = AllAligned;
   }
 
-  const Index offset1 = (FirstAligned && alignmentStep==1)?3:1;
-  const Index offset3 = (FirstAligned && alignmentStep==1)?1:3;
+  const Index offset1 = (alignmentPattern==FirstAligned && alignmentStep==1)?3:1;
+  const Index offset3 = (alignmentPattern==FirstAligned && alignmentStep==1)?1:3;
 
   Index rowBound = ((rows-skipRows)/rowsAtOnce)*rowsAtOnce + skipRows;
   for (Index i=skipRows; i<rowBound; i+=rowsAtOnce)
diff --git a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixVector_BLAS.h b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixVector_BLAS.h
index e3a5d5892..6e36c2b3c 100644
--- a/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixVector_BLAS.h
+++ b/xs/src/eigen/Eigen/src/Core/products/GeneralMatrixVector_BLAS.h
@@ -85,7 +85,7 @@ EIGEN_BLAS_GEMV_SPECIALIZE(float)
 EIGEN_BLAS_GEMV_SPECIALIZE(dcomplex)
 EIGEN_BLAS_GEMV_SPECIALIZE(scomplex)
 
-#define EIGEN_BLAS_GEMV_SPECIALIZATION(EIGTYPE,BLASTYPE,BLASPREFIX) \
+#define EIGEN_BLAS_GEMV_SPECIALIZATION(EIGTYPE,BLASTYPE,BLASFUNC) \
 template<typename Index, int LhsStorageOrder, bool ConjugateLhs, bool ConjugateRhs> \
 struct general_matrix_vector_product_gemv<Index,EIGTYPE,LhsStorageOrder,ConjugateLhs,EIGTYPE,ConjugateRhs> \
 { \
@@ -113,14 +113,21 @@ static void run( \
     x_ptr=x_tmp.data(); \
     incx=1; \
   } else x_ptr=rhs; \
-  BLASPREFIX##gemv_(&trans, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)lhs, &lda, (const BLASTYPE*)x_ptr, &incx, &numext::real_ref(beta), (BLASTYPE*)res, &incy); \
+  BLASFUNC(&trans, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)lhs, &lda, (const BLASTYPE*)x_ptr, &incx, (const BLASTYPE*)&numext::real_ref(beta), (BLASTYPE*)res, &incy); \
 }\
 };
 
-EIGEN_BLAS_GEMV_SPECIALIZATION(double,   double, d)
-EIGEN_BLAS_GEMV_SPECIALIZATION(float,    float,  s)
-EIGEN_BLAS_GEMV_SPECIALIZATION(dcomplex, double, z)
-EIGEN_BLAS_GEMV_SPECIALIZATION(scomplex, float,  c)
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_GEMV_SPECIALIZATION(double,   double, dgemv)
+EIGEN_BLAS_GEMV_SPECIALIZATION(float,    float,  sgemv)
+EIGEN_BLAS_GEMV_SPECIALIZATION(dcomplex, MKL_Complex16, zgemv)
+EIGEN_BLAS_GEMV_SPECIALIZATION(scomplex, MKL_Complex8 , cgemv)
+#else
+EIGEN_BLAS_GEMV_SPECIALIZATION(double,   double, dgemv_)
+EIGEN_BLAS_GEMV_SPECIALIZATION(float,    float,  sgemv_)
+EIGEN_BLAS_GEMV_SPECIALIZATION(dcomplex, double, zgemv_)
+EIGEN_BLAS_GEMV_SPECIALIZATION(scomplex, float,  cgemv_)
+#endif
 
 } // end namespase internal
 
diff --git a/xs/src/eigen/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h b/xs/src/eigen/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h
index a45238d69..9a5318507 100644
--- a/xs/src/eigen/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h
+++ b/xs/src/eigen/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h
@@ -40,7 +40,7 @@ namespace internal {
 
 /* Optimized selfadjoint matrix * matrix (?SYMM/?HEMM) product */
 
-#define EIGEN_BLAS_SYMM_L(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \
+#define EIGEN_BLAS_SYMM_L(EIGTYPE, BLASTYPE, EIGPREFIX, BLASFUNC) \
 template <typename Index, \
           int LhsStorageOrder, bool ConjugateLhs, \
           int RhsStorageOrder, bool ConjugateRhs> \
@@ -81,13 +81,13 @@ struct product_selfadjoint_matrix<EIGTYPE,Index,LhsStorageOrder,true,ConjugateLh
       ldb = convert_index<BlasIndex>(b_tmp.outerStride()); \
     } else b = _rhs; \
 \
-    BLASPREFIX##symm_(&side, &uplo, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
+    BLASFUNC(&side, &uplo, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, (const BLASTYPE*)&numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
 \
   } \
 };
 
 
-#define EIGEN_BLAS_HEMM_L(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \
+#define EIGEN_BLAS_HEMM_L(EIGTYPE, BLASTYPE, EIGPREFIX, BLASFUNC) \
 template <typename Index, \
           int LhsStorageOrder, bool ConjugateLhs, \
           int RhsStorageOrder, bool ConjugateRhs> \
@@ -144,20 +144,26 @@ struct product_selfadjoint_matrix<EIGTYPE,Index,LhsStorageOrder,true,ConjugateLh
       ldb = convert_index<BlasIndex>(b_tmp.outerStride()); \
     } \
 \
-    BLASPREFIX##hemm_(&side, &uplo, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
+    BLASFUNC(&side, &uplo, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, (const BLASTYPE*)&numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
 \
   } \
 };
 
-EIGEN_BLAS_SYMM_L(double, double, d, d)
-EIGEN_BLAS_SYMM_L(float, float, f, s)
-EIGEN_BLAS_HEMM_L(dcomplex, double, cd, z)
-EIGEN_BLAS_HEMM_L(scomplex, float, cf, c)
-
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_SYMM_L(double, double, d, dsymm)
+EIGEN_BLAS_SYMM_L(float, float, f, ssymm)
+EIGEN_BLAS_HEMM_L(dcomplex, MKL_Complex16, cd, zhemm)
+EIGEN_BLAS_HEMM_L(scomplex, MKL_Complex8, cf, chemm)
+#else
+EIGEN_BLAS_SYMM_L(double, double, d, dsymm_)
+EIGEN_BLAS_SYMM_L(float, float, f, ssymm_)
+EIGEN_BLAS_HEMM_L(dcomplex, double, cd, zhemm_)
+EIGEN_BLAS_HEMM_L(scomplex, float, cf, chemm_)
+#endif
 
 /* Optimized matrix * selfadjoint matrix (?SYMM/?HEMM) product */
 
-#define EIGEN_BLAS_SYMM_R(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \
+#define EIGEN_BLAS_SYMM_R(EIGTYPE, BLASTYPE, EIGPREFIX, BLASFUNC) \
 template <typename Index, \
           int LhsStorageOrder, bool ConjugateLhs, \
           int RhsStorageOrder, bool ConjugateRhs> \
@@ -197,13 +203,13 @@ struct product_selfadjoint_matrix<EIGTYPE,Index,LhsStorageOrder,false,ConjugateL
       ldb = convert_index<BlasIndex>(b_tmp.outerStride()); \
     } else b = _lhs; \
 \
-    BLASPREFIX##symm_(&side, &uplo, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
+    BLASFUNC(&side, &uplo, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, (const BLASTYPE*)&numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
 \
   } \
 };
 
 
-#define EIGEN_BLAS_HEMM_R(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \
+#define EIGEN_BLAS_HEMM_R(EIGTYPE, BLASTYPE, EIGPREFIX, BLASFUNC) \
 template <typename Index, \
           int LhsStorageOrder, bool ConjugateLhs, \
           int RhsStorageOrder, bool ConjugateRhs> \
@@ -259,15 +265,21 @@ struct product_selfadjoint_matrix<EIGTYPE,Index,LhsStorageOrder,false,ConjugateL
       ldb = convert_index<BlasIndex>(b_tmp.outerStride()); \
     } \
 \
-    BLASPREFIX##hemm_(&side, &uplo, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, &numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
+    BLASFUNC(&side, &uplo, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)b, &ldb, (const BLASTYPE*)&numext::real_ref(beta), (BLASTYPE*)res, &ldc); \
   } \
 };
 
-EIGEN_BLAS_SYMM_R(double, double, d, d)
-EIGEN_BLAS_SYMM_R(float, float, f, s)
-EIGEN_BLAS_HEMM_R(dcomplex, double, cd, z)
-EIGEN_BLAS_HEMM_R(scomplex, float, cf, c)
-
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_SYMM_R(double, double, d, dsymm)
+EIGEN_BLAS_SYMM_R(float, float, f, ssymm)
+EIGEN_BLAS_HEMM_R(dcomplex, MKL_Complex16, cd, zhemm)
+EIGEN_BLAS_HEMM_R(scomplex, MKL_Complex8, cf, chemm)
+#else
+EIGEN_BLAS_SYMM_R(double, double, d, dsymm_)
+EIGEN_BLAS_SYMM_R(float, float, f, ssymm_)
+EIGEN_BLAS_HEMM_R(dcomplex, double, cd, zhemm_)
+EIGEN_BLAS_HEMM_R(scomplex, float, cf, chemm_)
+#endif
 } // end namespace internal
 
 } // end namespace Eigen
diff --git a/xs/src/eigen/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h b/xs/src/eigen/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h
index 38f23accf..1238345e3 100644
--- a/xs/src/eigen/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h
+++ b/xs/src/eigen/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h
@@ -95,14 +95,21 @@ const EIGTYPE* _rhs, EIGTYPE* res, EIGTYPE alpha) \
     x_tmp=map_x.conjugate(); \
     x_ptr=x_tmp.data(); \
   } else x_ptr=_rhs; \
-  BLASFUNC(&uplo, &n, &numext::real_ref(alpha), (const BLASTYPE*)lhs, &lda, (const BLASTYPE*)x_ptr, &incx, &numext::real_ref(beta), (BLASTYPE*)res, &incy); \
+  BLASFUNC(&uplo, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)lhs, &lda, (const BLASTYPE*)x_ptr, &incx, (const BLASTYPE*)&numext::real_ref(beta), (BLASTYPE*)res, &incy); \
 }\
 };
 
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_SYMV_SPECIALIZATION(double,   double, dsymv)
+EIGEN_BLAS_SYMV_SPECIALIZATION(float,    float,  ssymv)
+EIGEN_BLAS_SYMV_SPECIALIZATION(dcomplex, MKL_Complex16, zhemv)
+EIGEN_BLAS_SYMV_SPECIALIZATION(scomplex, MKL_Complex8,  chemv)
+#else
 EIGEN_BLAS_SYMV_SPECIALIZATION(double,   double, dsymv_)
 EIGEN_BLAS_SYMV_SPECIALIZATION(float,    float,  ssymv_)
 EIGEN_BLAS_SYMV_SPECIALIZATION(dcomplex, double, zhemv_)
 EIGEN_BLAS_SYMV_SPECIALIZATION(scomplex, float,  chemv_)
+#endif
 
 } // end namespace internal
 
diff --git a/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixMatrix.h b/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixMatrix.h
index 6ec5a8a0b..f784507e7 100644
--- a/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixMatrix.h
+++ b/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixMatrix.h
@@ -137,7 +137,13 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix<Scalar,Index,Mode,true,
     ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA());
     ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB());
 
-    Matrix<Scalar,SmallPanelWidth,SmallPanelWidth,LhsStorageOrder> triangularBuffer((internal::constructor_without_unaligned_array_assert()));
+    // To work around an "error: member reference base type 'Matrix<...>
+    // (Eigen::internal::constructor_without_unaligned_array_assert (*)())' is
+    // not a structure or union" compilation error in nvcc (tested V8.0.61),
+    // create a dummy internal::constructor_without_unaligned_array_assert
+    // object to pass to the Matrix constructor.
+    internal::constructor_without_unaligned_array_assert a;
+    Matrix<Scalar,SmallPanelWidth,SmallPanelWidth,LhsStorageOrder> triangularBuffer(a);
     triangularBuffer.setZero();
     if((Mode&ZeroDiag)==ZeroDiag)
       triangularBuffer.diagonal().setZero();
@@ -284,7 +290,8 @@ EIGEN_DONT_INLINE void product_triangular_matrix_matrix<Scalar,Index,Mode,false,
     ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA());
     ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB());
 
-    Matrix<Scalar,SmallPanelWidth,SmallPanelWidth,RhsStorageOrder> triangularBuffer((internal::constructor_without_unaligned_array_assert()));
+    internal::constructor_without_unaligned_array_assert a;
+    Matrix<Scalar,SmallPanelWidth,SmallPanelWidth,RhsStorageOrder> triangularBuffer(a);
     triangularBuffer.setZero();
     if((Mode&ZeroDiag)==ZeroDiag)
       triangularBuffer.diagonal().setZero();
@@ -393,7 +400,9 @@ struct triangular_product_impl<Mode,LhsIsTriangular,Lhs,false,Rhs,false>
 {
   template<typename Dest> static void run(Dest& dst, const Lhs &a_lhs, const Rhs &a_rhs, const typename Dest::Scalar& alpha)
   {
-    typedef typename Dest::Scalar     Scalar;
+    typedef typename Lhs::Scalar  LhsScalar;
+    typedef typename Rhs::Scalar  RhsScalar;
+    typedef typename Dest::Scalar Scalar;
     
     typedef internal::blas_traits<Lhs> LhsBlasTraits;
     typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType;
@@ -405,8 +414,9 @@ struct triangular_product_impl<Mode,LhsIsTriangular,Lhs,false,Rhs,false>
     typename internal::add_const_on_value_type<ActualLhsType>::type lhs = LhsBlasTraits::extract(a_lhs);
     typename internal::add_const_on_value_type<ActualRhsType>::type rhs = RhsBlasTraits::extract(a_rhs);
 
-    Scalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(a_lhs)
-                               * RhsBlasTraits::extractScalarFactor(a_rhs);
+    LhsScalar lhs_alpha = LhsBlasTraits::extractScalarFactor(a_lhs);
+    RhsScalar rhs_alpha = RhsBlasTraits::extractScalarFactor(a_rhs);
+    Scalar actualAlpha = alpha * lhs_alpha * rhs_alpha;
 
     typedef internal::gemm_blocking_space<(Dest::Flags&RowMajorBit) ? RowMajor : ColMajor,Scalar,Scalar,
               Lhs::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime, Lhs::MaxColsAtCompileTime,4> BlockingType;
@@ -431,6 +441,21 @@ struct triangular_product_impl<Mode,LhsIsTriangular,Lhs,false,Rhs,false>
         &dst.coeffRef(0,0), dst.outerStride(),    // result info
         actualAlpha, blocking
       );
+
+    // Apply correction if the diagonal is unit and a scalar factor was nested:
+    if ((Mode&UnitDiag)==UnitDiag)
+    {
+      if (LhsIsTriangular && lhs_alpha!=LhsScalar(1))
+      {
+        Index diagSize = (std::min)(lhs.rows(),lhs.cols());
+        dst.topRows(diagSize) -= ((lhs_alpha-LhsScalar(1))*a_rhs).topRows(diagSize);
+      }
+      else if ((!LhsIsTriangular) && rhs_alpha!=RhsScalar(1))
+      {
+        Index diagSize = (std::min)(rhs.rows(),rhs.cols());
+        dst.leftCols(diagSize) -= (rhs_alpha-RhsScalar(1))*a_lhs.leftCols(diagSize);
+      }
+    }
   }
 };
 
diff --git a/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h b/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h
index aecded6bb..a25197ab0 100644
--- a/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h
+++ b/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h
@@ -75,7 +75,7 @@ EIGEN_BLAS_TRMM_SPECIALIZE(scomplex, true)
 EIGEN_BLAS_TRMM_SPECIALIZE(scomplex, false)
 
 // implements col-major += alpha * op(triangular) * op(general)
-#define EIGEN_BLAS_TRMM_L(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \
+#define EIGEN_BLAS_TRMM_L(EIGTYPE, BLASTYPE, EIGPREFIX, BLASFUNC) \
 template <typename Index, int Mode, \
           int LhsStorageOrder, bool ConjugateLhs, \
           int RhsStorageOrder, bool ConjugateRhs> \
@@ -172,7 +172,7 @@ struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,true, \
    } \
    /*std::cout << "TRMM_L: A is square! Go to BLAS TRMM implementation! \n";*/ \
 /* call ?trmm*/ \
-   BLASPREFIX##trmm_(&side, &uplo, &transa, &diag, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)b, &ldb); \
+   BLASFUNC(&side, &uplo, &transa, &diag, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)b, &ldb); \
 \
 /* Add op(a_triangular)*b into res*/ \
    Map<MatrixX##EIGPREFIX, 0, OuterStride<> > res_tmp(res,rows,cols,OuterStride<>(resStride)); \
@@ -180,13 +180,20 @@ struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,true, \
   } \
 };
 
-EIGEN_BLAS_TRMM_L(double, double, d, d)
-EIGEN_BLAS_TRMM_L(dcomplex, double, cd, z)
-EIGEN_BLAS_TRMM_L(float, float, f, s)
-EIGEN_BLAS_TRMM_L(scomplex, float, cf, c)
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_TRMM_L(double, double, d, dtrmm)
+EIGEN_BLAS_TRMM_L(dcomplex, MKL_Complex16, cd, ztrmm)
+EIGEN_BLAS_TRMM_L(float, float, f, strmm)
+EIGEN_BLAS_TRMM_L(scomplex, MKL_Complex8, cf, ctrmm)
+#else
+EIGEN_BLAS_TRMM_L(double, double, d, dtrmm_)
+EIGEN_BLAS_TRMM_L(dcomplex, double, cd, ztrmm_)
+EIGEN_BLAS_TRMM_L(float, float, f, strmm_)
+EIGEN_BLAS_TRMM_L(scomplex, float, cf, ctrmm_)
+#endif
 
 // implements col-major += alpha * op(general) * op(triangular)
-#define EIGEN_BLAS_TRMM_R(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \
+#define EIGEN_BLAS_TRMM_R(EIGTYPE, BLASTYPE, EIGPREFIX, BLASFUNC) \
 template <typename Index, int Mode, \
           int LhsStorageOrder, bool ConjugateLhs, \
           int RhsStorageOrder, bool ConjugateRhs> \
@@ -282,7 +289,7 @@ struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,false, \
    } \
    /*std::cout << "TRMM_R: A is square! Go to BLAS TRMM implementation! \n";*/ \
 /* call ?trmm*/ \
-   BLASPREFIX##trmm_(&side, &uplo, &transa, &diag, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)b, &ldb); \
+   BLASFUNC(&side, &uplo, &transa, &diag, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)b, &ldb); \
 \
 /* Add op(a_triangular)*b into res*/ \
    Map<MatrixX##EIGPREFIX, 0, OuterStride<> > res_tmp(res,rows,cols,OuterStride<>(resStride)); \
@@ -290,11 +297,17 @@ struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,false, \
   } \
 };
 
-EIGEN_BLAS_TRMM_R(double, double, d, d)
-EIGEN_BLAS_TRMM_R(dcomplex, double, cd, z)
-EIGEN_BLAS_TRMM_R(float, float, f, s)
-EIGEN_BLAS_TRMM_R(scomplex, float, cf, c)
-
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_TRMM_R(double, double, d, dtrmm)
+EIGEN_BLAS_TRMM_R(dcomplex, MKL_Complex16, cd, ztrmm)
+EIGEN_BLAS_TRMM_R(float, float, f, strmm)
+EIGEN_BLAS_TRMM_R(scomplex, MKL_Complex8, cf, ctrmm)
+#else
+EIGEN_BLAS_TRMM_R(double, double, d, dtrmm_)
+EIGEN_BLAS_TRMM_R(dcomplex, double, cd, ztrmm_)
+EIGEN_BLAS_TRMM_R(float, float, f, strmm_)
+EIGEN_BLAS_TRMM_R(scomplex, float, cf, ctrmm_)
+#endif
 } // end namespace internal
 
 } // end namespace Eigen
diff --git a/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixVector.h b/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixVector.h
index 4b292e74d..76bfa159c 100644
--- a/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixVector.h
+++ b/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixVector.h
@@ -221,8 +221,9 @@ template<int Mode> struct trmv_selector<Mode,ColMajor>
     typename internal::add_const_on_value_type<ActualLhsType>::type actualLhs = LhsBlasTraits::extract(lhs);
     typename internal::add_const_on_value_type<ActualRhsType>::type actualRhs = RhsBlasTraits::extract(rhs);
 
-    ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs)
-                                  * RhsBlasTraits::extractScalarFactor(rhs);
+    LhsScalar lhs_alpha = LhsBlasTraits::extractScalarFactor(lhs);
+    RhsScalar rhs_alpha = RhsBlasTraits::extractScalarFactor(rhs);
+    ResScalar actualAlpha = alpha * lhs_alpha * rhs_alpha;
 
     enum {
       // FIXME find a way to allow an inner stride on the result if packet_traits<Scalar>::size==1
@@ -274,6 +275,12 @@ template<int Mode> struct trmv_selector<Mode,ColMajor>
       else
         dest = MappedDest(actualDestPtr, dest.size());
     }
+
+    if ( ((Mode&UnitDiag)==UnitDiag) && (lhs_alpha!=LhsScalar(1)) )
+    {
+      Index diagSize = (std::min)(lhs.rows(),lhs.cols());
+      dest.head(diagSize) -= (lhs_alpha-LhsScalar(1))*rhs.head(diagSize);
+    }
   }
 };
 
@@ -295,8 +302,9 @@ template<int Mode> struct trmv_selector<Mode,RowMajor>
     typename add_const<ActualLhsType>::type actualLhs = LhsBlasTraits::extract(lhs);
     typename add_const<ActualRhsType>::type actualRhs = RhsBlasTraits::extract(rhs);
 
-    ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs)
-                                  * RhsBlasTraits::extractScalarFactor(rhs);
+    LhsScalar lhs_alpha = LhsBlasTraits::extractScalarFactor(lhs);
+    RhsScalar rhs_alpha = RhsBlasTraits::extractScalarFactor(rhs);
+    ResScalar actualAlpha = alpha * lhs_alpha * rhs_alpha;
 
     enum {
       DirectlyUseRhs = ActualRhsTypeCleaned::InnerStrideAtCompileTime==1
@@ -326,6 +334,12 @@ template<int Mode> struct trmv_selector<Mode,RowMajor>
             actualRhsPtr,1,
             dest.data(),dest.innerStride(),
             actualAlpha);
+
+    if ( ((Mode&UnitDiag)==UnitDiag) && (lhs_alpha!=LhsScalar(1)) )
+    {
+      Index diagSize = (std::min)(lhs.rows(),lhs.cols());
+      dest.head(diagSize) -= (lhs_alpha-LhsScalar(1))*rhs.head(diagSize);
+    }
   }
 };
 
diff --git a/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixVector_BLAS.h b/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixVector_BLAS.h
index 07bf26ce5..3d47a2b94 100644
--- a/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixVector_BLAS.h
+++ b/xs/src/eigen/Eigen/src/Core/products/TriangularMatrixVector_BLAS.h
@@ -71,7 +71,7 @@ EIGEN_BLAS_TRMV_SPECIALIZE(dcomplex)
 EIGEN_BLAS_TRMV_SPECIALIZE(scomplex)
 
 // implements col-major: res += alpha * op(triangular) * vector
-#define EIGEN_BLAS_TRMV_CM(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \
+#define EIGEN_BLAS_TRMV_CM(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX, BLASPOSTFIX) \
 template<typename Index, int Mode, bool ConjLhs, bool ConjRhs> \
 struct triangular_matrix_vector_product_trmv<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,ConjRhs,ColMajor> { \
   enum { \
@@ -121,10 +121,10 @@ struct triangular_matrix_vector_product_trmv<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,
    diag = IsUnitDiag ? 'U' : 'N'; \
 \
 /* call ?TRMV*/ \
-   BLASPREFIX##trmv_(&uplo, &trans, &diag, &n, (const BLASTYPE*)_lhs, &lda, (BLASTYPE*)x, &incx); \
+   BLASPREFIX##trmv##BLASPOSTFIX(&uplo, &trans, &diag, &n, (const BLASTYPE*)_lhs, &lda, (BLASTYPE*)x, &incx); \
 \
 /* Add op(a_tr)rhs into res*/ \
-   BLASPREFIX##axpy_(&n, &numext::real_ref(alpha),(const BLASTYPE*)x, &incx, (BLASTYPE*)_res, &incy); \
+   BLASPREFIX##axpy##BLASPOSTFIX(&n, (const BLASTYPE*)&numext::real_ref(alpha),(const BLASTYPE*)x, &incx, (BLASTYPE*)_res, &incy); \
 /* Non-square case - doesn't fit to BLAS ?TRMV. Fall to default triangular product*/ \
    if (size<(std::max)(rows,cols)) { \
      if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \
@@ -142,18 +142,25 @@ struct triangular_matrix_vector_product_trmv<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,
        m = convert_index<BlasIndex>(size); \
        n = convert_index<BlasIndex>(cols-size); \
      } \
-     BLASPREFIX##gemv_(&trans, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)x, &incx, &numext::real_ref(beta), (BLASTYPE*)y, &incy); \
+     BLASPREFIX##gemv##BLASPOSTFIX(&trans, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)x, &incx, (const BLASTYPE*)&numext::real_ref(beta), (BLASTYPE*)y, &incy); \
    } \
   } \
 };
 
-EIGEN_BLAS_TRMV_CM(double,   double, d,  d)
-EIGEN_BLAS_TRMV_CM(dcomplex, double, cd, z)
-EIGEN_BLAS_TRMV_CM(float,    float,  f,  s)
-EIGEN_BLAS_TRMV_CM(scomplex, float,  cf, c)
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_TRMV_CM(double,   double, d,  d,)
+EIGEN_BLAS_TRMV_CM(dcomplex, MKL_Complex16, cd, z,)
+EIGEN_BLAS_TRMV_CM(float,    float,  f,  s,)
+EIGEN_BLAS_TRMV_CM(scomplex, MKL_Complex8,  cf, c,)
+#else
+EIGEN_BLAS_TRMV_CM(double,   double, d,  d, _)
+EIGEN_BLAS_TRMV_CM(dcomplex, double, cd, z, _)
+EIGEN_BLAS_TRMV_CM(float,    float,  f,  s, _)
+EIGEN_BLAS_TRMV_CM(scomplex, float,  cf, c, _)
+#endif
 
 // implements row-major: res += alpha * op(triangular) * vector
-#define EIGEN_BLAS_TRMV_RM(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX) \
+#define EIGEN_BLAS_TRMV_RM(EIGTYPE, BLASTYPE, EIGPREFIX, BLASPREFIX, BLASPOSTFIX) \
 template<typename Index, int Mode, bool ConjLhs, bool ConjRhs> \
 struct triangular_matrix_vector_product_trmv<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,ConjRhs,RowMajor> { \
   enum { \
@@ -203,10 +210,10 @@ struct triangular_matrix_vector_product_trmv<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,
    diag = IsUnitDiag ? 'U' : 'N'; \
 \
 /* call ?TRMV*/ \
-   BLASPREFIX##trmv_(&uplo, &trans, &diag, &n, (const BLASTYPE*)_lhs, &lda, (BLASTYPE*)x, &incx); \
+   BLASPREFIX##trmv##BLASPOSTFIX(&uplo, &trans, &diag, &n, (const BLASTYPE*)_lhs, &lda, (BLASTYPE*)x, &incx); \
 \
 /* Add op(a_tr)rhs into res*/ \
-   BLASPREFIX##axpy_(&n, &numext::real_ref(alpha),(const BLASTYPE*)x, &incx, (BLASTYPE*)_res, &incy); \
+   BLASPREFIX##axpy##BLASPOSTFIX(&n, (const BLASTYPE*)&numext::real_ref(alpha),(const BLASTYPE*)x, &incx, (BLASTYPE*)_res, &incy); \
 /* Non-square case - doesn't fit to BLAS ?TRMV. Fall to default triangular product*/ \
    if (size<(std::max)(rows,cols)) { \
      if (ConjRhs) x_tmp = rhs.conjugate(); else x_tmp = rhs; \
@@ -224,15 +231,22 @@ struct triangular_matrix_vector_product_trmv<Index,Mode,EIGTYPE,ConjLhs,EIGTYPE,
        m = convert_index<BlasIndex>(size); \
        n = convert_index<BlasIndex>(cols-size); \
      } \
-     BLASPREFIX##gemv_(&trans, &n, &m, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)x, &incx, &numext::real_ref(beta), (BLASTYPE*)y, &incy); \
+     BLASPREFIX##gemv##BLASPOSTFIX(&trans, &n, &m, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (const BLASTYPE*)x, &incx, (const BLASTYPE*)&numext::real_ref(beta), (BLASTYPE*)y, &incy); \
    } \
   } \
 };
 
-EIGEN_BLAS_TRMV_RM(double,   double, d,  d)
-EIGEN_BLAS_TRMV_RM(dcomplex, double, cd, z)
-EIGEN_BLAS_TRMV_RM(float,    float,  f,  s)
-EIGEN_BLAS_TRMV_RM(scomplex, float,  cf, c)
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_TRMV_RM(double,   double, d,  d,)
+EIGEN_BLAS_TRMV_RM(dcomplex, MKL_Complex16, cd, z,)
+EIGEN_BLAS_TRMV_RM(float,    float,  f,  s,)
+EIGEN_BLAS_TRMV_RM(scomplex, MKL_Complex8,  cf, c,)
+#else
+EIGEN_BLAS_TRMV_RM(double,   double, d,  d,_)
+EIGEN_BLAS_TRMV_RM(dcomplex, double, cd, z,_)
+EIGEN_BLAS_TRMV_RM(float,    float,  f,  s,_)
+EIGEN_BLAS_TRMV_RM(scomplex, float,  cf, c,_)
+#endif
 
 } // end namespase internal
 
diff --git a/xs/src/eigen/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h b/xs/src/eigen/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h
index 88c0fb794..f0775116a 100644
--- a/xs/src/eigen/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h
+++ b/xs/src/eigen/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h
@@ -38,7 +38,7 @@ namespace Eigen {
 namespace internal {
 
 // implements LeftSide op(triangular)^-1 * general
-#define EIGEN_BLAS_TRSM_L(EIGTYPE, BLASTYPE, BLASPREFIX) \
+#define EIGEN_BLAS_TRSM_L(EIGTYPE, BLASTYPE, BLASFUNC) \
 template <typename Index, int Mode, bool Conjugate, int TriStorageOrder> \
 struct triangular_solve_matrix<EIGTYPE,Index,OnTheLeft,Mode,Conjugate,TriStorageOrder,ColMajor> \
 { \
@@ -80,18 +80,24 @@ struct triangular_solve_matrix<EIGTYPE,Index,OnTheLeft,Mode,Conjugate,TriStorage
    } \
    if (IsUnitDiag) diag='U'; \
 /* call ?trsm*/ \
-   BLASPREFIX##trsm_(&side, &uplo, &transa, &diag, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)_other, &ldb); \
+   BLASFUNC(&side, &uplo, &transa, &diag, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)_other, &ldb); \
  } \
 };
 
-EIGEN_BLAS_TRSM_L(double,   double, d)
-EIGEN_BLAS_TRSM_L(dcomplex, double, z)
-EIGEN_BLAS_TRSM_L(float,    float,  s)
-EIGEN_BLAS_TRSM_L(scomplex, float,  c)
-
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_TRSM_L(double,   double, dtrsm)
+EIGEN_BLAS_TRSM_L(dcomplex, MKL_Complex16, ztrsm)
+EIGEN_BLAS_TRSM_L(float,    float,  strsm)
+EIGEN_BLAS_TRSM_L(scomplex, MKL_Complex8, ctrsm)
+#else
+EIGEN_BLAS_TRSM_L(double,   double, dtrsm_)
+EIGEN_BLAS_TRSM_L(dcomplex, double, ztrsm_)
+EIGEN_BLAS_TRSM_L(float,    float,  strsm_)
+EIGEN_BLAS_TRSM_L(scomplex, float,  ctrsm_)
+#endif
 
 // implements RightSide general * op(triangular)^-1
-#define EIGEN_BLAS_TRSM_R(EIGTYPE, BLASTYPE, BLASPREFIX) \
+#define EIGEN_BLAS_TRSM_R(EIGTYPE, BLASTYPE, BLASFUNC) \
 template <typename Index, int Mode, bool Conjugate, int TriStorageOrder> \
 struct triangular_solve_matrix<EIGTYPE,Index,OnTheRight,Mode,Conjugate,TriStorageOrder,ColMajor> \
 { \
@@ -133,16 +139,22 @@ struct triangular_solve_matrix<EIGTYPE,Index,OnTheRight,Mode,Conjugate,TriStorag
    } \
    if (IsUnitDiag) diag='U'; \
 /* call ?trsm*/ \
-   BLASPREFIX##trsm_(&side, &uplo, &transa, &diag, &m, &n, &numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)_other, &ldb); \
+   BLASFUNC(&side, &uplo, &transa, &diag, &m, &n, (const BLASTYPE*)&numext::real_ref(alpha), (const BLASTYPE*)a, &lda, (BLASTYPE*)_other, &ldb); \
    /*std::cout << "TRMS_L specialization!\n";*/ \
  } \
 };
 
-EIGEN_BLAS_TRSM_R(double,   double, d)
-EIGEN_BLAS_TRSM_R(dcomplex, double, z)
-EIGEN_BLAS_TRSM_R(float,    float,  s)
-EIGEN_BLAS_TRSM_R(scomplex, float,  c)
-
+#ifdef EIGEN_USE_MKL
+EIGEN_BLAS_TRSM_R(double,   double, dtrsm)
+EIGEN_BLAS_TRSM_R(dcomplex, MKL_Complex16, ztrsm)
+EIGEN_BLAS_TRSM_R(float,    float,  strsm)
+EIGEN_BLAS_TRSM_R(scomplex, MKL_Complex8,  ctrsm)
+#else
+EIGEN_BLAS_TRSM_R(double,   double, dtrsm_)
+EIGEN_BLAS_TRSM_R(dcomplex, double, ztrsm_)
+EIGEN_BLAS_TRSM_R(float,    float,  strsm_)
+EIGEN_BLAS_TRSM_R(scomplex, float,  ctrsm_)
+#endif
 
 } // end namespace internal
 
diff --git a/xs/src/eigen/Eigen/src/Core/util/MKL_support.h b/xs/src/eigen/Eigen/src/Core/util/MKL_support.h
index 26b59669e..b7d6ecc76 100644
--- a/xs/src/eigen/Eigen/src/Core/util/MKL_support.h
+++ b/xs/src/eigen/Eigen/src/Core/util/MKL_support.h
@@ -49,10 +49,11 @@
   #define EIGEN_USE_LAPACKE
 #endif
 
-#if defined(EIGEN_USE_MKL_VML)
+#if defined(EIGEN_USE_MKL_VML) && !defined(EIGEN_USE_MKL)
   #define EIGEN_USE_MKL
 #endif
 
+
 #if defined EIGEN_USE_MKL
 #   include <mkl.h> 
 /*Check IMKL version for compatibility: < 10.3 is not usable with Eigen*/
@@ -108,6 +109,10 @@
 #endif
 #endif
 
+#if defined(EIGEN_USE_BLAS) && !defined(EIGEN_USE_MKL)
+#include "../../misc/blas.h"
+#endif
+
 namespace Eigen {
 
 typedef std::complex<double> dcomplex;
@@ -121,8 +126,5 @@ typedef int BlasIndex;
 
 } // end namespace Eigen
 
-#if defined(EIGEN_USE_BLAS)
-#include "../../misc/blas.h"
-#endif
 
 #endif // EIGEN_MKL_SUPPORT_H
diff --git a/xs/src/eigen/Eigen/src/Core/util/Macros.h b/xs/src/eigen/Eigen/src/Core/util/Macros.h
index 427d3cd6b..02d21d2cd 100644
--- a/xs/src/eigen/Eigen/src/Core/util/Macros.h
+++ b/xs/src/eigen/Eigen/src/Core/util/Macros.h
@@ -13,7 +13,7 @@
 
 #define EIGEN_WORLD_VERSION 3
 #define EIGEN_MAJOR_VERSION 3
-#define EIGEN_MINOR_VERSION 3
+#define EIGEN_MINOR_VERSION 5
 
 #define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \
                                       (EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \
@@ -399,7 +399,7 @@
 // Does the compiler support variadic templates?
 #ifndef EIGEN_HAS_VARIADIC_TEMPLATES
 #if EIGEN_MAX_CPP_VER>=11 && (__cplusplus > 199711L || EIGEN_COMP_MSVC >= 1900) \
-  && ( !defined(__NVCC__) || !EIGEN_ARCH_ARM_OR_ARM64 || (defined __CUDACC_VER__ && __CUDACC_VER__ >= 80000) )
+  && (!defined(__NVCC__) || !EIGEN_ARCH_ARM_OR_ARM64 || (EIGEN_CUDACC_VER >= 80000) )
     // ^^ Disable the use of variadic templates when compiling with versions of nvcc older than 8.0 on ARM devices:
     //    this prevents nvcc from crashing when compiling Eigen on Tegra X1
 #define EIGEN_HAS_VARIADIC_TEMPLATES 1
@@ -413,7 +413,7 @@
 
 #ifdef __CUDACC__
 // Const expressions are supported provided that c++11 is enabled and we're using either clang or nvcc 7.5 or above
-#if EIGEN_MAX_CPP_VER>=14 && (__cplusplus > 199711L && defined(__CUDACC_VER__) && (EIGEN_COMP_CLANG || __CUDACC_VER__ >= 70500))
+#if EIGEN_MAX_CPP_VER>=14 && (__cplusplus > 199711L && (EIGEN_COMP_CLANG || EIGEN_CUDACC_VER >= 70500))
   #define EIGEN_HAS_CONSTEXPR 1
 #endif
 #elif EIGEN_MAX_CPP_VER>=14 && (__has_feature(cxx_relaxed_constexpr) || (defined(__cplusplus) && __cplusplus >= 201402L) || \
@@ -487,11 +487,13 @@
 // EIGEN_STRONG_INLINE is a stronger version of the inline, using __forceinline on MSVC,
 // but it still doesn't use GCC's always_inline. This is useful in (common) situations where MSVC needs forceinline
 // but GCC is still doing fine with just inline.
+#ifndef EIGEN_STRONG_INLINE
 #if EIGEN_COMP_MSVC || EIGEN_COMP_ICC
 #define EIGEN_STRONG_INLINE __forceinline
 #else
 #define EIGEN_STRONG_INLINE inline
 #endif
+#endif
 
 // EIGEN_ALWAYS_INLINE is the stronget, it has the effect of making the function inline and adding every possible
 // attribute to maximize inlining. This should only be used when really necessary: in particular,
@@ -812,7 +814,8 @@ namespace Eigen {
 // just an empty macro !
 #define EIGEN_EMPTY
 
-#if EIGEN_COMP_MSVC_STRICT && (EIGEN_COMP_MSVC < 1900 ||  defined(__CUDACC_VER__)) // for older MSVC versions, as well as 1900 && CUDA 8, using the base operator is sufficient (cf Bugs 1000, 1324)
+#if EIGEN_COMP_MSVC_STRICT && (EIGEN_COMP_MSVC < 1900 || EIGEN_CUDACC_VER>0)
+  // for older MSVC versions, as well as 1900 && CUDA 8, using the base operator is sufficient (cf Bugs 1000, 1324)
   #define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \
     using Base::operator =;
 #elif EIGEN_COMP_CLANG // workaround clang bug (see http://forum.kde.org/viewtopic.php?f=74&t=102653)
@@ -986,7 +989,13 @@ namespace Eigen {
 #   define EIGEN_NOEXCEPT
 #   define EIGEN_NOEXCEPT_IF(x)
 #   define EIGEN_NO_THROW throw()
-#   define EIGEN_EXCEPTION_SPEC(X) throw(X)
+#   if EIGEN_COMP_MSVC
+      // MSVC does not support exception specifications (warning C4290),
+      // and they are deprecated in c++11 anyway.
+#     define EIGEN_EXCEPTION_SPEC(X) throw()
+#   else
+#     define EIGEN_EXCEPTION_SPEC(X) throw(X)
+#   endif
 #endif
 
 #endif // EIGEN_MACROS_H
diff --git a/xs/src/eigen/Eigen/src/Core/util/Memory.h b/xs/src/eigen/Eigen/src/Core/util/Memory.h
index c634d7ea0..66cdbd8dd 100644
--- a/xs/src/eigen/Eigen/src/Core/util/Memory.h
+++ b/xs/src/eigen/Eigen/src/Core/util/Memory.h
@@ -70,7 +70,7 @@ inline void throw_std_bad_alloc()
     throw std::bad_alloc();
   #else
     std::size_t huge = static_cast<std::size_t>(-1);
-    new int[huge];
+    ::operator new(huge);
   #endif
 }
 
@@ -493,7 +493,7 @@ template<typename T> struct smart_copy_helper<T,true> {
     IntPtr size = IntPtr(end)-IntPtr(start);
     if(size==0) return;
     eigen_internal_assert(start!=0 && end!=0 && target!=0);
-    memcpy(target, start, size);
+    std::memcpy(target, start, size);
   }
 };
 
@@ -696,7 +696,15 @@ template<typename T> void swap(scoped_array<T> &a,scoped_array<T> &b)
 /** \class aligned_allocator
 * \ingroup Core_Module
 *
-* \brief STL compatible allocator to use with with 16 byte aligned types
+* \brief STL compatible allocator to use with types requiring a non standrad alignment.
+*
+* The memory is aligned as for dynamically aligned matrix/array types such as MatrixXd.
+* By default, it will thus provide at least 16 bytes alignment and more in following cases:
+*  - 32 bytes alignment if AVX is enabled.
+*  - 64 bytes alignment if AVX512 is enabled.
+*
+* This can be controled using the \c EIGEN_MAX_ALIGN_BYTES macro as documented
+* \link TopicPreprocessorDirectivesPerformance there \endlink.
 *
 * Example:
 * \code
diff --git a/xs/src/eigen/Eigen/src/Core/util/Meta.h b/xs/src/eigen/Eigen/src/Core/util/Meta.h
index 7f6370755..1d73f05d6 100644
--- a/xs/src/eigen/Eigen/src/Core/util/Meta.h
+++ b/xs/src/eigen/Eigen/src/Core/util/Meta.h
@@ -485,6 +485,26 @@ T div_ceil(const T &a, const T &b)
   return (a+b-1) / b;
 }
 
+// The aim of the following functions is to bypass -Wfloat-equal warnings
+// when we really want a strict equality comparison on floating points.
+template<typename X, typename Y> EIGEN_STRONG_INLINE
+bool equal_strict(const X& x,const Y& y) { return x == y; }
+
+template<> EIGEN_STRONG_INLINE
+bool equal_strict(const float& x,const float& y) { return std::equal_to<float>()(x,y); }
+
+template<> EIGEN_STRONG_INLINE
+bool equal_strict(const double& x,const double& y) { return std::equal_to<double>()(x,y); }
+
+template<typename X, typename Y> EIGEN_STRONG_INLINE
+bool not_equal_strict(const X& x,const Y& y) { return x != y; }
+
+template<> EIGEN_STRONG_INLINE
+bool not_equal_strict(const float& x,const float& y) { return std::not_equal_to<float>()(x,y); }
+
+template<> EIGEN_STRONG_INLINE
+bool not_equal_strict(const double& x,const double& y) { return std::not_equal_to<double>()(x,y); }
+
 } // end namespace numext
 
 } // end namespace Eigen
diff --git a/xs/src/eigen/Eigen/src/Core/util/StaticAssert.h b/xs/src/eigen/Eigen/src/Core/util/StaticAssert.h
index 983361a45..500e47792 100644
--- a/xs/src/eigen/Eigen/src/Core/util/StaticAssert.h
+++ b/xs/src/eigen/Eigen/src/Core/util/StaticAssert.h
@@ -24,6 +24,7 @@
  *
  */
 
+#ifndef EIGEN_STATIC_ASSERT
 #ifndef EIGEN_NO_STATIC_ASSERT
 
   #if EIGEN_MAX_CPP_VER>=11 && (__has_feature(cxx_static_assert) || (defined(__cplusplus) && __cplusplus >= 201103L) || (EIGEN_COMP_MSVC >= 1600))
@@ -44,64 +45,65 @@
     struct static_assertion<true>
     {
       enum {
-        YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX,
-        YOU_MIXED_VECTORS_OF_DIFFERENT_SIZES,
-        YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES,
-        THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE,
-        THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE,
-        THIS_METHOD_IS_ONLY_FOR_OBJECTS_OF_A_SPECIFIC_SIZE,
-        OUT_OF_RANGE_ACCESS,
-        YOU_MADE_A_PROGRAMMING_MISTAKE,
-        EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT,
-        EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE,
-        YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR,
-        YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR,
-        UNALIGNED_LOAD_AND_STORE_OPERATIONS_UNIMPLEMENTED_ON_ALTIVEC,
-        THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES,
-        FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED,
-        NUMERIC_TYPE_MUST_BE_REAL,
-        COEFFICIENT_WRITE_ACCESS_TO_SELFADJOINT_NOT_SUPPORTED,
-        WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED,
-        THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE,
-        INVALID_MATRIX_PRODUCT,
-        INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS,
-        INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION,
-        YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY,
-        THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES,
-        THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES,
-        INVALID_MATRIX_TEMPLATE_PARAMETERS,
-        INVALID_MATRIXBASE_TEMPLATE_PARAMETERS,
-        BOTH_MATRICES_MUST_HAVE_THE_SAME_STORAGE_ORDER,
-        THIS_METHOD_IS_ONLY_FOR_DIAGONAL_MATRIX,
-        THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE,
-        THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES,
-        YOU_ALREADY_SPECIFIED_THIS_STRIDE,
-        INVALID_STORAGE_ORDER_FOR_THIS_VECTOR_EXPRESSION,
-        THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD,
-        PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1,
-        THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS,
-        YOU_CANNOT_MIX_ARRAYS_AND_MATRICES,
-        YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION,
-        THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY,
-        YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT,
-        THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS,
-        THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS,
-        THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL,
-        THIS_METHOD_IS_ONLY_FOR_ARRAYS_NOT_MATRICES,
-        YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED,
-        YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED,
-        THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE,
-        THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH,
-        OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG,
-        IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY,
-        STORAGE_LAYOUT_DOES_NOT_MATCH,
-        EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT__INVALID_COST_VALUE,
-        THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS,
-        MATRIX_FREE_CONJUGATE_GRADIENT_IS_COMPATIBLE_WITH_UPPER_UNION_LOWER_MODE_ONLY,
-        THIS_TYPE_IS_NOT_SUPPORTED,
-        STORAGE_KIND_MUST_MATCH,
-        STORAGE_INDEX_MUST_MATCH,
-        CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY
+        YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX=1,
+        YOU_MIXED_VECTORS_OF_DIFFERENT_SIZES=1,
+        YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES=1,
+        THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE=1,
+        THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE=1,
+        THIS_METHOD_IS_ONLY_FOR_OBJECTS_OF_A_SPECIFIC_SIZE=1,
+        OUT_OF_RANGE_ACCESS=1,
+        YOU_MADE_A_PROGRAMMING_MISTAKE=1,
+        EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT=1,
+        EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE=1,
+        YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR=1,
+        YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR=1,
+        UNALIGNED_LOAD_AND_STORE_OPERATIONS_UNIMPLEMENTED_ON_ALTIVEC=1,
+        THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES=1,
+        FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED=1,
+        NUMERIC_TYPE_MUST_BE_REAL=1,
+        COEFFICIENT_WRITE_ACCESS_TO_SELFADJOINT_NOT_SUPPORTED=1,
+        WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED=1,
+        THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE=1,
+        INVALID_MATRIX_PRODUCT=1,
+        INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS=1,
+        INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION=1,
+        YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY=1,
+        THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES=1,
+        THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES=1,
+        INVALID_MATRIX_TEMPLATE_PARAMETERS=1,
+        INVALID_MATRIXBASE_TEMPLATE_PARAMETERS=1,
+        BOTH_MATRICES_MUST_HAVE_THE_SAME_STORAGE_ORDER=1,
+        THIS_METHOD_IS_ONLY_FOR_DIAGONAL_MATRIX=1,
+        THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE=1,
+        THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES=1,
+        YOU_ALREADY_SPECIFIED_THIS_STRIDE=1,
+        INVALID_STORAGE_ORDER_FOR_THIS_VECTOR_EXPRESSION=1,
+        THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD=1,
+        PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1=1,
+        THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS=1,
+        YOU_CANNOT_MIX_ARRAYS_AND_MATRICES=1,
+        YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION=1,
+        THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY=1,
+        YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT=1,
+        THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS=1,
+        THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS=1,
+        THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL=1,
+        THIS_METHOD_IS_ONLY_FOR_ARRAYS_NOT_MATRICES=1,
+        YOU_PASSED_A_ROW_VECTOR_BUT_A_COLUMN_VECTOR_WAS_EXPECTED=1,
+        YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED=1,
+        THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE=1,
+        THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH=1,
+        OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG=1,
+        IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY=1,
+        STORAGE_LAYOUT_DOES_NOT_MATCH=1,
+        EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT__INVALID_COST_VALUE=1,
+        THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS=1,
+        MATRIX_FREE_CONJUGATE_GRADIENT_IS_COMPATIBLE_WITH_UPPER_UNION_LOWER_MODE_ONLY=1,
+        THIS_TYPE_IS_NOT_SUPPORTED=1,
+        STORAGE_KIND_MUST_MATCH=1,
+        STORAGE_INDEX_MUST_MATCH=1,
+        CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY=1,
+        SELFADJOINTVIEW_ACCEPTS_UPPER_AND_LOWER_MODE_ONLY=1
       };
     };
 
@@ -131,7 +133,7 @@
   #define EIGEN_STATIC_ASSERT(CONDITION,MSG) eigen_assert((CONDITION) && #MSG);
 
 #endif // EIGEN_NO_STATIC_ASSERT
-
+#endif // EIGEN_STATIC_ASSERT
 
 // static assertion failing if the type \a TYPE is not a vector type
 #define EIGEN_STATIC_ASSERT_VECTOR_ONLY(TYPE) \
diff --git a/xs/src/eigen/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h b/xs/src/eigen/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h
index 36a91dffc..87d789b3f 100644
--- a/xs/src/eigen/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h
+++ b/xs/src/eigen/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h
@@ -311,7 +311,6 @@ GeneralizedEigenSolver<MatrixType>::compute(const MatrixType& A, const MatrixTyp
     // Aliases:
     Map<VectorType> v(reinterpret_cast<Scalar*>(m_tmp.data()), size);
     ComplexVectorType &cv = m_tmp;
-    const MatrixType &mZ = m_realQZ.matrixZ();
     const MatrixType &mS = m_realQZ.matrixS();
     const MatrixType &mT = m_realQZ.matrixT();
 
@@ -351,7 +350,7 @@ GeneralizedEigenSolver<MatrixType>::compute(const MatrixType& A, const MatrixTyp
               }
             }
           }
-          m_eivec.col(i).real().noalias() = mZ.transpose() * v;
+          m_eivec.col(i).real().noalias() = m_realQZ.matrixZ().transpose() * v;
           m_eivec.col(i).real().normalize();
           m_eivec.col(i).imag().setConstant(0);
         }
@@ -400,7 +399,7 @@ GeneralizedEigenSolver<MatrixType>::compute(const MatrixType& A, const MatrixTyp
                               / (alpha*mT.coeffRef(j,j) - static_cast<Scalar>(beta*mS.coeffRef(j,j)));
             }
           }
-          m_eivec.col(i+1).noalias() = (mZ.transpose() * cv);
+          m_eivec.col(i+1).noalias() = (m_realQZ.matrixZ().transpose() * cv);
           m_eivec.col(i+1).normalize();
           m_eivec.col(i) = m_eivec.col(i+1).conjugate();
         }
diff --git a/xs/src/eigen/Eigen/src/Eigenvalues/RealSchur.h b/xs/src/eigen/Eigen/src/Eigenvalues/RealSchur.h
index f5c86041d..17ea903f5 100644
--- a/xs/src/eigen/Eigen/src/Eigenvalues/RealSchur.h
+++ b/xs/src/eigen/Eigen/src/Eigenvalues/RealSchur.h
@@ -303,7 +303,7 @@ RealSchur<MatrixType>& RealSchur<MatrixType>::computeFromHessenberg(const HessMa
   Scalar exshift(0);   // sum of exceptional shifts
   Scalar norm = computeNormOfT();
 
-  if(norm!=0)
+  if(norm!=Scalar(0))
   {
     while (iu >= 0)
     {
@@ -327,7 +327,7 @@ RealSchur<MatrixType>& RealSchur<MatrixType>::computeFromHessenberg(const HessMa
       else // No convergence yet
       {
         // The firstHouseholderVector vector has to be initialized to something to get rid of a silly GCC warning (-O1 -Wall -DNDEBUG )
-        Vector3s firstHouseholderVector(0,0,0), shiftInfo;
+        Vector3s firstHouseholderVector = Vector3s::Zero(), shiftInfo;
         computeShift(iu, iter, exshift, shiftInfo);
         iter = iter + 1;
         totalIter = totalIter + 1;
diff --git a/xs/src/eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h b/xs/src/eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h
index 3891cf883..b0c947dc0 100644
--- a/xs/src/eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h
+++ b/xs/src/eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h
@@ -37,7 +37,7 @@ namespace Eigen {
 
 /** \internal Specialization for the data types supported by LAPACKe */
 
-#define EIGEN_LAPACKE_EIG_SELFADJ(EIGTYPE, LAPACKE_TYPE, LAPACKE_RTYPE, LAPACKE_NAME, EIGCOLROW, LAPACKE_COLROW ) \
+#define EIGEN_LAPACKE_EIG_SELFADJ_2(EIGTYPE, LAPACKE_TYPE, LAPACKE_RTYPE, LAPACKE_NAME, EIGCOLROW ) \
 template<> template<typename InputType> inline \
 SelfAdjointEigenSolver<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >& \
 SelfAdjointEigenSolver<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >::compute(const EigenBase<InputType>& matrix, int options) \
@@ -47,7 +47,7 @@ SelfAdjointEigenSolver<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >::compute(c
           && (options&EigVecMask)!=EigVecMask \
           && "invalid option parameter"); \
   bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors; \
-  lapack_int n = internal::convert_index<lapack_int>(matrix.cols()), lda, matrix_order, info; \
+  lapack_int n = internal::convert_index<lapack_int>(matrix.cols()), lda, info; \
   m_eivalues.resize(n,1); \
   m_subdiag.resize(n-1); \
   m_eivec = matrix; \
@@ -63,27 +63,24 @@ SelfAdjointEigenSolver<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >::compute(c
   } \
 \
   lda = internal::convert_index<lapack_int>(m_eivec.outerStride()); \
-  matrix_order=LAPACKE_COLROW; \
   char jobz, uplo='L'/*, range='A'*/; \
   jobz = computeEigenvectors ? 'V' : 'N'; \
 \
-  info = LAPACKE_##LAPACKE_NAME( matrix_order, jobz, uplo, n, (LAPACKE_TYPE*)m_eivec.data(), lda, (LAPACKE_RTYPE*)m_eivalues.data() ); \
+  info = LAPACKE_##LAPACKE_NAME( LAPACK_COL_MAJOR, jobz, uplo, n, (LAPACKE_TYPE*)m_eivec.data(), lda, (LAPACKE_RTYPE*)m_eivalues.data() ); \
   m_info = (info==0) ? Success : NoConvergence; \
   m_isInitialized = true; \
   m_eigenvectorsOk = computeEigenvectors; \
   return *this; \
 }
 
+#define EIGEN_LAPACKE_EIG_SELFADJ(EIGTYPE, LAPACKE_TYPE, LAPACKE_RTYPE, LAPACKE_NAME )              \
+        EIGEN_LAPACKE_EIG_SELFADJ_2(EIGTYPE, LAPACKE_TYPE, LAPACKE_RTYPE, LAPACKE_NAME, ColMajor )  \
+        EIGEN_LAPACKE_EIG_SELFADJ_2(EIGTYPE, LAPACKE_TYPE, LAPACKE_RTYPE, LAPACKE_NAME, RowMajor ) 
 
-EIGEN_LAPACKE_EIG_SELFADJ(double,   double,                double, dsyev, ColMajor, LAPACK_COL_MAJOR)
-EIGEN_LAPACKE_EIG_SELFADJ(float,    float,                 float,  ssyev, ColMajor, LAPACK_COL_MAJOR)
-EIGEN_LAPACKE_EIG_SELFADJ(dcomplex, lapack_complex_double, double, zheev, ColMajor, LAPACK_COL_MAJOR)
-EIGEN_LAPACKE_EIG_SELFADJ(scomplex, lapack_complex_float,  float,  cheev, ColMajor, LAPACK_COL_MAJOR)
-
-EIGEN_LAPACKE_EIG_SELFADJ(double,   double,                double, dsyev, RowMajor, LAPACK_ROW_MAJOR)
-EIGEN_LAPACKE_EIG_SELFADJ(float,    float,                 float,  ssyev, RowMajor, LAPACK_ROW_MAJOR)
-EIGEN_LAPACKE_EIG_SELFADJ(dcomplex, lapack_complex_double, double, zheev, RowMajor, LAPACK_ROW_MAJOR)
-EIGEN_LAPACKE_EIG_SELFADJ(scomplex, lapack_complex_float,  float,  cheev, RowMajor, LAPACK_ROW_MAJOR)
+EIGEN_LAPACKE_EIG_SELFADJ(double,   double,                double, dsyev)
+EIGEN_LAPACKE_EIG_SELFADJ(float,    float,                 float,  ssyev)
+EIGEN_LAPACKE_EIG_SELFADJ(dcomplex, lapack_complex_double, double, zheev)
+EIGEN_LAPACKE_EIG_SELFADJ(scomplex, lapack_complex_float,  float,  cheev)
 
 } // end namespace Eigen
 
diff --git a/xs/src/eigen/Eigen/src/Geometry/AngleAxis.h b/xs/src/eigen/Eigen/src/Geometry/AngleAxis.h
index 0af3c1b08..83ee1be46 100644
--- a/xs/src/eigen/Eigen/src/Geometry/AngleAxis.h
+++ b/xs/src/eigen/Eigen/src/Geometry/AngleAxis.h
@@ -178,7 +178,7 @@ EIGEN_DEVICE_FUNC AngleAxis<Scalar>& AngleAxis<Scalar>::operator=(const Quaterni
   if (n != Scalar(0))
   {
     m_angle = Scalar(2)*atan2(n, abs(q.w()));
-    if(q.w() < 0)
+    if(q.w() < Scalar(0))
       n = -n;
     m_axis  = q.vec() / n;
   }
diff --git a/xs/src/eigen/Eigen/src/Geometry/Quaternion.h b/xs/src/eigen/Eigen/src/Geometry/Quaternion.h
index f6ef1bcf6..c3fd8c3e0 100644
--- a/xs/src/eigen/Eigen/src/Geometry/Quaternion.h
+++ b/xs/src/eigen/Eigen/src/Geometry/Quaternion.h
@@ -43,6 +43,11 @@ class QuaternionBase : public RotationBase<Derived, 3>
   typedef typename internal::traits<Derived>::Scalar Scalar;
   typedef typename NumTraits<Scalar>::Real RealScalar;
   typedef typename internal::traits<Derived>::Coefficients Coefficients;
+  typedef typename Coefficients::CoeffReturnType CoeffReturnType;
+  typedef typename internal::conditional<bool(internal::traits<Derived>::Flags&LvalueBit),
+                                        Scalar&, CoeffReturnType>::type NonConstCoeffReturnType;
+
+
   enum {
     Flags = Eigen::internal::traits<Derived>::Flags
   };
@@ -58,22 +63,22 @@ class QuaternionBase : public RotationBase<Derived, 3>
 
 
   /** \returns the \c x coefficient */
-  EIGEN_DEVICE_FUNC inline Scalar x() const { return this->derived().coeffs().coeff(0); }
+  EIGEN_DEVICE_FUNC inline CoeffReturnType x() const { return this->derived().coeffs().coeff(0); }
   /** \returns the \c y coefficient */
-  EIGEN_DEVICE_FUNC inline Scalar y() const { return this->derived().coeffs().coeff(1); }
+  EIGEN_DEVICE_FUNC inline CoeffReturnType y() const { return this->derived().coeffs().coeff(1); }
   /** \returns the \c z coefficient */
-  EIGEN_DEVICE_FUNC inline Scalar z() const { return this->derived().coeffs().coeff(2); }
+  EIGEN_DEVICE_FUNC inline CoeffReturnType z() const { return this->derived().coeffs().coeff(2); }
   /** \returns the \c w coefficient */
-  EIGEN_DEVICE_FUNC inline Scalar w() const { return this->derived().coeffs().coeff(3); }
+  EIGEN_DEVICE_FUNC inline CoeffReturnType w() const { return this->derived().coeffs().coeff(3); }
 
-  /** \returns a reference to the \c x coefficient */
-  EIGEN_DEVICE_FUNC inline Scalar& x() { return this->derived().coeffs().coeffRef(0); }
-  /** \returns a reference to the \c y coefficient */
-  EIGEN_DEVICE_FUNC inline Scalar& y() { return this->derived().coeffs().coeffRef(1); }
-  /** \returns a reference to the \c z coefficient */
-  EIGEN_DEVICE_FUNC inline Scalar& z() { return this->derived().coeffs().coeffRef(2); }
-  /** \returns a reference to the \c w coefficient */
-  EIGEN_DEVICE_FUNC inline Scalar& w() { return this->derived().coeffs().coeffRef(3); }
+  /** \returns a reference to the \c x coefficient (if Derived is a non-const lvalue) */
+  EIGEN_DEVICE_FUNC inline NonConstCoeffReturnType x() { return this->derived().coeffs().x(); }
+  /** \returns a reference to the \c y coefficient (if Derived is a non-const lvalue) */
+  EIGEN_DEVICE_FUNC inline NonConstCoeffReturnType y() { return this->derived().coeffs().y(); }
+  /** \returns a reference to the \c z coefficient (if Derived is a non-const lvalue) */
+  EIGEN_DEVICE_FUNC inline NonConstCoeffReturnType z() { return this->derived().coeffs().z(); }
+  /** \returns a reference to the \c w coefficient (if Derived is a non-const lvalue) */
+  EIGEN_DEVICE_FUNC inline NonConstCoeffReturnType w() { return this->derived().coeffs().w(); }
 
   /** \returns a read-only vector expression of the imaginary part (x,y,z) */
   EIGEN_DEVICE_FUNC inline const VectorBlock<const Coefficients,3> vec() const { return coeffs().template head<3>(); }
@@ -423,7 +428,7 @@ typedef Map<Quaternion<double>, Aligned>  QuaternionMapAlignedd;
 // Generic Quaternion * Quaternion product
 // This product can be specialized for a given architecture via the Arch template argument.
 namespace internal {
-template<int Arch, class Derived1, class Derived2, typename Scalar, int _Options> struct quat_product
+template<int Arch, class Derived1, class Derived2, typename Scalar> struct quat_product
 {
   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Quaternion<Scalar> run(const QuaternionBase<Derived1>& a, const QuaternionBase<Derived2>& b){
     return Quaternion<Scalar>
@@ -446,8 +451,7 @@ QuaternionBase<Derived>::operator* (const QuaternionBase<OtherDerived>& other) c
   EIGEN_STATIC_ASSERT((internal::is_same<typename Derived::Scalar, typename OtherDerived::Scalar>::value),
    YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
   return internal::quat_product<Architecture::Target, Derived, OtherDerived,
-                         typename internal::traits<Derived>::Scalar,
-                         EIGEN_PLAIN_ENUM_MIN(internal::traits<Derived>::Alignment, internal::traits<OtherDerived>::Alignment)>::run(*this, other);
+                         typename internal::traits<Derived>::Scalar>::run(*this, other);
 }
 
 /** \sa operator*(Quaternion) */
@@ -672,7 +676,7 @@ EIGEN_DEVICE_FUNC inline Quaternion<typename internal::traits<Derived>::Scalar>
 
 // Generic conjugate of a Quaternion
 namespace internal {
-template<int Arch, class Derived, typename Scalar, int _Options> struct quat_conj
+template<int Arch, class Derived, typename Scalar> struct quat_conj
 {
   EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Quaternion<Scalar> run(const QuaternionBase<Derived>& q){
     return Quaternion<Scalar>(q.w(),-q.x(),-q.y(),-q.z());
@@ -691,8 +695,7 @@ EIGEN_DEVICE_FUNC inline Quaternion<typename internal::traits<Derived>::Scalar>
 QuaternionBase<Derived>::conjugate() const
 {
   return internal::quat_conj<Architecture::Target, Derived,
-                         typename internal::traits<Derived>::Scalar,
-                         internal::traits<Derived>::Alignment>::run(*this);
+                         typename internal::traits<Derived>::Scalar>::run(*this);
                          
 }
 
diff --git a/xs/src/eigen/Eigen/src/Geometry/arch/Geometry_SSE.h b/xs/src/eigen/Eigen/src/Geometry/arch/Geometry_SSE.h
index 1a86ff837..f68cab583 100644
--- a/xs/src/eigen/Eigen/src/Geometry/arch/Geometry_SSE.h
+++ b/xs/src/eigen/Eigen/src/Geometry/arch/Geometry_SSE.h
@@ -16,17 +16,23 @@ namespace Eigen {
 namespace internal {
 
 template<class Derived, class OtherDerived>
-struct quat_product<Architecture::SSE, Derived, OtherDerived, float, Aligned16>
+struct quat_product<Architecture::SSE, Derived, OtherDerived, float>
 {
+  enum {
+    AAlignment = traits<Derived>::Alignment,
+    BAlignment = traits<OtherDerived>::Alignment,
+    ResAlignment = traits<Quaternion<float> >::Alignment
+  };
   static inline Quaternion<float> run(const QuaternionBase<Derived>& _a, const QuaternionBase<OtherDerived>& _b)
   {
     Quaternion<float> res;
     const __m128 mask = _mm_setr_ps(0.f,0.f,0.f,-0.f);
-    __m128 a = _a.coeffs().template packet<Aligned16>(0);
-    __m128 b = _b.coeffs().template packet<Aligned16>(0);
+    __m128 a = _a.coeffs().template packet<AAlignment>(0);
+    __m128 b = _b.coeffs().template packet<BAlignment>(0);
     __m128 s1 = _mm_mul_ps(vec4f_swizzle1(a,1,2,0,2),vec4f_swizzle1(b,2,0,1,2));
     __m128 s2 = _mm_mul_ps(vec4f_swizzle1(a,3,3,3,1),vec4f_swizzle1(b,0,1,2,1));
-    pstore(&res.x(),
+    pstoret<float,Packet4f,ResAlignment>(
+              &res.x(),
               _mm_add_ps(_mm_sub_ps(_mm_mul_ps(a,vec4f_swizzle1(b,3,3,3,3)),
                                     _mm_mul_ps(vec4f_swizzle1(a,2,0,1,0),
                                                vec4f_swizzle1(b,1,2,0,0))),
@@ -36,14 +42,17 @@ struct quat_product<Architecture::SSE, Derived, OtherDerived, float, Aligned16>
   }
 };
 
-template<class Derived, int Alignment>
-struct quat_conj<Architecture::SSE, Derived, float, Alignment>
+template<class Derived>
+struct quat_conj<Architecture::SSE, Derived, float>
 {
+  enum {
+    ResAlignment = traits<Quaternion<float> >::Alignment
+  };
   static inline Quaternion<float> run(const QuaternionBase<Derived>& q)
   {
     Quaternion<float> res;
     const __m128 mask = _mm_setr_ps(-0.f,-0.f,-0.f,0.f);
-    pstore(&res.x(), _mm_xor_ps(mask, q.coeffs().template packet<Alignment>(0)));
+    pstoret<float,Packet4f,ResAlignment>(&res.x(), _mm_xor_ps(mask, q.coeffs().template packet<traits<Derived>::Alignment>(0)));
     return res;
   }
 };
@@ -52,6 +61,9 @@ struct quat_conj<Architecture::SSE, Derived, float, Alignment>
 template<typename VectorLhs,typename VectorRhs>
 struct cross3_impl<Architecture::SSE,VectorLhs,VectorRhs,float,true>
 {
+  enum {
+    ResAlignment = traits<typename plain_matrix_type<VectorLhs>::type>::Alignment
+  };
   static inline typename plain_matrix_type<VectorLhs>::type
   run(const VectorLhs& lhs, const VectorRhs& rhs)
   {
@@ -60,7 +72,7 @@ struct cross3_impl<Architecture::SSE,VectorLhs,VectorRhs,float,true>
     __m128 mul1=_mm_mul_ps(vec4f_swizzle1(a,1,2,0,3),vec4f_swizzle1(b,2,0,1,3));
     __m128 mul2=_mm_mul_ps(vec4f_swizzle1(a,2,0,1,3),vec4f_swizzle1(b,1,2,0,3));
     typename plain_matrix_type<VectorLhs>::type res;
-    pstore(&res.x(),_mm_sub_ps(mul1,mul2));
+    pstoret<float,Packet4f,ResAlignment>(&res.x(),_mm_sub_ps(mul1,mul2));
     return res;
   }
 };
@@ -68,9 +80,14 @@ struct cross3_impl<Architecture::SSE,VectorLhs,VectorRhs,float,true>
 
 
 
-template<class Derived, class OtherDerived, int Alignment>
-struct quat_product<Architecture::SSE, Derived, OtherDerived, double, Alignment>
+template<class Derived, class OtherDerived>
+struct quat_product<Architecture::SSE, Derived, OtherDerived, double>
 {
+  enum {
+    BAlignment = traits<OtherDerived>::Alignment,
+    ResAlignment = traits<Quaternion<double> >::Alignment
+  };
+
   static inline Quaternion<double> run(const QuaternionBase<Derived>& _a, const QuaternionBase<OtherDerived>& _b)
   {
   const Packet2d mask = _mm_castsi128_pd(_mm_set_epi32(0x0,0x0,0x80000000,0x0));
@@ -78,8 +95,8 @@ struct quat_product<Architecture::SSE, Derived, OtherDerived, double, Alignment>
   Quaternion<double> res;
 
   const double* a = _a.coeffs().data();
-  Packet2d b_xy = _b.coeffs().template packet<Alignment>(0);
-  Packet2d b_zw = _b.coeffs().template packet<Alignment>(2);
+  Packet2d b_xy = _b.coeffs().template packet<BAlignment>(0);
+  Packet2d b_zw = _b.coeffs().template packet<BAlignment>(2);
   Packet2d a_xx = pset1<Packet2d>(a[0]);
   Packet2d a_yy = pset1<Packet2d>(a[1]);
   Packet2d a_zz = pset1<Packet2d>(a[2]);
@@ -97,9 +114,9 @@ struct quat_product<Architecture::SSE, Derived, OtherDerived, double, Alignment>
   t2 = psub(pmul(a_zz, b_xy), pmul(a_xx, b_zw));
 #ifdef EIGEN_VECTORIZE_SSE3
   EIGEN_UNUSED_VARIABLE(mask)
-  pstore(&res.x(), _mm_addsub_pd(t1, preverse(t2)));
+  pstoret<double,Packet2d,ResAlignment>(&res.x(), _mm_addsub_pd(t1, preverse(t2)));
 #else
-  pstore(&res.x(), padd(t1, pxor(mask,preverse(t2))));
+  pstoret<double,Packet2d,ResAlignment>(&res.x(), padd(t1, pxor(mask,preverse(t2))));
 #endif
   
   /*
@@ -111,25 +128,28 @@ struct quat_product<Architecture::SSE, Derived, OtherDerived, double, Alignment>
   t2 = padd(pmul(a_zz, b_zw), pmul(a_xx, b_xy));
 #ifdef EIGEN_VECTORIZE_SSE3
   EIGEN_UNUSED_VARIABLE(mask)
-  pstore(&res.z(), preverse(_mm_addsub_pd(preverse(t1), t2)));
+  pstoret<double,Packet2d,ResAlignment>(&res.z(), preverse(_mm_addsub_pd(preverse(t1), t2)));
 #else
-  pstore(&res.z(), psub(t1, pxor(mask,preverse(t2))));
+  pstoret<double,Packet2d,ResAlignment>(&res.z(), psub(t1, pxor(mask,preverse(t2))));
 #endif
 
   return res;
 }
 };
 
-template<class Derived, int Alignment>
-struct quat_conj<Architecture::SSE, Derived, double, Alignment>
+template<class Derived>
+struct quat_conj<Architecture::SSE, Derived, double>
 {
+  enum {
+    ResAlignment = traits<Quaternion<double> >::Alignment
+  };
   static inline Quaternion<double> run(const QuaternionBase<Derived>& q)
   {
     Quaternion<double> res;
     const __m128d mask0 = _mm_setr_pd(-0.,-0.);
     const __m128d mask2 = _mm_setr_pd(-0.,0.);
-    pstore(&res.x(), _mm_xor_pd(mask0, q.coeffs().template packet<Alignment>(0)));
-    pstore(&res.z(), _mm_xor_pd(mask2, q.coeffs().template packet<Alignment>(2)));
+    pstoret<double,Packet2d,ResAlignment>(&res.x(), _mm_xor_pd(mask0, q.coeffs().template packet<traits<Derived>::Alignment>(0)));
+    pstoret<double,Packet2d,ResAlignment>(&res.z(), _mm_xor_pd(mask2, q.coeffs().template packet<traits<Derived>::Alignment>(2)));
     return res;
   }
 };
diff --git a/xs/src/eigen/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h b/xs/src/eigen/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
index 358444aff..f66c846ef 100644
--- a/xs/src/eigen/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
+++ b/xs/src/eigen/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
@@ -152,13 +152,28 @@ class LeastSquareDiagonalPreconditioner : public DiagonalPreconditioner<_Scalar>
     {
       // Compute the inverse squared-norm of each column of mat
       m_invdiag.resize(mat.cols());
-      for(Index j=0; j<mat.outerSize(); ++j)
+      if(MatType::IsRowMajor)
       {
-        RealScalar sum = mat.innerVector(j).squaredNorm();
-        if(sum>0)
-          m_invdiag(j) = RealScalar(1)/sum;
-        else
-          m_invdiag(j) = RealScalar(1);
+        m_invdiag.setZero();
+        for(Index j=0; j<mat.outerSize(); ++j)
+        {
+          for(typename MatType::InnerIterator it(mat,j); it; ++it)
+            m_invdiag(it.index()) += numext::abs2(it.value());
+        }
+        for(Index j=0; j<mat.cols(); ++j)
+          if(numext::real(m_invdiag(j))>RealScalar(0))
+            m_invdiag(j) = RealScalar(1)/numext::real(m_invdiag(j));
+      }
+      else
+      {
+        for(Index j=0; j<mat.outerSize(); ++j)
+        {
+          RealScalar sum = mat.col(j).squaredNorm();
+          if(sum>RealScalar(0))
+            m_invdiag(j) = RealScalar(1)/sum;
+          else
+            m_invdiag(j) = RealScalar(1);
+        }
       }
       Base::m_isInitialized = true;
       return *this;
diff --git a/xs/src/eigen/Eigen/src/Jacobi/Jacobi.h b/xs/src/eigen/Eigen/src/Jacobi/Jacobi.h
index d25af8e90..437e666a3 100644
--- a/xs/src/eigen/Eigen/src/Jacobi/Jacobi.h
+++ b/xs/src/eigen/Eigen/src/Jacobi/Jacobi.h
@@ -298,12 +298,144 @@ inline void MatrixBase<Derived>::applyOnTheRight(Index p, Index q, const JacobiR
 }
 
 namespace internal {
+
+template<typename Scalar, typename OtherScalar,
+         int SizeAtCompileTime, int MinAlignment, bool Vectorizable>
+struct apply_rotation_in_the_plane_selector
+{
+  static inline void run(Scalar *x, Index incrx, Scalar *y, Index incry, Index size, OtherScalar c, OtherScalar s)
+  {
+    for(Index i=0; i<size; ++i)
+    {
+      Scalar xi = *x;
+      Scalar yi = *y;
+      *x =  c * xi + numext::conj(s) * yi;
+      *y = -s * xi + numext::conj(c) * yi;
+      x += incrx;
+      y += incry;
+    }
+  }
+};
+
+template<typename Scalar, typename OtherScalar,
+         int SizeAtCompileTime, int MinAlignment>
+struct apply_rotation_in_the_plane_selector<Scalar,OtherScalar,SizeAtCompileTime,MinAlignment,true /* vectorizable */>
+{
+  static inline void run(Scalar *x, Index incrx, Scalar *y, Index incry, Index size, OtherScalar c, OtherScalar s)
+  {
+    enum {
+      PacketSize = packet_traits<Scalar>::size,
+      OtherPacketSize = packet_traits<OtherScalar>::size
+    };
+    typedef typename packet_traits<Scalar>::type Packet;
+    typedef typename packet_traits<OtherScalar>::type OtherPacket;
+
+    /*** dynamic-size vectorized paths ***/
+    if(SizeAtCompileTime == Dynamic && ((incrx==1 && incry==1) || PacketSize == 1))
+    {
+      // both vectors are sequentially stored in memory => vectorization
+      enum { Peeling = 2 };
+
+      Index alignedStart = internal::first_default_aligned(y, size);
+      Index alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize;
+
+      const OtherPacket pc = pset1<OtherPacket>(c);
+      const OtherPacket ps = pset1<OtherPacket>(s);
+      conj_helper<OtherPacket,Packet,NumTraits<OtherScalar>::IsComplex,false> pcj;
+      conj_helper<OtherPacket,Packet,false,false> pm;
+
+      for(Index i=0; i<alignedStart; ++i)
+      {
+        Scalar xi = x[i];
+        Scalar yi = y[i];
+        x[i] =  c * xi + numext::conj(s) * yi;
+        y[i] = -s * xi + numext::conj(c) * yi;
+      }
+
+      Scalar* EIGEN_RESTRICT px = x + alignedStart;
+      Scalar* EIGEN_RESTRICT py = y + alignedStart;
+
+      if(internal::first_default_aligned(x, size)==alignedStart)
+      {
+        for(Index i=alignedStart; i<alignedEnd; i+=PacketSize)
+        {
+          Packet xi = pload<Packet>(px);
+          Packet yi = pload<Packet>(py);
+          pstore(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
+          pstore(py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
+          px += PacketSize;
+          py += PacketSize;
+        }
+      }
+      else
+      {
+        Index peelingEnd = alignedStart + ((size-alignedStart)/(Peeling*PacketSize))*(Peeling*PacketSize);
+        for(Index i=alignedStart; i<peelingEnd; i+=Peeling*PacketSize)
+        {
+          Packet xi   = ploadu<Packet>(px);
+          Packet xi1  = ploadu<Packet>(px+PacketSize);
+          Packet yi   = pload <Packet>(py);
+          Packet yi1  = pload <Packet>(py+PacketSize);
+          pstoreu(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
+          pstoreu(px+PacketSize, padd(pm.pmul(pc,xi1),pcj.pmul(ps,yi1)));
+          pstore (py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
+          pstore (py+PacketSize, psub(pcj.pmul(pc,yi1),pm.pmul(ps,xi1)));
+          px += Peeling*PacketSize;
+          py += Peeling*PacketSize;
+        }
+        if(alignedEnd!=peelingEnd)
+        {
+          Packet xi = ploadu<Packet>(x+peelingEnd);
+          Packet yi = pload <Packet>(y+peelingEnd);
+          pstoreu(x+peelingEnd, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
+          pstore (y+peelingEnd, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
+        }
+      }
+
+      for(Index i=alignedEnd; i<size; ++i)
+      {
+        Scalar xi = x[i];
+        Scalar yi = y[i];
+        x[i] =  c * xi + numext::conj(s) * yi;
+        y[i] = -s * xi + numext::conj(c) * yi;
+      }
+    }
+
+    /*** fixed-size vectorized path ***/
+    else if(SizeAtCompileTime != Dynamic && MinAlignment>0) // FIXME should be compared to the required alignment
+    {
+      const OtherPacket pc = pset1<OtherPacket>(c);
+      const OtherPacket ps = pset1<OtherPacket>(s);
+      conj_helper<OtherPacket,Packet,NumTraits<OtherPacket>::IsComplex,false> pcj;
+      conj_helper<OtherPacket,Packet,false,false> pm;
+      Scalar* EIGEN_RESTRICT px = x;
+      Scalar* EIGEN_RESTRICT py = y;
+      for(Index i=0; i<size; i+=PacketSize)
+      {
+        Packet xi = pload<Packet>(px);
+        Packet yi = pload<Packet>(py);
+        pstore(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
+        pstore(py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
+        px += PacketSize;
+        py += PacketSize;
+      }
+    }
+
+    /*** non-vectorized path ***/
+    else
+    {
+      apply_rotation_in_the_plane_selector<Scalar,OtherScalar,SizeAtCompileTime,MinAlignment,false>::run(x,incrx,y,incry,size,c,s);
+    }
+  }
+};
+
 template<typename VectorX, typename VectorY, typename OtherScalar>
 void /*EIGEN_DONT_INLINE*/ apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x, DenseBase<VectorY>& xpr_y, const JacobiRotation<OtherScalar>& j)
 {
   typedef typename VectorX::Scalar Scalar;
-  enum { PacketSize = packet_traits<Scalar>::size };
-  typedef typename packet_traits<Scalar>::type Packet;
+  const bool Vectorizable =    (VectorX::Flags & VectorY::Flags & PacketAccessBit)
+                            && (int(packet_traits<Scalar>::size) == int(packet_traits<OtherScalar>::size));
+
   eigen_assert(xpr_x.size() == xpr_y.size());
   Index size = xpr_x.size();
   Index incrx = xpr_x.derived().innerStride();
@@ -317,113 +449,11 @@ void /*EIGEN_DONT_INLINE*/ apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x
   if (c==OtherScalar(1) && s==OtherScalar(0))
     return;
 
-  /*** dynamic-size vectorized paths ***/
-
-  if(VectorX::SizeAtCompileTime == Dynamic &&
-    (VectorX::Flags & VectorY::Flags & PacketAccessBit) &&
-    ((incrx==1 && incry==1) || PacketSize == 1))
-  {
-    // both vectors are sequentially stored in memory => vectorization
-    enum { Peeling = 2 };
-
-    Index alignedStart = internal::first_default_aligned(y, size);
-    Index alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize;
-
-    const Packet pc = pset1<Packet>(c);
-    const Packet ps = pset1<Packet>(s);
-    conj_helper<Packet,Packet,NumTraits<Scalar>::IsComplex,false> pcj;
-
-    for(Index i=0; i<alignedStart; ++i)
-    {
-      Scalar xi = x[i];
-      Scalar yi = y[i];
-      x[i] =  c * xi + numext::conj(s) * yi;
-      y[i] = -s * xi + numext::conj(c) * yi;
-    }
-
-    Scalar* EIGEN_RESTRICT px = x + alignedStart;
-    Scalar* EIGEN_RESTRICT py = y + alignedStart;
-
-    if(internal::first_default_aligned(x, size)==alignedStart)
-    {
-      for(Index i=alignedStart; i<alignedEnd; i+=PacketSize)
-      {
-        Packet xi = pload<Packet>(px);
-        Packet yi = pload<Packet>(py);
-        pstore(px, padd(pmul(pc,xi),pcj.pmul(ps,yi)));
-        pstore(py, psub(pcj.pmul(pc,yi),pmul(ps,xi)));
-        px += PacketSize;
-        py += PacketSize;
-      }
-    }
-    else
-    {
-      Index peelingEnd = alignedStart + ((size-alignedStart)/(Peeling*PacketSize))*(Peeling*PacketSize);
-      for(Index i=alignedStart; i<peelingEnd; i+=Peeling*PacketSize)
-      {
-        Packet xi   = ploadu<Packet>(px);
-        Packet xi1  = ploadu<Packet>(px+PacketSize);
-        Packet yi   = pload <Packet>(py);
-        Packet yi1  = pload <Packet>(py+PacketSize);
-        pstoreu(px, padd(pmul(pc,xi),pcj.pmul(ps,yi)));
-        pstoreu(px+PacketSize, padd(pmul(pc,xi1),pcj.pmul(ps,yi1)));
-        pstore (py, psub(pcj.pmul(pc,yi),pmul(ps,xi)));
-        pstore (py+PacketSize, psub(pcj.pmul(pc,yi1),pmul(ps,xi1)));
-        px += Peeling*PacketSize;
-        py += Peeling*PacketSize;
-      }
-      if(alignedEnd!=peelingEnd)
-      {
-        Packet xi = ploadu<Packet>(x+peelingEnd);
-        Packet yi = pload <Packet>(y+peelingEnd);
-        pstoreu(x+peelingEnd, padd(pmul(pc,xi),pcj.pmul(ps,yi)));
-        pstore (y+peelingEnd, psub(pcj.pmul(pc,yi),pmul(ps,xi)));
-      }
-    }
-
-    for(Index i=alignedEnd; i<size; ++i)
-    {
-      Scalar xi = x[i];
-      Scalar yi = y[i];
-      x[i] =  c * xi + numext::conj(s) * yi;
-      y[i] = -s * xi + numext::conj(c) * yi;
-    }
-  }
-
-  /*** fixed-size vectorized path ***/
-  else if(VectorX::SizeAtCompileTime != Dynamic &&
-          (VectorX::Flags & VectorY::Flags & PacketAccessBit) &&
-          (EIGEN_PLAIN_ENUM_MIN(evaluator<VectorX>::Alignment, evaluator<VectorY>::Alignment)>0)) // FIXME should be compared to the required alignment
-  {
-    const Packet pc = pset1<Packet>(c);
-    const Packet ps = pset1<Packet>(s);
-    conj_helper<Packet,Packet,NumTraits<Scalar>::IsComplex,false> pcj;
-    Scalar* EIGEN_RESTRICT px = x;
-    Scalar* EIGEN_RESTRICT py = y;
-    for(Index i=0; i<size; i+=PacketSize)
-    {
-      Packet xi = pload<Packet>(px);
-      Packet yi = pload<Packet>(py);
-      pstore(px, padd(pmul(pc,xi),pcj.pmul(ps,yi)));
-      pstore(py, psub(pcj.pmul(pc,yi),pmul(ps,xi)));
-      px += PacketSize;
-      py += PacketSize;
-    }
-  }
-
-  /*** non-vectorized path ***/
-  else
-  {
-    for(Index i=0; i<size; ++i)
-    {
-      Scalar xi = *x;
-      Scalar yi = *y;
-      *x =  c * xi + numext::conj(s) * yi;
-      *y = -s * xi + numext::conj(c) * yi;
-      x += incrx;
-      y += incry;
-    }
-  }
+  apply_rotation_in_the_plane_selector<
+    Scalar,OtherScalar,
+    VectorX::SizeAtCompileTime,
+    EIGEN_PLAIN_ENUM_MIN(evaluator<VectorX>::Alignment, evaluator<VectorY>::Alignment),
+    Vectorizable>::run(x,incrx,y,incry,size,c,s);
 }
 
 } // end namespace internal
diff --git a/xs/src/eigen/Eigen/src/LU/InverseImpl.h b/xs/src/eigen/Eigen/src/LU/InverseImpl.h
index 018f99b58..f49f23360 100644
--- a/xs/src/eigen/Eigen/src/LU/InverseImpl.h
+++ b/xs/src/eigen/Eigen/src/LU/InverseImpl.h
@@ -404,7 +404,7 @@ inline void MatrixBase<Derived>::computeInverseWithCheck(
     const RealScalar& absDeterminantThreshold
   ) const
 {
-  RealScalar determinant;
+  Scalar determinant;
   // i'd love to put some static assertions there, but SFINAE means that they have no effect...
   eigen_assert(rows() == cols());
   computeInverseAndDetWithCheck(inverse,determinant,invertible,absDeterminantThreshold);
diff --git a/xs/src/eigen/Eigen/src/OrderingMethods/Eigen_Colamd.h b/xs/src/eigen/Eigen/src/OrderingMethods/Eigen_Colamd.h
index 933cd564b..da85b4d6e 100644
--- a/xs/src/eigen/Eigen/src/OrderingMethods/Eigen_Colamd.h
+++ b/xs/src/eigen/Eigen/src/OrderingMethods/Eigen_Colamd.h
@@ -1004,7 +1004,7 @@ static IndexType find_ordering /* return the number of garbage collections */
     COLAMD_ASSERT (head [min_score] >= COLAMD_EMPTY) ;
 
     /* get pivot column from head of minimum degree list */
-    while (head [min_score] == COLAMD_EMPTY && min_score < n_col)
+    while (min_score < n_col && head [min_score] == COLAMD_EMPTY)
     {
       min_score++ ;
     }
diff --git a/xs/src/eigen/Eigen/src/PaStiXSupport/PaStiXSupport.h b/xs/src/eigen/Eigen/src/PaStiXSupport/PaStiXSupport.h
index d2ebfd7bb..160d8a523 100644
--- a/xs/src/eigen/Eigen/src/PaStiXSupport/PaStiXSupport.h
+++ b/xs/src/eigen/Eigen/src/PaStiXSupport/PaStiXSupport.h
@@ -64,28 +64,28 @@ namespace internal
     typedef typename _MatrixType::StorageIndex StorageIndex;
   };
   
-  void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, float *vals, int *perm, int * invp, float *x, int nbrhs, int *iparm, double *dparm)
+  inline void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, float *vals, int *perm, int * invp, float *x, int nbrhs, int *iparm, double *dparm)
   {
     if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
     if (nbrhs == 0) {x = NULL; nbrhs=1;}
     s_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm); 
   }
   
-  void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, double *vals, int *perm, int * invp, double *x, int nbrhs, int *iparm, double *dparm)
+  inline void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, double *vals, int *perm, int * invp, double *x, int nbrhs, int *iparm, double *dparm)
   {
     if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
     if (nbrhs == 0) {x = NULL; nbrhs=1;}
     d_pastix(pastix_data, pastix_comm, n, ptr, idx, vals, perm, invp, x, nbrhs, iparm, dparm); 
   }
   
-  void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<float> *vals, int *perm, int * invp, std::complex<float> *x, int nbrhs, int *iparm, double *dparm)
+  inline void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<float> *vals, int *perm, int * invp, std::complex<float> *x, int nbrhs, int *iparm, double *dparm)
   {
     if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
     if (nbrhs == 0) {x = NULL; nbrhs=1;}
     c_pastix(pastix_data, pastix_comm, n, ptr, idx, reinterpret_cast<PASTIX_COMPLEX*>(vals), perm, invp, reinterpret_cast<PASTIX_COMPLEX*>(x), nbrhs, iparm, dparm); 
   }
   
-  void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<double> *vals, int *perm, int * invp, std::complex<double> *x, int nbrhs, int *iparm, double *dparm)
+  inline void eigen_pastix(pastix_data_t **pastix_data, int pastix_comm, int n, int *ptr, int *idx, std::complex<double> *vals, int *perm, int * invp, std::complex<double> *x, int nbrhs, int *iparm, double *dparm)
   {
     if (n == 0) { ptr = NULL; idx = NULL; vals = NULL; }
     if (nbrhs == 0) {x = NULL; nbrhs=1;}
diff --git a/xs/src/eigen/Eigen/src/QR/ColPivHouseholderQR.h b/xs/src/eigen/Eigen/src/QR/ColPivHouseholderQR.h
index 0e47c8332..a7b47d55d 100644
--- a/xs/src/eigen/Eigen/src/QR/ColPivHouseholderQR.h
+++ b/xs/src/eigen/Eigen/src/QR/ColPivHouseholderQR.h
@@ -506,8 +506,8 @@ void ColPivHouseholderQR<MatrixType>::computeInPlace()
     m_colNormsUpdated.coeffRef(k) = m_colNormsDirect.coeffRef(k);
   }
 
-  RealScalar threshold_helper =  numext::abs2<Scalar>(m_colNormsUpdated.maxCoeff() * NumTraits<Scalar>::epsilon()) / RealScalar(rows);
-  RealScalar norm_downdate_threshold = numext::sqrt(NumTraits<Scalar>::epsilon());
+  RealScalar threshold_helper =  numext::abs2<RealScalar>(m_colNormsUpdated.maxCoeff() * NumTraits<RealScalar>::epsilon()) / RealScalar(rows);
+  RealScalar norm_downdate_threshold = numext::sqrt(NumTraits<RealScalar>::epsilon());
 
   m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
   m_maxpivot = RealScalar(0);
@@ -553,12 +553,12 @@ void ColPivHouseholderQR<MatrixType>::computeInPlace()
       // http://www.netlib.org/lapack/lawnspdf/lawn176.pdf
       // and used in LAPACK routines xGEQPF and xGEQP3.
       // See lines 278-297 in http://www.netlib.org/lapack/explore-html/dc/df4/sgeqpf_8f_source.html
-      if (m_colNormsUpdated.coeffRef(j) != 0) {
+      if (m_colNormsUpdated.coeffRef(j) != RealScalar(0)) {
         RealScalar temp = abs(m_qr.coeffRef(k, j)) / m_colNormsUpdated.coeffRef(j);
         temp = (RealScalar(1) + temp) * (RealScalar(1) - temp);
-        temp = temp < 0 ? 0 : temp;
-        RealScalar temp2 = temp * numext::abs2<Scalar>(m_colNormsUpdated.coeffRef(j) /
-                                                       m_colNormsDirect.coeffRef(j));
+        temp = temp <  RealScalar(0) ? RealScalar(0) : temp;
+        RealScalar temp2 = temp * numext::abs2<RealScalar>(m_colNormsUpdated.coeffRef(j) /
+                                                           m_colNormsDirect.coeffRef(j));
         if (temp2 <= norm_downdate_threshold) {
           // The updated norm has become too inaccurate so re-compute the column
           // norm directly.
diff --git a/xs/src/eigen/Eigen/src/SVD/BDCSVD.h b/xs/src/eigen/Eigen/src/SVD/BDCSVD.h
index 25fca6f4d..1134d66e7 100644
--- a/xs/src/eigen/Eigen/src/SVD/BDCSVD.h
+++ b/xs/src/eigen/Eigen/src/SVD/BDCSVD.h
@@ -11,7 +11,7 @@
 // Copyright (C) 2013 Jean Ceccato <jean.ceccato@ensimag.fr>
 // Copyright (C) 2013 Pierre Zoppitelli <pierre.zoppitelli@ensimag.fr>
 // Copyright (C) 2013 Jitse Niesen <jitse@maths.leeds.ac.uk>
-// Copyright (C) 2014-2016 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2014-2017 Gael Guennebaud <gael.guennebaud@inria.fr>
 //
 // Source Code Form is subject to the terms of the Mozilla
 // Public License v. 2.0. If a copy of the MPL was not distributed
@@ -77,6 +77,7 @@ public:
   typedef _MatrixType MatrixType;
   typedef typename MatrixType::Scalar Scalar;
   typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+  typedef typename NumTraits<RealScalar>::Literal Literal;
   enum {
     RowsAtCompileTime = MatrixType::RowsAtCompileTime, 
     ColsAtCompileTime = MatrixType::ColsAtCompileTime, 
@@ -259,7 +260,7 @@ BDCSVD<MatrixType>& BDCSVD<MatrixType>::compute(const MatrixType& matrix, unsign
   
   //**** step 0 - Copy the input matrix and apply scaling to reduce over/under-flows
   RealScalar scale = matrix.cwiseAbs().maxCoeff();
-  if(scale==RealScalar(0)) scale = RealScalar(1);
+  if(scale==Literal(0)) scale = Literal(1);
   MatrixX copy;
   if (m_isTranspose) copy = matrix.adjoint()/scale;
   else               copy = matrix/scale;
@@ -351,13 +352,13 @@ void BDCSVD<MatrixType>::structured_update(Block<MatrixXr,Dynamic,Dynamic> A, co
     Index k1=0, k2=0;
     for(Index j=0; j<n; ++j)
     {
-      if( (A.col(j).head(n1).array()!=0).any() )
+      if( (A.col(j).head(n1).array()!=Literal(0)).any() )
       {
         A1.col(k1) = A.col(j).head(n1);
         B1.row(k1) = B.row(j);
         ++k1;
       }
-      if( (A.col(j).tail(n2).array()!=0).any() )
+      if( (A.col(j).tail(n2).array()!=Literal(0)).any() )
       {
         A2.col(k2) = A.col(j).tail(n2);
         B2.row(k2) = B.row(j);
@@ -449,11 +450,11 @@ void BDCSVD<MatrixType>::divide (Index firstCol, Index lastCol, Index firstRowW,
     l = m_naiveU.row(1).segment(firstCol, k);
     f = m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1);
   }
-  if (m_compV) m_naiveV(firstRowW+k, firstColW) = 1;
+  if (m_compV) m_naiveV(firstRowW+k, firstColW) = Literal(1);
   if (r0<considerZero)
   {
-    c0 = 1;
-    s0 = 0;
+    c0 = Literal(1);
+    s0 = Literal(0);
   }
   else
   {
@@ -574,7 +575,7 @@ void BDCSVD<MatrixType>::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec
   ArrayRef col0 = m_computed.col(firstCol).segment(firstCol, n);
   m_workspace.head(n) =  m_computed.block(firstCol, firstCol, n, n).diagonal();
   ArrayRef diag = m_workspace.head(n);
-  diag(0) = 0;
+  diag(0) = Literal(0);
 
   // Allocate space for singular values and vectors
   singVals.resize(n);
@@ -590,7 +591,7 @@ void BDCSVD<MatrixType>::computeSVDofM(Index firstCol, Index n, MatrixXr& U, Vec
   // but others are interleaved and we must ignore them at this stage.
   // To this end, let's compute a permutation skipping them:
   Index actual_n = n;
-  while(actual_n>1 && diag(actual_n-1)==0) --actual_n;
+  while(actual_n>1 && diag(actual_n-1)==Literal(0)) --actual_n;
   Index m = 0; // size of the deflated problem
   for(Index k=0;k<actual_n;++k)
     if(abs(col0(k))>considerZero)
@@ -691,11 +692,13 @@ template <typename MatrixType>
 typename BDCSVD<MatrixType>::RealScalar BDCSVD<MatrixType>::secularEq(RealScalar mu, const ArrayRef& col0, const ArrayRef& diag, const IndicesRef &perm, const ArrayRef& diagShifted, RealScalar shift)
 {
   Index m = perm.size();
-  RealScalar res = 1;
+  RealScalar res = Literal(1);
   for(Index i=0; i<m; ++i)
   {
     Index j = perm(i);
-    res += numext::abs2(col0(j)) / ((diagShifted(j) - mu) * (diag(j) + shift + mu));
+    // The following expression could be rewritten to involve only a single division,
+    // but this would make the expression more sensitive to overflow.
+    res += (col0(j) / (diagShifted(j) - mu)) * (col0(j) / (diag(j) + shift + mu));
   }
   return res;
 
@@ -707,19 +710,22 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
 {
   using std::abs;
   using std::swap;
+  using std::sqrt;
 
   Index n = col0.size();
   Index actual_n = n;
-  while(actual_n>1 && col0(actual_n-1)==0) --actual_n;
+  // Note that here actual_n is computed based on col0(i)==0 instead of diag(i)==0 as above
+  // because 1) we have diag(i)==0 => col0(i)==0 and 2) if col0(i)==0, then diag(i) is already a singular value.
+  while(actual_n>1 && col0(actual_n-1)==Literal(0)) --actual_n;
 
   for (Index k = 0; k < n; ++k)
   {
-    if (col0(k) == 0 || actual_n==1)
+    if (col0(k) == Literal(0) || actual_n==1)
     {
       // if col0(k) == 0, then entry is deflated, so singular value is on diagonal
       // if actual_n==1, then the deflated problem is already diagonalized
       singVals(k) = k==0 ? col0(0) : diag(k);
-      mus(k) = 0;
+      mus(k) = Literal(0);
       shifts(k) = k==0 ? col0(0) : diag(k);
       continue;
     } 
@@ -731,15 +737,17 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
       right = (diag(actual_n-1) + col0.matrix().norm());
     else
     {
-      // Skip deflated singular values
+      // Skip deflated singular values,
+      // recall that at this stage we assume that z[j]!=0 and all entries for which z[j]==0 have been put aside.
+      // This should be equivalent to using perm[]
       Index l = k+1;
-      while(col0(l)==0) { ++l; eigen_internal_assert(l<actual_n); }
+      while(col0(l)==Literal(0)) { ++l; eigen_internal_assert(l<actual_n); }
       right = diag(l);
     }
 
     // first decide whether it's closer to the left end or the right end
-    RealScalar mid = left + (right-left) / 2;
-    RealScalar fMid = secularEq(mid, col0, diag, perm, diag, 0);
+    RealScalar mid = left + (right-left) / Literal(2);
+    RealScalar fMid = secularEq(mid, col0, diag, perm, diag, Literal(0));
 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
     std::cout << right-left << "\n";
     std::cout << "fMid = " << fMid << " " << secularEq(mid-left, col0, diag, perm, diag-left, left) << " " << secularEq(mid-right, col0, diag, perm, diag-right, right)   << "\n";
@@ -755,7 +763,7 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
               << " "       << secularEq(0.8*(left+right), col0, diag, perm, diag, 0)
               << " "       << secularEq(0.9*(left+right), col0, diag, perm, diag, 0) << "\n";
 #endif
-    RealScalar shift = (k == actual_n-1 || fMid > 0) ? left : right;
+    RealScalar shift = (k == actual_n-1 || fMid > Literal(0)) ? left : right;
     
     // measure everything relative to shift
     Map<ArrayXr> diagShifted(m_workspace.data()+4*n, n);
@@ -785,13 +793,13 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
 
     // rational interpolation: fit a function of the form a / mu + b through the two previous
     // iterates and use its zero to compute the next iterate
-    bool useBisection = fPrev*fCur>0;
-    while (fCur!=0 && abs(muCur - muPrev) > 8 * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits<RealScalar>::epsilon() && !useBisection)
+    bool useBisection = fPrev*fCur>Literal(0);
+    while (fCur!=Literal(0) && abs(muCur - muPrev) > Literal(8) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits<RealScalar>::epsilon() && !useBisection)
     {
       ++m_numIters;
 
       // Find a and b such that the function f(mu) = a / mu + b matches the current and previous samples.
-      RealScalar a = (fCur - fPrev) / (1/muCur - 1/muPrev);
+      RealScalar a = (fCur - fPrev) / (Literal(1)/muCur - Literal(1)/muPrev);
       RealScalar b = fCur - a / muCur;
       // And find mu such that f(mu)==0:
       RealScalar muZero = -a/b;
@@ -803,8 +811,8 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
       fCur = fZero;
       
       
-      if (shift == left  && (muCur < 0 || muCur > right - left)) useBisection = true;
-      if (shift == right && (muCur < -(right - left) || muCur > 0)) useBisection = true;
+      if (shift == left  && (muCur < Literal(0) || muCur > right - left)) useBisection = true;
+      if (shift == right && (muCur < -(right - left) || muCur > Literal(0))) useBisection = true;
       if (abs(fCur)>abs(fPrev)) useBisection = true;
     }
 
@@ -817,15 +825,23 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
       RealScalar leftShifted, rightShifted;
       if (shift == left)
       {
-        leftShifted = (std::numeric_limits<RealScalar>::min)();
+        // to avoid overflow, we must have mu > max(real_min, |z(k)|/sqrt(real_max)),
+        // the factor 2 is to be more conservative
+        leftShifted = numext::maxi<RealScalar>( (std::numeric_limits<RealScalar>::min)(), Literal(2) * abs(col0(k)) / sqrt((std::numeric_limits<RealScalar>::max)()) );
+
+        // check that we did it right:
+        eigen_internal_assert( (numext::isfinite)( (col0(k)/leftShifted)*(col0(k)/(diag(k)+shift+leftShifted)) ) );
         // I don't understand why the case k==0 would be special there:
-        // if (k == 0) rightShifted = right - left; else 
-        rightShifted = (k==actual_n-1) ? right : ((right - left) * RealScalar(0.6)); // theoretically we can take 0.5, but let's be safe
+        // if (k == 0) rightShifted = right - left; else
+        rightShifted = (k==actual_n-1) ? right : ((right - left) * RealScalar(0.51)); // theoretically we can take 0.5, but let's be safe
       }
       else
       {
-        leftShifted = -(right - left) * RealScalar(0.6);
-        rightShifted = -(std::numeric_limits<RealScalar>::min)();
+        leftShifted = -(right - left) * RealScalar(0.51);
+        if(k+1<n)
+          rightShifted = -numext::maxi<RealScalar>( (std::numeric_limits<RealScalar>::min)(), abs(col0(k+1)) / sqrt((std::numeric_limits<RealScalar>::max)()) );
+        else
+          rightShifted = -(std::numeric_limits<RealScalar>::min)();
       }
       
       RealScalar fLeft = secularEq(leftShifted, col0, diag, perm, diagShifted, shift);
@@ -841,13 +857,13 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
         std::cout << k << " : " <<  fLeft << " * " << fRight << " == " << fLeft * fRight << "  ;  " << left << " - " << right << " -> " <<  leftShifted << " " << rightShifted << "   shift=" << shift << "\n";
       }
 #endif
-      eigen_internal_assert(fLeft * fRight < 0);
+      eigen_internal_assert(fLeft * fRight < Literal(0));
       
-      while (rightShifted - leftShifted > 2 * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(abs(leftShifted), abs(rightShifted)))
+      while (rightShifted - leftShifted > Literal(2) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(abs(leftShifted), abs(rightShifted)))
       {
-        RealScalar midShifted = (leftShifted + rightShifted) / 2;
+        RealScalar midShifted = (leftShifted + rightShifted) / Literal(2);
         fMid = secularEq(midShifted, col0, diag, perm, diagShifted, shift);
-        if (fLeft * fMid < 0)
+        if (fLeft * fMid < Literal(0))
         {
           rightShifted = midShifted;
         }
@@ -858,7 +874,7 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
         }
       }
 
-      muCur = (leftShifted + rightShifted) / 2;
+      muCur = (leftShifted + rightShifted) / Literal(2);
     }
       
     singVals[k] = shift + muCur;
@@ -892,8 +908,8 @@ void BDCSVD<MatrixType>::perturbCol0
   // The offset permits to skip deflated entries while computing zhat
   for (Index k = 0; k < n; ++k)
   {
-    if (col0(k) == 0) // deflated
-      zhat(k) = 0;
+    if (col0(k) == Literal(0)) // deflated
+      zhat(k) = Literal(0);
     else
     {
       // see equation (3.6)
@@ -918,7 +934,7 @@ void BDCSVD<MatrixType>::perturbCol0
       std::cout << "zhat(" << k << ") =  sqrt( " << prod << ")  ;  " << (singVals(last) + dk) << " * " << mus(last) + shifts(last) << " - " << dk << "\n";
 #endif
       RealScalar tmp = sqrt(prod);
-      zhat(k) = col0(k) > 0 ? tmp : -tmp;
+      zhat(k) = col0(k) > Literal(0) ? tmp : -tmp;
     }
   }
 }
@@ -934,7 +950,7 @@ void BDCSVD<MatrixType>::computeSingVecs
   
   for (Index k = 0; k < n; ++k)
   {
-    if (zhat(k) == 0)
+    if (zhat(k) == Literal(0))
     {
       U.col(k) = VectorType::Unit(n+1, k);
       if (m_compV) V.col(k) = VectorType::Unit(n, k);
@@ -947,7 +963,7 @@ void BDCSVD<MatrixType>::computeSingVecs
         Index i = perm(l);
         U(i,k) = zhat(i)/(((diag(i) - shifts(k)) - mus(k)) )/( (diag(i) + singVals[k]));
       }
-      U(n,k) = 0;      
+      U(n,k) = Literal(0);
       U.col(k).normalize();
     
       if (m_compV)
@@ -958,7 +974,7 @@ void BDCSVD<MatrixType>::computeSingVecs
           Index i = perm(l);
           V(i,k) = diag(i) * zhat(i) / (((diag(i) - shifts(k)) - mus(k)) )/( (diag(i) + singVals[k]));
         }
-        V(0,k) = -1;
+        V(0,k) = Literal(-1);
         V.col(k).normalize();
       }
     }
@@ -979,15 +995,15 @@ void BDCSVD<MatrixType>::deflation43(Index firstCol, Index shift, Index i, Index
   Index start = firstCol + shift;
   RealScalar c = m_computed(start, start);
   RealScalar s = m_computed(start+i, start);
-  RealScalar r = sqrt(numext::abs2(c) + numext::abs2(s));
-  if (r == 0)
+  RealScalar r = numext::hypot(c,s);
+  if (r == Literal(0))
   {
-    m_computed(start+i, start+i) = 0;
+    m_computed(start+i, start+i) = Literal(0);
     return;
   }
   m_computed(start,start) = r;  
-  m_computed(start+i, start) = 0;
-  m_computed(start+i, start+i) = 0;
+  m_computed(start+i, start) = Literal(0);
+  m_computed(start+i, start+i) = Literal(0);
   
   JacobiRotation<RealScalar> J(c/r,-s/r);
   if (m_compU)  m_naiveU.middleRows(firstCol, size+1).applyOnTheRight(firstCol, firstCol+i, J);
@@ -1020,7 +1036,7 @@ void BDCSVD<MatrixType>::deflation44(Index firstColu , Index firstColm, Index fi
     << m_computed(firstColm + i+1, firstColm+i+1) << " "
     << m_computed(firstColm + i+2, firstColm+i+2) << "\n";
 #endif
-  if (r==0)
+  if (r==Literal(0))
   {
     m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j);
     return;
@@ -1029,7 +1045,7 @@ void BDCSVD<MatrixType>::deflation44(Index firstColu , Index firstColm, Index fi
   s/=r;
   m_computed(firstColm + i, firstColm) = r;  
   m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i);
-  m_computed(firstColm + j, firstColm) = 0;
+  m_computed(firstColm + j, firstColm) = Literal(0);
 
   JacobiRotation<RealScalar> J(c,-s);
   if (m_compU)  m_naiveU.middleRows(firstColu, size+1).applyOnTheRight(firstColu + i, firstColu + j, J);
@@ -1053,7 +1069,7 @@ void BDCSVD<MatrixType>::deflation(Index firstCol, Index lastCol, Index k, Index
   const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
   RealScalar maxDiag = diag.tail((std::max)(Index(1),length-1)).cwiseAbs().maxCoeff();
   RealScalar epsilon_strict = numext::maxi<RealScalar>(considerZero,NumTraits<RealScalar>::epsilon() * maxDiag);
-  RealScalar epsilon_coarse = 8 * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(col0.cwiseAbs().maxCoeff(), maxDiag);
+  RealScalar epsilon_coarse = Literal(8) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(col0.cwiseAbs().maxCoeff(), maxDiag);
   
 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
   assert(m_naiveU.allFinite());
@@ -1081,7 +1097,7 @@ void BDCSVD<MatrixType>::deflation(Index firstCol, Index lastCol, Index k, Index
 #ifdef  EIGEN_BDCSVD_DEBUG_VERBOSE
       std::cout << "deflation 4.2, set z(" << i << ") to zero because " << abs(col0(i)) << " < " << epsilon_strict << "  (diag(" << i << ")=" << diag(i) << ")\n";
 #endif
-      col0(i) = 0;
+      col0(i) = Literal(0);
     }
 
   //condition 4.3
diff --git a/xs/src/eigen/Eigen/src/SVD/JacobiSVD_LAPACKE.h b/xs/src/eigen/Eigen/src/SVD/JacobiSVD_LAPACKE.h
index 50272154f..ff0516f61 100644
--- a/xs/src/eigen/Eigen/src/SVD/JacobiSVD_LAPACKE.h
+++ b/xs/src/eigen/Eigen/src/SVD/JacobiSVD_LAPACKE.h
@@ -61,9 +61,10 @@ JacobiSVD<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic>, ColPiv
     u    = (LAPACKE_TYPE*)m_matrixU.data(); \
   } else { ldu=1; u=&dummy; }\
   MatrixType localV; \
-  ldvt = (m_computeFullV) ? internal::convert_index<lapack_int>(m_cols) : (m_computeThinV) ? internal::convert_index<lapack_int>(m_diagSize) : 1; \
+  lapack_int vt_rows = (m_computeFullV) ? internal::convert_index<lapack_int>(m_cols) : (m_computeThinV) ? internal::convert_index<lapack_int>(m_diagSize) : 1; \
   if (computeV()) { \
-    localV.resize(ldvt, m_cols); \
+    localV.resize(vt_rows, m_cols); \
+    ldvt  = internal::convert_index<lapack_int>(localV.outerStride()); \
     vt   = (LAPACKE_TYPE*)localV.data(); \
   } else { ldvt=1; vt=&dummy; }\
   Matrix<LAPACKE_RTYPE, Dynamic, Dynamic> superb; superb.resize(m_diagSize, 1); \
diff --git a/xs/src/eigen/Eigen/src/SVD/UpperBidiagonalization.h b/xs/src/eigen/Eigen/src/SVD/UpperBidiagonalization.h
index 0b1460894..11ac847e1 100644
--- a/xs/src/eigen/Eigen/src/SVD/UpperBidiagonalization.h
+++ b/xs/src/eigen/Eigen/src/SVD/UpperBidiagonalization.h
@@ -159,6 +159,8 @@ void upperbidiagonalization_blocked_helper(MatrixType& A,
                                                       traits<MatrixType>::Flags & RowMajorBit> > Y)
 {
   typedef typename MatrixType::Scalar Scalar;
+  typedef typename MatrixType::RealScalar RealScalar;
+  typedef typename NumTraits<RealScalar>::Literal Literal;
   enum { StorageOrder = traits<MatrixType>::Flags & RowMajorBit };
   typedef InnerStride<int(StorageOrder) == int(ColMajor) ? 1 : Dynamic> ColInnerStride;
   typedef InnerStride<int(StorageOrder) == int(ColMajor) ? Dynamic : 1> RowInnerStride;
@@ -263,7 +265,7 @@ void upperbidiagonalization_blocked_helper(MatrixType& A,
     SubMatType A10( A.block(bs,0, brows-bs,bs) );
     SubMatType A01( A.block(0,bs, bs,bcols-bs) );
     Scalar tmp = A01(bs-1,0);
-    A01(bs-1,0) = 1;
+    A01(bs-1,0) = Literal(1);
     A11.noalias() -= A10 * Y.topLeftCorner(bcols,bs).bottomRows(bcols-bs).adjoint();
     A11.noalias() -= X.topLeftCorner(brows,bs).bottomRows(brows-bs) * A01;
     A01(bs-1,0) = tmp;
diff --git a/xs/src/eigen/Eigen/src/SparseCore/AmbiVector.h b/xs/src/eigen/Eigen/src/SparseCore/AmbiVector.h
index 8a5cc91f2..e0295f2af 100644
--- a/xs/src/eigen/Eigen/src/SparseCore/AmbiVector.h
+++ b/xs/src/eigen/Eigen/src/SparseCore/AmbiVector.h
@@ -94,7 +94,7 @@ class AmbiVector
       Index allocSize = m_allocatedElements * sizeof(ListEl);
       allocSize = (allocSize + sizeof(Scalar) - 1)/sizeof(Scalar);
       Scalar* newBuffer = new Scalar[allocSize];
-      memcpy(newBuffer,  m_buffer,  copyElements * sizeof(ListEl));
+      std::memcpy(newBuffer,  m_buffer,  copyElements * sizeof(ListEl));
       delete[] m_buffer;
       m_buffer = newBuffer;
     }
diff --git a/xs/src/eigen/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/xs/src/eigen/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h
index 492eb0a29..9db119b67 100644
--- a/xs/src/eigen/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h
+++ b/xs/src/eigen/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h
@@ -17,7 +17,9 @@ namespace internal {
 template<typename Lhs, typename Rhs, typename ResultType>
 static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res, bool sortedInsertion = false)
 {
-  typedef typename remove_all<Lhs>::type::Scalar Scalar;
+  typedef typename remove_all<Lhs>::type::Scalar LhsScalar;
+  typedef typename remove_all<Rhs>::type::Scalar RhsScalar;
+  typedef typename remove_all<ResultType>::type::Scalar ResScalar;
 
   // make sure to call innerSize/outerSize since we fake the storage order.
   Index rows = lhs.innerSize();
@@ -25,7 +27,7 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r
   eigen_assert(lhs.outerSize() == rhs.innerSize());
   
   ei_declare_aligned_stack_constructed_variable(bool,   mask,     rows, 0);
-  ei_declare_aligned_stack_constructed_variable(Scalar, values,   rows, 0);
+  ei_declare_aligned_stack_constructed_variable(ResScalar, values,   rows, 0);
   ei_declare_aligned_stack_constructed_variable(Index,  indices,  rows, 0);
   
   std::memset(mask,0,sizeof(bool)*rows);
@@ -51,12 +53,12 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r
     Index nnz = 0;
     for (typename evaluator<Rhs>::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt)
     {
-      Scalar y = rhsIt.value();
+      RhsScalar y = rhsIt.value();
       Index k = rhsIt.index();
       for (typename evaluator<Lhs>::InnerIterator lhsIt(lhsEval, k); lhsIt; ++lhsIt)
       {
         Index i = lhsIt.index();
-        Scalar x = lhsIt.value();
+        LhsScalar x = lhsIt.value();
         if(!mask[i])
         {
           mask[i] = true;
@@ -166,11 +168,12 @@ struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,RowMajor,C
 {
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
   {
-     typedef SparseMatrix<typename ResultType::Scalar,RowMajor,typename ResultType::StorageIndex> RowMajorMatrix;
-     RowMajorMatrix rhsRow = rhs;
-     RowMajorMatrix resRow(lhs.rows(), rhs.cols());
-     internal::conservative_sparse_sparse_product_impl<RowMajorMatrix,Lhs,RowMajorMatrix>(rhsRow, lhs, resRow);
-     res = resRow;
+    typedef SparseMatrix<typename Rhs::Scalar,RowMajor,typename ResultType::StorageIndex> RowMajorRhs;
+    typedef SparseMatrix<typename ResultType::Scalar,RowMajor,typename ResultType::StorageIndex> RowMajorRes;
+    RowMajorRhs rhsRow = rhs;
+    RowMajorRes resRow(lhs.rows(), rhs.cols());
+    internal::conservative_sparse_sparse_product_impl<RowMajorRhs,Lhs,RowMajorRes>(rhsRow, lhs, resRow);
+    res = resRow;
   }
 };
 
@@ -179,10 +182,11 @@ struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,ColMajor,R
 {
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,RowMajor,typename ResultType::StorageIndex> RowMajorMatrix;
-    RowMajorMatrix lhsRow = lhs;
-    RowMajorMatrix resRow(lhs.rows(), rhs.cols());
-    internal::conservative_sparse_sparse_product_impl<Rhs,RowMajorMatrix,RowMajorMatrix>(rhs, lhsRow, resRow);
+    typedef SparseMatrix<typename Lhs::Scalar,RowMajor,typename ResultType::StorageIndex> RowMajorLhs;
+    typedef SparseMatrix<typename ResultType::Scalar,RowMajor,typename ResultType::StorageIndex> RowMajorRes;
+    RowMajorLhs lhsRow = lhs;
+    RowMajorRes resRow(lhs.rows(), rhs.cols());
+    internal::conservative_sparse_sparse_product_impl<Rhs,RowMajorLhs,RowMajorRes>(rhs, lhsRow, resRow);
     res = resRow;
   }
 };
@@ -219,10 +223,11 @@ struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,RowMajor,C
 {
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorMatrix;
-    ColMajorMatrix lhsCol = lhs;
-    ColMajorMatrix resCol(lhs.rows(), rhs.cols());
-    internal::conservative_sparse_sparse_product_impl<ColMajorMatrix,Rhs,ColMajorMatrix>(lhsCol, rhs, resCol);
+    typedef SparseMatrix<typename Lhs::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorLhs;
+    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorRes;
+    ColMajorLhs lhsCol = lhs;
+    ColMajorRes resCol(lhs.rows(), rhs.cols());
+    internal::conservative_sparse_sparse_product_impl<ColMajorLhs,Rhs,ColMajorRes>(lhsCol, rhs, resCol);
     res = resCol;
   }
 };
@@ -232,10 +237,11 @@ struct conservative_sparse_sparse_product_selector<Lhs,Rhs,ResultType,ColMajor,R
 {
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorMatrix;
-    ColMajorMatrix rhsCol = rhs;
-    ColMajorMatrix resCol(lhs.rows(), rhs.cols());
-    internal::conservative_sparse_sparse_product_impl<Lhs,ColMajorMatrix,ColMajorMatrix>(lhs, rhsCol, resCol);
+    typedef SparseMatrix<typename Rhs::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorRhs;
+    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorRes;
+    ColMajorRhs rhsCol = rhs;
+    ColMajorRes resCol(lhs.rows(), rhs.cols());
+    internal::conservative_sparse_sparse_product_impl<Lhs,ColMajorRhs,ColMajorRes>(lhs, rhsCol, resCol);
     res = resCol;
   }
 };
@@ -263,7 +269,8 @@ namespace internal {
 template<typename Lhs, typename Rhs, typename ResultType>
 static void sparse_sparse_to_dense_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res)
 {
-  typedef typename remove_all<Lhs>::type::Scalar Scalar;
+  typedef typename remove_all<Lhs>::type::Scalar LhsScalar;
+  typedef typename remove_all<Rhs>::type::Scalar RhsScalar;
   Index cols = rhs.outerSize();
   eigen_assert(lhs.outerSize() == rhs.innerSize());
 
@@ -274,12 +281,12 @@ static void sparse_sparse_to_dense_product_impl(const Lhs& lhs, const Rhs& rhs,
   {
     for (typename evaluator<Rhs>::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt)
     {
-      Scalar y = rhsIt.value();
+      RhsScalar y = rhsIt.value();
       Index k = rhsIt.index();
       for (typename evaluator<Lhs>::InnerIterator lhsIt(lhsEval, k); lhsIt; ++lhsIt)
       {
         Index i = lhsIt.index();
-        Scalar x = lhsIt.value();
+        LhsScalar x = lhsIt.value();
         res.coeffRef(i,j) += x * y;
       }
     }
@@ -310,9 +317,9 @@ struct sparse_sparse_to_dense_product_selector<Lhs,Rhs,ResultType,RowMajor,ColMa
 {
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorMatrix;
-    ColMajorMatrix lhsCol(lhs);
-    internal::sparse_sparse_to_dense_product_impl<ColMajorMatrix,Rhs,ResultType>(lhsCol, rhs, res);
+    typedef SparseMatrix<typename Lhs::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorLhs;
+    ColMajorLhs lhsCol(lhs);
+    internal::sparse_sparse_to_dense_product_impl<ColMajorLhs,Rhs,ResultType>(lhsCol, rhs, res);
   }
 };
 
@@ -321,9 +328,9 @@ struct sparse_sparse_to_dense_product_selector<Lhs,Rhs,ResultType,ColMajor,RowMa
 {
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorMatrix;
-    ColMajorMatrix rhsCol(rhs);
-    internal::sparse_sparse_to_dense_product_impl<Lhs,ColMajorMatrix,ResultType>(lhs, rhsCol, res);
+    typedef SparseMatrix<typename Rhs::Scalar,ColMajor,typename ResultType::StorageIndex> ColMajorRhs;
+    ColMajorRhs rhsCol(rhs);
+    internal::sparse_sparse_to_dense_product_impl<Lhs,ColMajorRhs,ResultType>(lhs, rhsCol, res);
   }
 };
 
diff --git a/xs/src/eigen/Eigen/src/SparseCore/SparseSelfAdjointView.h b/xs/src/eigen/Eigen/src/SparseCore/SparseSelfAdjointView.h
index 9e39be738..65611b3d4 100644
--- a/xs/src/eigen/Eigen/src/SparseCore/SparseSelfAdjointView.h
+++ b/xs/src/eigen/Eigen/src/SparseCore/SparseSelfAdjointView.h
@@ -47,6 +47,7 @@ template<typename MatrixType, unsigned int _Mode> class SparseSelfAdjointView
     
     enum {
       Mode = _Mode,
+      TransposeMode = ((Mode & Upper) ? Lower : 0) | ((Mode & Lower) ? Upper : 0),
       RowsAtCompileTime = internal::traits<SparseSelfAdjointView>::RowsAtCompileTime,
       ColsAtCompileTime = internal::traits<SparseSelfAdjointView>::ColsAtCompileTime
     };
@@ -310,7 +311,7 @@ inline void sparse_selfadjoint_time_dense_product(const SparseLhsType& lhs, cons
         while (i && i.index()<j) ++i;
         if(i && i.index()==j)
         {
-          res(j,k) += alpha * i.value() * rhs(j,k);
+          res.coeffRef(j,k) += alpha * i.value() * rhs.coeff(j,k);
           ++i;
         }
       }
@@ -323,14 +324,14 @@ inline void sparse_selfadjoint_time_dense_product(const SparseLhsType& lhs, cons
       {
         LhsScalar lhs_ij = i.value();
         if(!LhsIsRowMajor) lhs_ij = numext::conj(lhs_ij);
-        res_j += lhs_ij * rhs(i.index(),k);
+        res_j += lhs_ij * rhs.coeff(i.index(),k);
         res(i.index(),k) += numext::conj(lhs_ij) * rhs_j;
       }
-      res(j,k) += alpha * res_j;
+      res.coeffRef(j,k) += alpha * res_j;
 
       // handle diagonal coeff
       if (ProcessFirstHalf && i && (i.index()==j))
-        res(j,k) += alpha * i.value() * rhs(j,k);
+        res.coeffRef(j,k) += alpha * i.value() * rhs.coeff(j,k);
     }
   }
 }
@@ -368,7 +369,7 @@ struct generic_product_impl<Lhs, RhsView, DenseShape, SparseSelfAdjointShape, Pr
     
     // transpose everything
     Transpose<Dest> dstT(dst);
-    internal::sparse_selfadjoint_time_dense_product<RhsView::Mode>(rhsNested.transpose(), lhsNested.transpose(), dstT, alpha);
+    internal::sparse_selfadjoint_time_dense_product<RhsView::TransposeMode>(rhsNested.transpose(), lhsNested.transpose(), dstT, alpha);
   }
 };
 
diff --git a/xs/src/eigen/Eigen/src/SparseCore/SparseSparseProductWithPruning.h b/xs/src/eigen/Eigen/src/SparseCore/SparseSparseProductWithPruning.h
index 21c419002..88820a48f 100644
--- a/xs/src/eigen/Eigen/src/SparseCore/SparseSparseProductWithPruning.h
+++ b/xs/src/eigen/Eigen/src/SparseCore/SparseSparseProductWithPruning.h
@@ -21,7 +21,8 @@ static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& r
 {
   // return sparse_sparse_product_with_pruning_impl2(lhs,rhs,res);
 
-  typedef typename remove_all<Lhs>::type::Scalar Scalar;
+  typedef typename remove_all<Rhs>::type::Scalar RhsScalar;
+  typedef typename remove_all<ResultType>::type::Scalar ResScalar;
   typedef typename remove_all<Lhs>::type::StorageIndex StorageIndex;
 
   // make sure to call innerSize/outerSize since we fake the storage order.
@@ -31,7 +32,7 @@ static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& r
   eigen_assert(lhs.outerSize() == rhs.innerSize());
 
   // allocate a temporary buffer
-  AmbiVector<Scalar,StorageIndex> tempVector(rows);
+  AmbiVector<ResScalar,StorageIndex> tempVector(rows);
 
   // mimics a resizeByInnerOuter:
   if(ResultType::IsRowMajor)
@@ -63,14 +64,14 @@ static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& r
     {
       // FIXME should be written like this: tmp += rhsIt.value() * lhs.col(rhsIt.index())
       tempVector.restart();
-      Scalar x = rhsIt.value();
+      RhsScalar x = rhsIt.value();
       for (typename evaluator<Lhs>::InnerIterator lhsIt(lhsEval, rhsIt.index()); lhsIt; ++lhsIt)
       {
         tempVector.coeffRef(lhsIt.index()) += lhsIt.value() * x;
       }
     }
     res.startVec(j);
-    for (typename AmbiVector<Scalar,StorageIndex>::Iterator it(tempVector,tolerance); it; ++it)
+    for (typename AmbiVector<ResScalar,StorageIndex>::Iterator it(tempVector,tolerance); it; ++it)
       res.insertBackByOuterInner(j,it.index()) = it.value();
   }
   res.finalize();
@@ -85,7 +86,6 @@ struct sparse_sparse_product_with_pruning_selector;
 template<typename Lhs, typename Rhs, typename ResultType>
 struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,ColMajor,ColMajor,ColMajor>
 {
-  typedef typename traits<typename remove_all<Lhs>::type>::Scalar Scalar;
   typedef typename ResultType::RealScalar RealScalar;
 
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance)
@@ -129,8 +129,8 @@ struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,RowMajor,R
   typedef typename ResultType::RealScalar RealScalar;
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename Lhs::StorageIndex> ColMajorMatrixLhs;
-    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename Lhs::StorageIndex> ColMajorMatrixRhs;
+    typedef SparseMatrix<typename Lhs::Scalar,ColMajor,typename Lhs::StorageIndex> ColMajorMatrixLhs;
+    typedef SparseMatrix<typename Rhs::Scalar,ColMajor,typename Lhs::StorageIndex> ColMajorMatrixRhs;
     ColMajorMatrixLhs colLhs(lhs);
     ColMajorMatrixRhs colRhs(rhs);
     internal::sparse_sparse_product_with_pruning_impl<ColMajorMatrixLhs,ColMajorMatrixRhs,ResultType>(colLhs, colRhs, res, tolerance);
@@ -149,7 +149,7 @@ struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,ColMajor,R
   typedef typename ResultType::RealScalar RealScalar;
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,RowMajor,typename Lhs::StorageIndex> RowMajorMatrixLhs;
+    typedef SparseMatrix<typename Lhs::Scalar,RowMajor,typename Lhs::StorageIndex> RowMajorMatrixLhs;
     RowMajorMatrixLhs rowLhs(lhs);
     sparse_sparse_product_with_pruning_selector<RowMajorMatrixLhs,Rhs,ResultType,RowMajor,RowMajor>(rowLhs,rhs,res,tolerance);
   }
@@ -161,7 +161,7 @@ struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,RowMajor,C
   typedef typename ResultType::RealScalar RealScalar;
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,RowMajor,typename Lhs::StorageIndex> RowMajorMatrixRhs;
+    typedef SparseMatrix<typename Rhs::Scalar,RowMajor,typename Lhs::StorageIndex> RowMajorMatrixRhs;
     RowMajorMatrixRhs rowRhs(rhs);
     sparse_sparse_product_with_pruning_selector<Lhs,RowMajorMatrixRhs,ResultType,RowMajor,RowMajor,RowMajor>(lhs,rowRhs,res,tolerance);
   }
@@ -173,7 +173,7 @@ struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,ColMajor,R
   typedef typename ResultType::RealScalar RealScalar;
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename Lhs::StorageIndex> ColMajorMatrixRhs;
+    typedef SparseMatrix<typename Rhs::Scalar,ColMajor,typename Lhs::StorageIndex> ColMajorMatrixRhs;
     ColMajorMatrixRhs colRhs(rhs);
     internal::sparse_sparse_product_with_pruning_impl<Lhs,ColMajorMatrixRhs,ResultType>(lhs, colRhs, res, tolerance);
   }
@@ -185,7 +185,7 @@ struct sparse_sparse_product_with_pruning_selector<Lhs,Rhs,ResultType,RowMajor,C
   typedef typename ResultType::RealScalar RealScalar;
   static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance)
   {
-    typedef SparseMatrix<typename ResultType::Scalar,ColMajor,typename Lhs::StorageIndex> ColMajorMatrixLhs;
+    typedef SparseMatrix<typename Lhs::Scalar,ColMajor,typename Lhs::StorageIndex> ColMajorMatrixLhs;
     ColMajorMatrixLhs colLhs(lhs);
     internal::sparse_sparse_product_with_pruning_impl<ColMajorMatrixLhs,Rhs,ResultType>(colLhs, rhs, res, tolerance);
   }
diff --git a/xs/src/eigen/Eigen/src/SparseQR/SparseQR.h b/xs/src/eigen/Eigen/src/SparseQR/SparseQR.h
index 2d4498b03..7409fcae9 100644
--- a/xs/src/eigen/Eigen/src/SparseQR/SparseQR.h
+++ b/xs/src/eigen/Eigen/src/SparseQR/SparseQR.h
@@ -52,7 +52,7 @@ namespace internal {
   * rank-revealing permutations. Use colsPermutation() to get it.
   * 
   * Q is the orthogonal matrix represented as products of Householder reflectors. 
-  * Use matrixQ() to get an expression and matrixQ().transpose() to get the transpose.
+  * Use matrixQ() to get an expression and matrixQ().adjoint() to get the adjoint.
   * You can then apply it to a vector.
   * 
   * R is the sparse triangular or trapezoidal matrix. The later occurs when A is rank-deficient.
@@ -65,6 +65,7 @@ namespace internal {
   * \implsparsesolverconcept
   *
   * \warning The input sparse matrix A must be in compressed mode (see SparseMatrix::makeCompressed()).
+  * \warning For complex matrices matrixQ().transpose() will actually return the adjoint matrix.
   * 
   */
 template<typename _MatrixType, typename _OrderingType>
@@ -196,9 +197,9 @@ class SparseQR : public SparseSolverBase<SparseQR<_MatrixType,_OrderingType> >
 
       Index rank = this->rank();
       
-      // Compute Q^T * b;
+      // Compute Q^* * b;
       typename Dest::PlainObject y, b;
-      y = this->matrixQ().transpose() * B; 
+      y = this->matrixQ().adjoint() * B;
       b = y;
       
       // Solve with the triangular matrix R
@@ -604,7 +605,7 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived
   // Get the references 
   SparseQR_QProduct(const SparseQRType& qr, const Derived& other, bool transpose) : 
   m_qr(qr),m_other(other),m_transpose(transpose) {}
-  inline Index rows() const { return m_transpose ? m_qr.rows() : m_qr.cols(); }
+  inline Index rows() const { return m_qr.matrixQ().rows(); }
   inline Index cols() const { return m_other.cols(); }
   
   // Assign to a vector
@@ -632,7 +633,10 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived
     }
     else
     {
-      eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
+      eigen_assert(m_qr.matrixQ().cols() == m_other.rows() && "Non conforming object sizes");
+
+      res.conservativeResize(rows(), cols());
+
       // Compute res = Q * other column by column
       for(Index j = 0; j < res.cols(); j++)
       {
@@ -641,7 +645,7 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived
           Scalar tau = Scalar(0);
           tau = m_qr.m_Q.col(k).dot(res.col(j));
           if(tau==Scalar(0)) continue;
-          tau = tau * m_qr.m_hcoeffs(k);
+          tau = tau * numext::conj(m_qr.m_hcoeffs(k));
           res.col(j) -= tau * m_qr.m_Q.col(k);
         }
       }
@@ -650,7 +654,7 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived
   
   const SparseQRType& m_qr;
   const Derived& m_other;
-  bool m_transpose;
+  bool m_transpose; // TODO this actually means adjoint
 };
 
 template<typename SparseQRType>
@@ -668,13 +672,14 @@ struct SparseQRMatrixQReturnType : public EigenBase<SparseQRMatrixQReturnType<Sp
   {
     return SparseQR_QProduct<SparseQRType,Derived>(m_qr,other.derived(),false);
   }
+  // To use for operations with the adjoint of Q
   SparseQRMatrixQTransposeReturnType<SparseQRType> adjoint() const
   {
     return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
   }
   inline Index rows() const { return m_qr.rows(); }
-  inline Index cols() const { return (std::min)(m_qr.rows(),m_qr.cols()); }
-  // To use for operations with the transpose of Q
+  inline Index cols() const { return m_qr.rows(); }
+  // To use for operations with the transpose of Q FIXME this is the same as adjoint at the moment
   SparseQRMatrixQTransposeReturnType<SparseQRType> transpose() const
   {
     return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
@@ -682,6 +687,7 @@ struct SparseQRMatrixQReturnType : public EigenBase<SparseQRMatrixQReturnType<Sp
   const SparseQRType& m_qr;
 };
 
+// TODO this actually represents the adjoint of Q
 template<typename SparseQRType>
 struct SparseQRMatrixQTransposeReturnType
 {
@@ -712,7 +718,7 @@ struct Assignment<DstXprType, SparseQRMatrixQReturnType<SparseQRType>, internal:
   typedef typename DstXprType::StorageIndex StorageIndex;
   static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar,Scalar> &/*func*/)
   {
-    typename DstXprType::PlainObject idMat(src.m_qr.rows(), src.m_qr.rows());
+    typename DstXprType::PlainObject idMat(src.rows(), src.cols());
     idMat.setIdentity();
     // Sort the sparse householder reflectors if needed
     const_cast<SparseQRType *>(&src.m_qr)->_sort_matrix_Q();
diff --git a/xs/src/eigen/Eigen/src/UmfPackSupport/UmfPackSupport.h b/xs/src/eigen/Eigen/src/UmfPackSupport/UmfPackSupport.h
index dc74de935..91c09ab13 100644
--- a/xs/src/eigen/Eigen/src/UmfPackSupport/UmfPackSupport.h
+++ b/xs/src/eigen/Eigen/src/UmfPackSupport/UmfPackSupport.h
@@ -10,19 +10,37 @@
 #ifndef EIGEN_UMFPACKSUPPORT_H
 #define EIGEN_UMFPACKSUPPORT_H
 
-namespace Eigen { 
+namespace Eigen {
 
 /* TODO extract L, extract U, compute det, etc... */
 
 // generic double/complex<double> wrapper functions:
 
 
-inline void umfpack_defaults(double control[UMFPACK_CONTROL], double) 
+inline void umfpack_defaults(double control[UMFPACK_CONTROL], double)
 { umfpack_di_defaults(control); }
 
-inline void umfpack_defaults(double control[UMFPACK_CONTROL], std::complex<double>) 
+inline void umfpack_defaults(double control[UMFPACK_CONTROL], std::complex<double>)
 { umfpack_zi_defaults(control); }
 
+inline void umfpack_report_info(double control[UMFPACK_CONTROL], double info[UMFPACK_INFO], double)
+{ umfpack_di_report_info(control, info);}
+
+inline void umfpack_report_info(double control[UMFPACK_CONTROL], double info[UMFPACK_INFO], std::complex<double>)
+{ umfpack_zi_report_info(control, info);}
+
+inline void umfpack_report_status(double control[UMFPACK_CONTROL], int status, double)
+{ umfpack_di_report_status(control, status);}
+
+inline void umfpack_report_status(double control[UMFPACK_CONTROL], int status, std::complex<double>)
+{ umfpack_zi_report_status(control, status);}
+
+inline void umfpack_report_control(double control[UMFPACK_CONTROL], double)
+{ umfpack_di_report_control(control);}
+
+inline void umfpack_report_control(double control[UMFPACK_CONTROL], std::complex<double>)
+{ umfpack_zi_report_control(control);}
+
 inline void umfpack_free_numeric(void **Numeric, double)
 { umfpack_di_free_numeric(Numeric); *Numeric = 0; }
 
@@ -156,6 +174,7 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
   public:
 
     typedef Array<double, UMFPACK_CONTROL, 1> UmfpackControl;
+    typedef Array<double, UMFPACK_INFO, 1> UmfpackInfo;
 
     UmfPackLU()
       : m_dummy(0,0), mp_matrix(m_dummy)
@@ -215,7 +234,7 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
       return m_q;
     }
 
-    /** Computes the sparse Cholesky decomposition of \a matrix 
+    /** Computes the sparse Cholesky decomposition of \a matrix
      *  Note that the matrix should be column-major, and in compressed format for best performance.
      *  \sa SparseMatrix::makeCompressed().
      */
@@ -240,7 +259,7 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
     {
       if(m_symbolic) umfpack_free_symbolic(&m_symbolic,Scalar());
       if(m_numeric)  umfpack_free_numeric(&m_numeric,Scalar());
-      
+
       grab(matrix.derived());
 
       analyzePattern_impl();
@@ -267,7 +286,7 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
     {
       return m_control;
     }
-    
+
     /** Provides access to the control settings array used by UmfPack.
       *
       * If this array contains NaN's, the default values are used.
@@ -278,7 +297,7 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
     {
       return m_control;
     }
-    
+
     /** Performs a numeric decomposition of \a matrix
       *
       * The given matrix must has the same sparcity than the matrix on which the pattern anylysis has been performed.
@@ -293,10 +312,38 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
         umfpack_free_numeric(&m_numeric,Scalar());
 
       grab(matrix.derived());
-      
+
       factorize_impl();
     }
 
+    /** Prints the current UmfPack control settings.
+      *
+      * \sa umfpackControl()
+      */
+    void umfpackReportControl()
+    {
+      umfpack_report_control(m_control.data(), Scalar());
+    }
+
+    /** Prints statistics collected by UmfPack.
+      *
+      * \sa analyzePattern(), compute()
+      */
+    void umfpackReportInfo()
+    {
+      eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()");
+      umfpack_report_info(m_control.data(), m_umfpackInfo.data(), Scalar());
+    }
+
+    /** Prints the status of the previous factorization operation performed by UmfPack (symbolic or numerical factorization).
+      *
+      * \sa analyzePattern(), compute()
+      */
+    void umfpackReportStatus() {
+      eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()");
+      umfpack_report_status(m_control.data(), m_fact_errorCode, Scalar());
+    }
+
     /** \internal */
     template<typename BDerived,typename XDerived>
     bool _solve_impl(const MatrixBase<BDerived> &b, MatrixBase<XDerived> &x) const;
@@ -314,41 +361,42 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
       m_numeric               = 0;
       m_symbolic              = 0;
       m_extractedDataAreDirty = true;
+
+      umfpack_defaults(m_control.data(), Scalar());
     }
-    
+
     void analyzePattern_impl()
     {
-      umfpack_defaults(m_control.data(), Scalar());
-      int errorCode = 0;
-      errorCode = umfpack_symbolic(internal::convert_index<int>(mp_matrix.rows()),
-                                   internal::convert_index<int>(mp_matrix.cols()),
-                                   mp_matrix.outerIndexPtr(), mp_matrix.innerIndexPtr(), mp_matrix.valuePtr(),
-                                   &m_symbolic, m_control.data(), 0);
+      m_fact_errorCode = umfpack_symbolic(internal::convert_index<int>(mp_matrix.rows()),
+                                          internal::convert_index<int>(mp_matrix.cols()),
+                                          mp_matrix.outerIndexPtr(), mp_matrix.innerIndexPtr(), mp_matrix.valuePtr(),
+                                          &m_symbolic, m_control.data(), m_umfpackInfo.data());
 
       m_isInitialized = true;
-      m_info = errorCode ? InvalidInput : Success;
+      m_info = m_fact_errorCode ? InvalidInput : Success;
       m_analysisIsOk = true;
       m_factorizationIsOk = false;
       m_extractedDataAreDirty = true;
     }
-    
+
     void factorize_impl()
     {
+
       m_fact_errorCode = umfpack_numeric(mp_matrix.outerIndexPtr(), mp_matrix.innerIndexPtr(), mp_matrix.valuePtr(),
-                                         m_symbolic, &m_numeric, m_control.data(), 0);
+                                         m_symbolic, &m_numeric, m_control.data(), m_umfpackInfo.data());
 
       m_info = m_fact_errorCode == UMFPACK_OK ? Success : NumericalIssue;
       m_factorizationIsOk = true;
       m_extractedDataAreDirty = true;
     }
-    
+
     template<typename MatrixDerived>
     void grab(const EigenBase<MatrixDerived> &A)
     {
       mp_matrix.~UmfpackMatrixRef();
       ::new (&mp_matrix) UmfpackMatrixRef(A.derived());
     }
-    
+
     void grab(const UmfpackMatrixRef &A)
     {
       if(&(A.derived()) != &mp_matrix)
@@ -357,19 +405,20 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
         ::new (&mp_matrix) UmfpackMatrixRef(A);
       }
     }
-  
+
     // cached data to reduce reallocation, etc.
     mutable LUMatrixType m_l;
     int m_fact_errorCode;
     UmfpackControl m_control;
-    
+    mutable UmfpackInfo m_umfpackInfo;
+
     mutable LUMatrixType m_u;
     mutable IntColVectorType m_p;
     mutable IntRowVectorType m_q;
 
     UmfpackMatrixType m_dummy;
     UmfpackMatrixRef mp_matrix;
-  
+
     void* m_numeric;
     void* m_symbolic;
 
@@ -377,7 +426,7 @@ class UmfPackLU : public SparseSolverBase<UmfPackLU<_MatrixType> >
     int m_factorizationIsOk;
     int m_analysisIsOk;
     mutable bool m_extractedDataAreDirty;
-    
+
   private:
     UmfPackLU(const UmfPackLU& ) { }
 };
@@ -427,7 +476,7 @@ bool UmfPackLU<MatrixType>::_solve_impl(const MatrixBase<BDerived> &b, MatrixBas
   eigen_assert((BDerived::Flags&RowMajorBit)==0 && "UmfPackLU backend does not support non col-major rhs yet");
   eigen_assert((XDerived::Flags&RowMajorBit)==0 && "UmfPackLU backend does not support non col-major result yet");
   eigen_assert(b.derived().data() != x.derived().data() && " Umfpack does not support inplace solve");
-  
+
   int errorCode;
   Scalar* x_ptr = 0;
   Matrix<Scalar,Dynamic,1> x_tmp;
@@ -442,7 +491,7 @@ bool UmfPackLU<MatrixType>::_solve_impl(const MatrixBase<BDerived> &b, MatrixBas
       x_ptr = &x.col(j).coeffRef(0);
     errorCode = umfpack_solve(UMFPACK_A,
         mp_matrix.outerIndexPtr(), mp_matrix.innerIndexPtr(), mp_matrix.valuePtr(),
-        x_ptr, &b.const_cast_derived().col(j).coeffRef(0), m_numeric, m_control.data(), 0);
+        x_ptr, &b.const_cast_derived().col(j).coeffRef(0), m_numeric, m_control.data(), m_umfpackInfo.data());
     if(x.innerStride()!=1)
       x.col(j) = x_tmp;
     if (errorCode!=0)
diff --git a/xs/src/eigen/README.md b/xs/src/eigen/README.md
index f56262cca..39892c00b 100644
--- a/xs/src/eigen/README.md
+++ b/xs/src/eigen/README.md
@@ -1,5 +1,5 @@
 THIS IS NOT THE COMPLETE EIGEN DISTRIBUTION. ONLY FILES NEEDED FOR COMPILING EIGEN INTO SLIC3R WERE PUT INTO THE SLIC3R SOURCE DISTRIBUTION.
-THIS DIRECTORY CONTAINS PIECES OF THE EIGEN 3.3.3 SOURCE DISTRIBUTION.
+THIS DIRECTORY CONTAINS PIECES OF THE EIGEN 3.3.5 b3f3d4950030 SOURCE DISTRIBUTION.
 
 
 **Eigen is a C++ template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms.**
diff --git a/xs/src/libnest2d/libnest2d/geometry_traits.hpp b/xs/src/libnest2d/libnest2d/geometry_traits.hpp
index 058c47cd4..8427c0552 100644
--- a/xs/src/libnest2d/libnest2d/geometry_traits.hpp
+++ b/xs/src/libnest2d/libnest2d/geometry_traits.hpp
@@ -163,25 +163,25 @@ struct PointLike {
     template<class RawPoint>
     static TCoord<RawPoint> x(const RawPoint& p)
     {
-        return p.x();
+        return p(0);
     }
 
     template<class RawPoint>
     static TCoord<RawPoint> y(const RawPoint& p)
     {
-        return p.y();
+        return p(1);
     }
 
     template<class RawPoint>
     static TCoord<RawPoint>& x(RawPoint& p)
     {
-        return p.x();
+        return p(0);
     }
 
     template<class RawPoint>
     static TCoord<RawPoint>& y(RawPoint& p)
     {
-        return p.y();
+        return p(1);
     }
 
     template<class RawPoint>
diff --git a/xs/src/libslic3r/BoundingBox.cpp b/xs/src/libslic3r/BoundingBox.cpp
index 4355cd61b..d3cca7ff2 100644
--- a/xs/src/libslic3r/BoundingBox.cpp
+++ b/xs/src/libslic3r/BoundingBox.cpp
@@ -7,9 +7,9 @@
 namespace Slic3r {
 
 template BoundingBoxBase<Point>::BoundingBoxBase(const std::vector<Point> &points);
-template BoundingBoxBase<Pointf>::BoundingBoxBase(const std::vector<Pointf> &points);
+template BoundingBoxBase<Vec2d>::BoundingBoxBase(const std::vector<Vec2d> &points);
 
-template BoundingBox3Base<Pointf3>::BoundingBox3Base(const std::vector<Pointf3> &points);
+template BoundingBox3Base<Vec3d>::BoundingBox3Base(const std::vector<Vec3d> &points);
 
 BoundingBox::BoundingBox(const Lines &lines)
 {
@@ -22,23 +22,21 @@ BoundingBox::BoundingBox(const Lines &lines)
     *this = BoundingBox(points);
 }
 
-void
-BoundingBox::polygon(Polygon* polygon) const
+void BoundingBox::polygon(Polygon* polygon) const
 {
     polygon->points.clear();
     polygon->points.resize(4);
-    polygon->points[0].x = this->min.x;
-    polygon->points[0].y = this->min.y;
-    polygon->points[1].x = this->max.x;
-    polygon->points[1].y = this->min.y;
-    polygon->points[2].x = this->max.x;
-    polygon->points[2].y = this->max.y;
-    polygon->points[3].x = this->min.x;
-    polygon->points[3].y = this->max.y;
+    polygon->points[0](0) = this->min(0);
+    polygon->points[0](1) = this->min(1);
+    polygon->points[1](0) = this->max(0);
+    polygon->points[1](1) = this->min(1);
+    polygon->points[2](0) = this->max(0);
+    polygon->points[2](1) = this->max(1);
+    polygon->points[3](0) = this->min(0);
+    polygon->points[3](1) = this->max(1);
 }
 
-Polygon
-BoundingBox::polygon() const
+Polygon BoundingBox::polygon() const
 {
     Polygon p;
     this->polygon(&p);
@@ -50,8 +48,8 @@ BoundingBox BoundingBox::rotated(double angle) const
     BoundingBox out;
     out.merge(this->min.rotated(angle));
     out.merge(this->max.rotated(angle));
-    out.merge(Point(this->min.x, this->max.y).rotated(angle));
-    out.merge(Point(this->max.x, this->min.y).rotated(angle));
+    out.merge(Point(this->min(0), this->max(1)).rotated(angle));
+    out.merge(Point(this->max(0), this->min(1)).rotated(angle));
     return out;
 }
 
@@ -60,36 +58,35 @@ BoundingBox BoundingBox::rotated(double angle, const Point &center) const
     BoundingBox out;
     out.merge(this->min.rotated(angle, center));
     out.merge(this->max.rotated(angle, center));
-    out.merge(Point(this->min.x, this->max.y).rotated(angle, center));
-    out.merge(Point(this->max.x, this->min.y).rotated(angle, center));
+    out.merge(Point(this->min(0), this->max(1)).rotated(angle, center));
+    out.merge(Point(this->max(0), this->min(1)).rotated(angle, center));
     return out;
 }
 
 template <class PointClass> void
 BoundingBoxBase<PointClass>::scale(double factor)
 {
-    this->min.scale(factor);
-    this->max.scale(factor);
+    this->min *= factor;
+    this->max *= factor;
 }
 template void BoundingBoxBase<Point>::scale(double factor);
-template void BoundingBoxBase<Pointf>::scale(double factor);
-template void BoundingBoxBase<Pointf3>::scale(double factor);
+template void BoundingBoxBase<Vec2d>::scale(double factor);
+template void BoundingBoxBase<Vec3d>::scale(double factor);
 
 template <class PointClass> void
 BoundingBoxBase<PointClass>::merge(const PointClass &point)
 {
     if (this->defined) {
-        this->min.x = std::min(point.x, this->min.x);
-        this->min.y = std::min(point.y, this->min.y);
-        this->max.x = std::max(point.x, this->max.x);
-        this->max.y = std::max(point.y, this->max.y);
+        this->min = this->min.cwiseMin(point);
+        this->max = this->max.cwiseMax(point);
     } else {
-        this->min = this->max = point;
+        this->min = point;
+        this->max = point;
         this->defined = true;
     }
 }
 template void BoundingBoxBase<Point>::merge(const Point &point);
-template void BoundingBoxBase<Pointf>::merge(const Pointf &point);
+template void BoundingBoxBase<Vec2d>::merge(const Vec2d &point);
 
 template <class PointClass> void
 BoundingBoxBase<PointClass>::merge(const std::vector<PointClass> &points)
@@ -97,18 +94,16 @@ BoundingBoxBase<PointClass>::merge(const std::vector<PointClass> &points)
     this->merge(BoundingBoxBase(points));
 }
 template void BoundingBoxBase<Point>::merge(const Points &points);
-template void BoundingBoxBase<Pointf>::merge(const Pointfs &points);
+template void BoundingBoxBase<Vec2d>::merge(const Pointfs &points);
 
 template <class PointClass> void
 BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb)
 {
-    assert(bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y);
+    assert(bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1));
     if (bb.defined) {
         if (this->defined) {
-            this->min.x = std::min(bb.min.x, this->min.x);
-            this->min.y = std::min(bb.min.y, this->min.y);
-            this->max.x = std::max(bb.max.x, this->max.x);
-            this->max.y = std::max(bb.max.y, this->max.y);
+            this->min = this->min.cwiseMin(bb.min);
+            this->max = this->max.cwiseMax(bb.max);
         } else {
             this->min = bb.min;
             this->max = bb.max;
@@ -117,120 +112,121 @@ BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb)
     }
 }
 template void BoundingBoxBase<Point>::merge(const BoundingBoxBase<Point> &bb);
-template void BoundingBoxBase<Pointf>::merge(const BoundingBoxBase<Pointf> &bb);
+template void BoundingBoxBase<Vec2d>::merge(const BoundingBoxBase<Vec2d> &bb);
 
 template <class PointClass> void
 BoundingBox3Base<PointClass>::merge(const PointClass &point)
 {
     if (this->defined) {
-        this->min.z = std::min(point.z, this->min.z);
-        this->max.z = std::max(point.z, this->max.z);
+        this->min = this->min.cwiseMin(point);
+        this->max = this->max.cwiseMax(point);
+    } else {
+        this->min = point;
+        this->max = point;
+        this->defined = true;
     }
-    BoundingBoxBase<PointClass>::merge(point);
 }
-template void BoundingBox3Base<Pointf3>::merge(const Pointf3 &point);
+template void BoundingBox3Base<Vec3d>::merge(const Vec3d &point);
 
 template <class PointClass> void
 BoundingBox3Base<PointClass>::merge(const std::vector<PointClass> &points)
 {
     this->merge(BoundingBox3Base(points));
 }
-template void BoundingBox3Base<Pointf3>::merge(const Pointf3s &points);
+template void BoundingBox3Base<Vec3d>::merge(const Pointf3s &points);
 
 template <class PointClass> void
 BoundingBox3Base<PointClass>::merge(const BoundingBox3Base<PointClass> &bb)
 {
-    assert(bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y || bb.min.z >= bb.max.z);
+    assert(bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1) || bb.min(2) >= bb.max(2));
     if (bb.defined) {
         if (this->defined) {
-            this->min.z = std::min(bb.min.z, this->min.z);
-            this->max.z = std::max(bb.max.z, this->max.z);
+            this->min = this->min.cwiseMin(bb.min);
+            this->max = this->max.cwiseMax(bb.max);
+        } else {
+            this->min = bb.min;
+            this->max = bb.max;
+            this->defined = true;
         }
-        BoundingBoxBase<PointClass>::merge(bb);
     }
 }
-template void BoundingBox3Base<Pointf3>::merge(const BoundingBox3Base<Pointf3> &bb);
+template void BoundingBox3Base<Vec3d>::merge(const BoundingBox3Base<Vec3d> &bb);
 
 template <class PointClass> PointClass
 BoundingBoxBase<PointClass>::size() const
 {
-    return PointClass(this->max.x - this->min.x, this->max.y - this->min.y);
+    return PointClass(this->max(0) - this->min(0), this->max(1) - this->min(1));
 }
 template Point BoundingBoxBase<Point>::size() const;
-template Pointf BoundingBoxBase<Pointf>::size() const;
+template Vec2d BoundingBoxBase<Vec2d>::size() const;
 
 template <class PointClass> PointClass
 BoundingBox3Base<PointClass>::size() const
 {
-    return PointClass(this->max.x - this->min.x, this->max.y - this->min.y, this->max.z - this->min.z);
+    return PointClass(this->max(0) - this->min(0), this->max(1) - this->min(1), this->max(2) - this->min(2));
 }
-template Pointf3 BoundingBox3Base<Pointf3>::size() const;
+template Vec3d BoundingBox3Base<Vec3d>::size() const;
 
 template <class PointClass> double BoundingBoxBase<PointClass>::radius() const
 {
     assert(this->defined);
-    double x = this->max.x - this->min.x;
-    double y = this->max.y - this->min.y;
+    double x = this->max(0) - this->min(0);
+    double y = this->max(1) - this->min(1);
     return 0.5 * sqrt(x*x+y*y);
 }
 template double BoundingBoxBase<Point>::radius() const;
-template double BoundingBoxBase<Pointf>::radius() const;
+template double BoundingBoxBase<Vec2d>::radius() const;
 
 template <class PointClass> double BoundingBox3Base<PointClass>::radius() const
 {
-    double x = this->max.x - this->min.x;
-    double y = this->max.y - this->min.y;
-    double z = this->max.z - this->min.z;
+    double x = this->max(0) - this->min(0);
+    double y = this->max(1) - this->min(1);
+    double z = this->max(2) - this->min(2);
     return 0.5 * sqrt(x*x+y*y+z*z);
 }
-template double BoundingBox3Base<Pointf3>::radius() const;
+template double BoundingBox3Base<Vec3d>::radius() const;
 
 template <class PointClass> void
 BoundingBoxBase<PointClass>::offset(coordf_t delta)
 {
-    this->min.translate(-delta, -delta);
-    this->max.translate(delta, delta);
+    PointClass v(delta, delta);
+    this->min -= v;
+    this->max += v;
 }
 template void BoundingBoxBase<Point>::offset(coordf_t delta);
-template void BoundingBoxBase<Pointf>::offset(coordf_t delta);
+template void BoundingBoxBase<Vec2d>::offset(coordf_t delta);
 
 template <class PointClass> void
 BoundingBox3Base<PointClass>::offset(coordf_t delta)
 {
-    this->min.translate(-delta, -delta, -delta);
-    this->max.translate(delta, delta, delta);
+    PointClass v(delta, delta, delta);
+    this->min -= v;
+    this->max += v;
 }
-template void BoundingBox3Base<Pointf3>::offset(coordf_t delta);
+template void BoundingBox3Base<Vec3d>::offset(coordf_t delta);
 
 template <class PointClass> PointClass
 BoundingBoxBase<PointClass>::center() const
 {
-    return PointClass(
-        (this->max.x + this->min.x)/2,
-        (this->max.y + this->min.y)/2
-    );
+    return (this->min + this->max) / 2;
 }
 template Point BoundingBoxBase<Point>::center() const;
-template Pointf BoundingBoxBase<Pointf>::center() const;
+template Vec2d BoundingBoxBase<Vec2d>::center() const;
 
 template <class PointClass> PointClass
 BoundingBox3Base<PointClass>::center() const
 {
-    return PointClass(
-        (this->max.x + this->min.x)/2,
-        (this->max.y + this->min.y)/2,
-        (this->max.z + this->min.z)/2
-    );
+    return (this->min + this->max) / 2;
 }
-template Pointf3 BoundingBox3Base<Pointf3>::center() const;
+template Vec3d BoundingBox3Base<Vec3d>::center() const;
 
 template <class PointClass> coordf_t
 BoundingBox3Base<PointClass>::max_size() const
 {
     PointClass s = size();
-    return std::max(s.x, std::max(s.y, s.z));
+    return std::max(s(0), std::max(s(1), s(2)));
 }
-template coordf_t BoundingBox3Base<Pointf3>::max_size() const;
+template coordf_t BoundingBox3Base<Vec3d>::max_size() const;
 
 // Align a coordinate to a grid. The coordinate may be negative,
 // the aligned value will never be bigger than the original one.
@@ -248,46 +244,40 @@ static inline coord_t _align_to_grid(const coord_t coord, const coord_t spacing)
 void BoundingBox::align_to_grid(const coord_t cell_size)
 {
     if (this->defined) {
-        min.x = _align_to_grid(min.x, cell_size);
-        min.y = _align_to_grid(min.y, cell_size);
+        min(0) = _align_to_grid(min(0), cell_size);
+        min(1) = _align_to_grid(min(1), cell_size);
     }
 }
 
-BoundingBoxf3 BoundingBoxf3::transformed(const std::vector<float>& matrix) const
+BoundingBoxf3 BoundingBoxf3::transformed(const Transform3d& matrix) const
 {
-    Eigen::Matrix<float, 3, 8> vertices;
+    typedef Eigen::Matrix<double, 3, 8, Eigen::DontAlign> Vertices;
 
-    vertices(0, 0) = (float)min.x; vertices(1, 0) = (float)min.y; vertices(2, 0) = (float)min.z;
-    vertices(0, 1) = (float)max.x; vertices(1, 1) = (float)min.y; vertices(2, 1) = (float)min.z;
-    vertices(0, 2) = (float)max.x; vertices(1, 2) = (float)max.y; vertices(2, 2) = (float)min.z;
-    vertices(0, 3) = (float)min.x; vertices(1, 3) = (float)max.y; vertices(2, 3) = (float)min.z;
-    vertices(0, 4) = (float)min.x; vertices(1, 4) = (float)min.y; vertices(2, 4) = (float)max.z;
-    vertices(0, 5) = (float)max.x; vertices(1, 5) = (float)min.y; vertices(2, 5) = (float)max.z;
-    vertices(0, 6) = (float)max.x; vertices(1, 6) = (float)max.y; vertices(2, 6) = (float)max.z;
-    vertices(0, 7) = (float)min.x; vertices(1, 7) = (float)max.y; vertices(2, 7) = (float)max.z;
+    Vertices src_vertices;
+    src_vertices(0, 0) = min(0); src_vertices(1, 0) = min(1); src_vertices(2, 0) = min(2);
+    src_vertices(0, 1) = max(0); src_vertices(1, 1) = min(1); src_vertices(2, 1) = min(2);
+    src_vertices(0, 2) = max(0); src_vertices(1, 2) = max(1); src_vertices(2, 2) = min(2);
+    src_vertices(0, 3) = min(0); src_vertices(1, 3) = max(1); src_vertices(2, 3) = min(2);
+    src_vertices(0, 4) = min(0); src_vertices(1, 4) = min(1); src_vertices(2, 4) = max(2);
+    src_vertices(0, 5) = max(0); src_vertices(1, 5) = min(1); src_vertices(2, 5) = max(2);
+    src_vertices(0, 6) = max(0); src_vertices(1, 6) = max(1); src_vertices(2, 6) = max(2);
+    src_vertices(0, 7) = min(0); src_vertices(1, 7) = max(1); src_vertices(2, 7) = max(2);
 
-    Eigen::Transform<float, 3, Eigen::Affine> m;
-    ::memcpy((void*)m.data(), (const void*)matrix.data(), 16 * sizeof(float));
-    Eigen::Matrix<float, 3, 8> transf_vertices = m * vertices.colwise().homogeneous();
+    Vertices dst_vertices = matrix * src_vertices.colwise().homogeneous();
 
-    float min_x = transf_vertices(0, 0);
-    float max_x = transf_vertices(0, 0);
-    float min_y = transf_vertices(1, 0);
-    float max_y = transf_vertices(1, 0);
-    float min_z = transf_vertices(2, 0);
-    float max_z = transf_vertices(2, 0);
+    Vec3d v_min(dst_vertices(0, 0), dst_vertices(1, 0), dst_vertices(2, 0));
+    Vec3d v_max = v_min;
 
     for (int i = 1; i < 8; ++i)
     {
-        min_x = std::min(min_x, transf_vertices(0, i));
-        max_x = std::max(max_x, transf_vertices(0, i));
-        min_y = std::min(min_y, transf_vertices(1, i));
-        max_y = std::max(max_y, transf_vertices(1, i));
-        min_z = std::min(min_z, transf_vertices(2, i));
-        max_z = std::max(max_z, transf_vertices(2, i));
+        for (int j = 0; j < 3; ++j)
+        {
+            v_min(j) = std::min(v_min(j), dst_vertices(j, i));
+            v_max(j) = std::max(v_max(j), dst_vertices(j, i));
+        }
     }
 
-    return BoundingBoxf3(Pointf3((coordf_t)min_x, (coordf_t)min_y, (coordf_t)min_z), Pointf3((coordf_t)max_x, (coordf_t)max_y, (coordf_t)max_z));
+    return BoundingBoxf3(v_min, v_max);
 }
 
 }
diff --git a/xs/src/libslic3r/BoundingBox.hpp b/xs/src/libslic3r/BoundingBox.hpp
index 5324dbe3b..db56c765c 100644
--- a/xs/src/libslic3r/BoundingBox.hpp
+++ b/xs/src/libslic3r/BoundingBox.hpp
@@ -7,11 +7,6 @@
 
 namespace Slic3r {
 
-typedef Point   Size;
-typedef Point3  Size3;
-typedef Pointf  Sizef;
-typedef Pointf3 Sizef3;
-
 template <class PointClass>
 class BoundingBoxBase
 {
@@ -20,25 +15,22 @@ public:
     PointClass max;
     bool defined;
     
-    BoundingBoxBase() : defined(false) {};
+    BoundingBoxBase() : defined(false), min(PointClass::Zero()), max(PointClass::Zero()) {}
     BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) : 
-        min(pmin), max(pmax), defined(pmin.x < pmax.x && pmin.y < pmax.y) {}
-    BoundingBoxBase(const std::vector<PointClass>& points)
+        min(pmin), max(pmax), defined(pmin(0) < pmax(0) && pmin(1) < pmax(1)) {}
+    BoundingBoxBase(const std::vector<PointClass>& points) : min(PointClass::Zero()), max(PointClass::Zero())
     {
         if (points.empty())
             CONFESS("Empty point set supplied to BoundingBoxBase constructor");
 
         typename std::vector<PointClass>::const_iterator it = points.begin();
-        this->min.x = this->max.x = it->x;
-        this->min.y = this->max.y = it->y;
-        for (++it; it != points.end(); ++it)
-        {
-            this->min.x = std::min(it->x, this->min.x);
-            this->min.y = std::min(it->y, this->min.y);
-            this->max.x = std::max(it->x, this->max.x);
-            this->max.y = std::max(it->y, this->max.y);
+        this->min = *it;
+        this->max = *it;
+        for (++ it; it != points.end(); ++ it) {
+            this->min = this->min.cwiseMin(*it);
+            this->max = this->max.cwiseMax(*it);
         }
-        this->defined = (this->min.x < this->max.x) && (this->min.y < this->max.y);
+        this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1));
     }
     void merge(const PointClass &point);
     void merge(const std::vector<PointClass> &points);
@@ -46,17 +38,17 @@ public:
     void scale(double factor);
     PointClass size() const;
     double radius() const;
-    void translate(coordf_t x, coordf_t y) { assert(this->defined); this->min.translate(x, y); this->max.translate(x, y); }
-    void translate(const Pointf &pos) { this->translate(pos.x, pos.y); }
+    void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; }
+    void translate(const Vec2d &v) { this->min += v; this->max += v; }
     void offset(coordf_t delta);
     PointClass center() const;
     bool contains(const PointClass &point) const {
-        return point.x >= this->min.x && point.x <= this->max.x
-            && point.y >= this->min.y && point.y <= this->max.y;
+        return point(0) >= this->min(0) && point(0) <= this->max(0)
+            && point(1) >= this->min(1) && point(1) <= this->max(1);
     }
     bool overlap(const BoundingBoxBase<PointClass> &other) const {
-        return ! (this->max.x < other.min.x || this->min.x > other.max.x ||
-                  this->max.y < other.min.y || this->min.y > other.max.y);
+        return ! (this->max(0) < other.min(0) || this->min(0) > other.max(0) ||
+                  this->max(1) < other.min(1) || this->min(1) > other.max(1));
     }
     bool operator==(const BoundingBoxBase<PointClass> &rhs) { return this->min == rhs.min && this->max == rhs.max; }
     bool operator!=(const BoundingBoxBase<PointClass> &rhs) { return ! (*this == rhs); }
@@ -69,35 +61,33 @@ public:
     BoundingBox3Base() : BoundingBoxBase<PointClass>() {};
     BoundingBox3Base(const PointClass &pmin, const PointClass &pmax) : 
         BoundingBoxBase<PointClass>(pmin, pmax) 
-        { if (pmin.z >= pmax.z) BoundingBoxBase<PointClass>::defined = false; }
+        { if (pmin(2) >= pmax(2)) BoundingBoxBase<PointClass>::defined = false; }
     BoundingBox3Base(const std::vector<PointClass>& points)
-        : BoundingBoxBase<PointClass>(points)
     {
         if (points.empty())
             CONFESS("Empty point set supplied to BoundingBox3Base constructor");
-
         typename std::vector<PointClass>::const_iterator it = points.begin();
-        this->min.z = this->max.z = it->z;
-        for (++it; it != points.end(); ++it)
-        {
-            this->min.z = std::min(it->z, this->min.z);
-            this->max.z = std::max(it->z, this->max.z);
+        this->min = *it;
+        this->max = *it;
+        for (++ it; it != points.end(); ++ it) {
+            this->min = this->min.cwiseMin(*it);
+            this->max = this->max.cwiseMax(*it);
         }
-        this->defined &= (this->min.z < this->max.z);
+        this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1)) && (this->min(2) < this->max(2));
     }
     void merge(const PointClass &point);
     void merge(const std::vector<PointClass> &points);
     void merge(const BoundingBox3Base<PointClass> &bb);
     PointClass size() const;
     double radius() const;
-    void translate(coordf_t x, coordf_t y, coordf_t z) { this->min.translate(x, y, z); this->max.translate(x, y, z); }
-    void translate(const Pointf3 &pos) { this->translate(pos.x, pos.y, pos.z); }
+    void translate(coordf_t x, coordf_t y, coordf_t z) { assert(this->defined); PointClass v(x, y, z); this->min += v; this->max += v; }
+    void translate(const Vec3d &v) { this->min += v; this->max += v; }
     void offset(coordf_t delta);
     PointClass center() const;
     coordf_t max_size() const;
 
     bool contains(const PointClass &point) const {
-        return BoundingBoxBase<PointClass>::contains(point) && point.z >= this->min.z && point.z <= this->max.z;
+        return BoundingBoxBase<PointClass>::contains(point) && point(2) >= this->min(2) && point(2) <= this->max(2);
     }
 
     bool contains(const BoundingBox3Base<PointClass>& other) const {
@@ -105,7 +95,7 @@ public:
     }
 
     bool intersects(const BoundingBox3Base<PointClass>& other) const {
-        return (this->min.x < other.max.x) && (this->max.x > other.min.x) && (this->min.y < other.max.y) && (this->max.y > other.min.y) && (this->min.z < other.max.z) && (this->max.z > other.min.z);
+        return (this->min(0) < other.max(0)) && (this->max(0) > other.min(0)) && (this->min(1) < other.max(1)) && (this->max(1) > other.min(1)) && (this->min(2) < other.max(2)) && (this->max(2) > other.min(2));
     }
 };
 
@@ -130,42 +120,42 @@ public:
     friend BoundingBox get_extents_rotated(const Points &points, double angle);
 };
 
-class BoundingBox3  : public BoundingBox3Base<Point3> 
+class BoundingBox3  : public BoundingBox3Base<Vec3crd> 
 {
 public:
-    BoundingBox3() : BoundingBox3Base<Point3>() {};
-    BoundingBox3(const Point3 &pmin, const Point3 &pmax) : BoundingBox3Base<Point3>(pmin, pmax) {};
-    BoundingBox3(const Points3& points) : BoundingBox3Base<Point3>(points) {};
+    BoundingBox3() : BoundingBox3Base<Vec3crd>() {};
+    BoundingBox3(const Vec3crd &pmin, const Vec3crd &pmax) : BoundingBox3Base<Vec3crd>(pmin, pmax) {};
+    BoundingBox3(const Points3& points) : BoundingBox3Base<Vec3crd>(points) {};
 };
 
-class BoundingBoxf : public BoundingBoxBase<Pointf> 
+class BoundingBoxf : public BoundingBoxBase<Vec2d> 
 {
 public:
-    BoundingBoxf() : BoundingBoxBase<Pointf>() {};
-    BoundingBoxf(const Pointf &pmin, const Pointf &pmax) : BoundingBoxBase<Pointf>(pmin, pmax) {};
-    BoundingBoxf(const std::vector<Pointf> &points) : BoundingBoxBase<Pointf>(points) {};
+    BoundingBoxf() : BoundingBoxBase<Vec2d>() {};
+    BoundingBoxf(const Vec2d &pmin, const Vec2d &pmax) : BoundingBoxBase<Vec2d>(pmin, pmax) {};
+    BoundingBoxf(const std::vector<Vec2d> &points) : BoundingBoxBase<Vec2d>(points) {};
 };
 
-class BoundingBoxf3 : public BoundingBox3Base<Pointf3> 
+class BoundingBoxf3 : public BoundingBox3Base<Vec3d> 
 {
 public:
-    BoundingBoxf3() : BoundingBox3Base<Pointf3>() {};
-    BoundingBoxf3(const Pointf3 &pmin, const Pointf3 &pmax) : BoundingBox3Base<Pointf3>(pmin, pmax) {};
-    BoundingBoxf3(const std::vector<Pointf3> &points) : BoundingBox3Base<Pointf3>(points) {};
+    BoundingBoxf3() : BoundingBox3Base<Vec3d>() {};
+    BoundingBoxf3(const Vec3d &pmin, const Vec3d &pmax) : BoundingBox3Base<Vec3d>(pmin, pmax) {};
+    BoundingBoxf3(const std::vector<Vec3d> &points) : BoundingBox3Base<Vec3d>(points) {};
 
-    BoundingBoxf3 transformed(const std::vector<float>& matrix) const;
+    BoundingBoxf3 transformed(const Transform3d& matrix) const;
 };
 
 template<typename VT>
 inline bool empty(const BoundingBoxBase<VT> &bb)
 {
-    return ! bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y;
+    return ! bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1);
 }
 
 template<typename VT>
 inline bool empty(const BoundingBox3Base<VT> &bb)
 {
-    return ! bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y || bb.min.z >= bb.max.z;
+    return ! bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1) || bb.min(2) >= bb.max(2);
 }
 
 } // namespace Slic3r
diff --git a/xs/src/libslic3r/BridgeDetector.cpp b/xs/src/libslic3r/BridgeDetector.cpp
index a5272683f..ccc3505ce 100644
--- a/xs/src/libslic3r/BridgeDetector.cpp
+++ b/xs/src/libslic3r/BridgeDetector.cpp
@@ -102,16 +102,16 @@ bool BridgeDetector::detect_angle(double bridge_direction_override)
             // Get an oriented bounding box around _anchor_regions.
             BoundingBox bbox = get_extents_rotated(this->_anchor_regions, - angle);
             // Cover the region with line segments.
-            lines.reserve((bbox.max.y - bbox.min.y + this->spacing) / this->spacing);
+            lines.reserve((bbox.max(1) - bbox.min(1) + this->spacing) / this->spacing);
             double s = sin(angle);
             double c = cos(angle);
             //FIXME Vojtech: The lines shall be spaced half the line width from the edge, but then 
             // some of the test cases fail. Need to adjust the test cases then?
-//            for (coord_t y = bbox.min.y + this->spacing / 2; y <= bbox.max.y; y += this->spacing)
-            for (coord_t y = bbox.min.y; y <= bbox.max.y; y += this->spacing)
+//            for (coord_t y = bbox.min(1) + this->spacing / 2; y <= bbox.max(1); y += this->spacing)
+            for (coord_t y = bbox.min(1); y <= bbox.max(1); y += this->spacing)
                 lines.push_back(Line(
-                    Point((coord_t)round(c * bbox.min.x - s * y), (coord_t)round(c * y + s * bbox.min.x)),
-                    Point((coord_t)round(c * bbox.max.x - s * y), (coord_t)round(c * y + s * bbox.max.x))));
+                    Point((coord_t)round(c * bbox.min(0) - s * y), (coord_t)round(c * y + s * bbox.min(0))),
+                    Point((coord_t)round(c * bbox.max(0) - s * y), (coord_t)round(c * y + s * bbox.max(0)))));
         }
 
         double total_length = 0;
@@ -182,9 +182,9 @@ std::vector<double> BridgeDetector::bridge_direction_candidates() const
     
     /*  we also test angles of each open supporting edge
         (this finds the optimal angle for C-shaped supports) */
-    for (Polylines::const_iterator edge = this->_edges.begin(); edge != this->_edges.end(); ++edge)
-        if (! edge->first_point().coincides_with(edge->last_point()))
-            angles.push_back(Line(edge->first_point(), edge->last_point()).direction());
+    for (const Polyline &edge : this->_edges)
+        if (edge.first_point() != edge.last_point())
+            angles.push_back(Line(edge.first_point(), edge.last_point()).direction());
     
     // remove duplicates
     double min_resolution = PI/180.0;  // 1 degree
@@ -282,10 +282,12 @@ BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
             extrusions would be anchored within such length (i.e. a slightly non-parallel bridging
             direction might still benefit from anchors if long enough)
             double angle_tolerance = PI / 180.0 * 5.0; */
-        for (Lines::const_iterator line = unsupported_lines.begin(); line != unsupported_lines.end(); ++line) {
-            if (!Slic3r::Geometry::directions_parallel(line->direction(), angle))
-                unsupported->push_back(*line);
-        }
+        for (const Line &line : unsupported_lines)
+            if (! Slic3r::Geometry::directions_parallel(line.direction(), angle)) {
+                unsupported->emplace_back(Polyline());
+                unsupported->back().points.emplace_back(line.a);
+                unsupported->back().points.emplace_back(line.b);
+            }
     }
     
     /*
diff --git a/xs/src/libslic3r/ClipperUtils.cpp b/xs/src/libslic3r/ClipperUtils.cpp
index 31a12aa77..f00e908ce 100644
--- a/xs/src/libslic3r/ClipperUtils.cpp
+++ b/xs/src/libslic3r/ClipperUtils.cpp
@@ -171,7 +171,7 @@ Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input)
 {
     ClipperLib::Path retval;
     for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit)
-        retval.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y ));
+        retval.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) ));
     return retval;
 }
 
@@ -181,7 +181,7 @@ Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input)
     ClipperLib::Path output;
     output.reserve(input.points.size());
     for (Slic3r::Points::const_reverse_iterator pit = input.points.rbegin(); pit != input.points.rend(); ++pit)
-        output.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y ));
+        output.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) ));
     return output;
 }
 
@@ -595,26 +595,26 @@ Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, co
        to recombine continuous polylines. */
     for (size_t i = 0; i < retval.size(); ++i) {
         for (size_t j = i+1; j < retval.size(); ++j) {
-            if (retval[i].points.back().coincides_with(retval[j].points.front())) {
+            if (retval[i].points.back() == retval[j].points.front()) {
                 /* If last point of i coincides with first point of j,
                    append points of j to i and delete j */
                 retval[i].points.insert(retval[i].points.end(), retval[j].points.begin()+1, retval[j].points.end());
                 retval.erase(retval.begin() + j);
                 --j;
-            } else if (retval[i].points.front().coincides_with(retval[j].points.back())) {
+            } else if (retval[i].points.front() == retval[j].points.back()) {
                 /* If first point of i coincides with last point of j,
                    prepend points of j to i and delete j */
                 retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1);
                 retval.erase(retval.begin() + j);
                 --j;
-            } else if (retval[i].points.front().coincides_with(retval[j].points.front())) {
+            } else if (retval[i].points.front() == retval[j].points.front()) {
                 /* Since Clipper does not preserve orientation of polylines, 
                    also check the case when first point of i coincides with first point of j. */
                 retval[j].reverse();
                 retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1);
                 retval.erase(retval.begin() + j);
                 --j;
-            } else if (retval[i].points.back().coincides_with(retval[j].points.back())) {
+            } else if (retval[i].points.back() == retval[j].points.back()) {
                 /* Since Clipper does not preserve orientation of polylines, 
                    also check the case when last point of i coincides with last point of j. */
                 retval[j].reverse();
@@ -634,8 +634,8 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons
     // convert Lines to Polylines
     Polylines polylines;
     polylines.reserve(subject.size());
-    for (Lines::const_iterator line = subject.begin(); line != subject.end(); ++line)
-        polylines.push_back(*line);
+    for (const Line &line : subject)
+        polylines.emplace_back(Polyline(line.a, line.b));
     
     // perform operation
     polylines = _clipper_pl(clipType, polylines, clip, safety_offset_);
diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp
index 377bdbea4..7f75f815d 100644
--- a/xs/src/libslic3r/Config.hpp
+++ b/xs/src/libslic3r/Config.hpp
@@ -622,11 +622,11 @@ public:
     }
 };
 
-class ConfigOptionPoint : public ConfigOptionSingle<Pointf>
+class ConfigOptionPoint : public ConfigOptionSingle<Vec2d>
 {
 public:
-    ConfigOptionPoint() : ConfigOptionSingle<Pointf>(Pointf(0,0)) {}
-    explicit ConfigOptionPoint(const Pointf &value) : ConfigOptionSingle<Pointf>(value) {}
+    ConfigOptionPoint() : ConfigOptionSingle<Vec2d>(Vec2d(0,0)) {}
+    explicit ConfigOptionPoint(const Vec2d &value) : ConfigOptionSingle<Vec2d>(value) {}
     
     static ConfigOptionType static_type() { return coPoint; }
     ConfigOptionType        type()  const override { return static_type(); }
@@ -637,9 +637,9 @@ public:
     std::string serialize() const override
     {
         std::ostringstream ss;
-        ss << this->value.x;
+        ss << this->value(0);
         ss << ",";
-        ss << this->value.y;
+        ss << this->value(1);
         return ss.str();
     }
     
@@ -647,18 +647,18 @@ public:
     {
         UNUSED(append);
         char dummy;
-        return sscanf(str.data(), " %lf , %lf %c", &this->value.x, &this->value.y, &dummy) == 2 ||
-               sscanf(str.data(), " %lf x %lf %c", &this->value.x, &this->value.y, &dummy) == 2;
+        return sscanf(str.data(), " %lf , %lf %c", &this->value(0), &this->value(1), &dummy) == 2 ||
+               sscanf(str.data(), " %lf x %lf %c", &this->value(0), &this->value(1), &dummy) == 2;
     }
 };
 
-class ConfigOptionPoints : public ConfigOptionVector<Pointf>
+class ConfigOptionPoints : public ConfigOptionVector<Vec2d>
 {
 public:
-    ConfigOptionPoints() : ConfigOptionVector<Pointf>() {}
-    explicit ConfigOptionPoints(size_t n, const Pointf &value) : ConfigOptionVector<Pointf>(n, value) {}
-    explicit ConfigOptionPoints(std::initializer_list<Pointf> il) : ConfigOptionVector<Pointf>(std::move(il)) {}
-    explicit ConfigOptionPoints(const std::vector<Pointf> &values) : ConfigOptionVector<Pointf>(values) {}
+    ConfigOptionPoints() : ConfigOptionVector<Vec2d>() {}
+    explicit ConfigOptionPoints(size_t n, const Vec2d &value) : ConfigOptionVector<Vec2d>(n, value) {}
+    explicit ConfigOptionPoints(std::initializer_list<Vec2d> il) : ConfigOptionVector<Vec2d>(std::move(il)) {}
+    explicit ConfigOptionPoints(const std::vector<Vec2d> &values) : ConfigOptionVector<Vec2d>(values) {}
 
     static ConfigOptionType static_type() { return coPoints; }
     ConfigOptionType        type()  const override { return static_type(); }
@@ -671,9 +671,9 @@ public:
         std::ostringstream ss;
         for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
             if (it - this->values.begin() != 0) ss << ",";
-            ss << it->x;
+            ss << (*it)(0);
             ss << "x";
-            ss << it->y;
+            ss << (*it)(1);
         }
         return ss.str();
     }
@@ -696,13 +696,13 @@ public:
         std::istringstream is(str);
         std::string point_str;
         while (std::getline(is, point_str, ',')) {
-            Pointf point;
+            Vec2d point(Vec2d::Zero());
             std::istringstream iss(point_str);
             std::string coord_str;
             if (std::getline(iss, coord_str, 'x')) {
-                std::istringstream(coord_str) >> point.x;
+                std::istringstream(coord_str) >> point(0);
                 if (std::getline(iss, coord_str, 'x')) {
-                    std::istringstream(coord_str) >> point.y;
+                    std::istringstream(coord_str) >> point(1);
                 }
             }
             this->values.push_back(point);
diff --git a/xs/src/libslic3r/EdgeGrid.cpp b/xs/src/libslic3r/EdgeGrid.cpp
index 733ff2ad7..50f424e6d 100644
--- a/xs/src/libslic3r/EdgeGrid.cpp
+++ b/xs/src/libslic3r/EdgeGrid.cpp
@@ -117,15 +117,15 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 			m_bbox.merge(pts[j]);
 	}
 	coord_t eps = 16;
-	m_bbox.min.x -= eps;
-	m_bbox.min.y -= eps;
-	m_bbox.max.x += eps;
-	m_bbox.max.y += eps;
+	m_bbox.min(0) -= eps;
+	m_bbox.min(1) -= eps;
+	m_bbox.max(0) += eps;
+	m_bbox.max(1) += eps;
 
 	// 2) Initialize the edge grid.
 	m_resolution = resolution;
-	m_cols = (m_bbox.max.x - m_bbox.min.x + m_resolution - 1) / m_resolution;
-	m_rows = (m_bbox.max.y - m_bbox.min.y + m_resolution - 1) / m_resolution;
+	m_cols = (m_bbox.max(0) - m_bbox.min(0) + m_resolution - 1) / m_resolution;
+	m_rows = (m_bbox.max(1) - m_bbox.min(1) + m_resolution - 1) / m_resolution;
 	m_cells.assign(m_rows * m_cols, Cell());
 
 	// 3) First round of contour rasterization, count the edges per grid cell.
@@ -135,15 +135,15 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 			// End points of the line segment.
 			Slic3r::Point p1(pts[j]);
 			Slic3r::Point p2 = pts[(j + 1 == pts.size()) ? 0 : j + 1];
-			p1.x -= m_bbox.min.x;
-			p1.y -= m_bbox.min.y;
-			p2.x -= m_bbox.min.x;
-			p2.y -= m_bbox.min.y;
+			p1(0) -= m_bbox.min(0);
+			p1(1) -= m_bbox.min(1);
+			p2(0) -= m_bbox.min(0);
+			p2(1) -= m_bbox.min(1);
 		   	// Get the cells of the end points.
-		    coord_t ix    = p1.x / m_resolution;
-		    coord_t iy    = p1.y / m_resolution;
-		    coord_t ixb   = p2.x / m_resolution;
-		    coord_t iyb   = p2.y / m_resolution;
+		    coord_t ix    = p1(0) / m_resolution;
+		    coord_t iy    = p1(1) / m_resolution;
+		    coord_t ixb   = p2(0) / m_resolution;
+		    coord_t iyb   = p2(1) / m_resolution;
 			assert(ix >= 0 && ix < m_cols);
 			assert(iy >= 0 && iy < m_rows);
 			assert(ixb >= 0 && ixb < m_cols);
@@ -154,13 +154,13 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 				// Both ends fall into the same cell.
 				continue;
 		    // Raster the centeral part of the line.
-			coord_t dx = std::abs(p2.x - p1.x);
-			coord_t dy = std::abs(p2.y - p1.y);
-			if (p1.x < p2.x) {
-				int64_t ex = int64_t((ix + 1)*m_resolution - p1.x) * int64_t(dy);
-				if (p1.y < p2.y) {
+			coord_t dx = std::abs(p2(0) - p1(0));
+			coord_t dy = std::abs(p2(1) - p1(1));
+			if (p1(0) < p2(0)) {
+				int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy);
+				if (p1(1) < p2(1)) {
 					// x positive, y positive
-					int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx);
+					int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx);
 					do {
 						assert(ix <= ixb && iy <= iyb);
 						if (ex < ey) {
@@ -185,7 +185,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 				}
 				else {
 					// x positive, y non positive
-					int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx);
+					int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx);
 					do {
 						assert(ix <= ixb && iy >= iyb);
 						if (ex <= ey) {
@@ -203,10 +203,10 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 				}
 			}
 			else {
-				int64_t ex = int64_t(p1.x - ix*m_resolution) * int64_t(dy);
-				if (p1.y < p2.y) {
+				int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy);
+				if (p1(1) < p2(1)) {
 					// x non positive, y positive
-					int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx);
+					int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx);
 					do {
 						assert(ix >= ixb && iy <= iyb);
 						if (ex < ey) {
@@ -225,7 +225,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 				}
 				else {
 					// x non positive, y non positive
-					int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx);
+					int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx);
 					do {
 						assert(ix >= ixb && iy >= iyb);
 						if (ex < ey) {
@@ -279,15 +279,15 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 			// End points of the line segment.
 			Slic3r::Point p1(pts[j]);
 			Slic3r::Point p2 = pts[(j + 1 == pts.size()) ? 0 : j + 1];
-			p1.x -= m_bbox.min.x;
-			p1.y -= m_bbox.min.y;
-			p2.x -= m_bbox.min.x;
-			p2.y -= m_bbox.min.y;
+			p1(0) -= m_bbox.min(0);
+			p1(1) -= m_bbox.min(1);
+			p2(0) -= m_bbox.min(0);
+			p2(1) -= m_bbox.min(1);
 			// Get the cells of the end points.
-			coord_t ix = p1.x / m_resolution;
-			coord_t iy = p1.y / m_resolution;
-			coord_t ixb = p2.x / m_resolution;
-			coord_t iyb = p2.y / m_resolution;
+			coord_t ix = p1(0) / m_resolution;
+			coord_t iy = p1(1) / m_resolution;
+			coord_t ixb = p2(0) / m_resolution;
+			coord_t iyb = p2(1) / m_resolution;
 			assert(ix >= 0 && ix < m_cols);
 			assert(iy >= 0 && iy < m_rows);
 			assert(ixb >= 0 && ixb < m_cols);
@@ -298,13 +298,13 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 				// Both ends fall into the same cell.
 				continue;
 			// Raster the centeral part of the line.
-			coord_t dx = std::abs(p2.x - p1.x);
-			coord_t dy = std::abs(p2.y - p1.y);
-			if (p1.x < p2.x) {
-				int64_t ex = int64_t((ix + 1)*m_resolution - p1.x) * int64_t(dy);
-				if (p1.y < p2.y) {
+			coord_t dx = std::abs(p2(0) - p1(0));
+			coord_t dy = std::abs(p2(1) - p1(1));
+			if (p1(0) < p2(0)) {
+				int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy);
+				if (p1(1) < p2(1)) {
 					// x positive, y positive
-					int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx);
+					int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx);
 					do {
 						assert(ix <= ixb && iy <= iyb);
 						if (ex < ey) {
@@ -329,7 +329,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 				}
 				else {
 					// x positive, y non positive
-					int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx);
+					int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx);
 					do {
 						assert(ix <= ixb && iy >= iyb);
 						if (ex <= ey) {
@@ -347,10 +347,10 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 				}
 			}
 			else {
-				int64_t ex = int64_t(p1.x - ix*m_resolution) * int64_t(dy);
-				if (p1.y < p2.y) {
+				int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy);
+				if (p1(1) < p2(1)) {
 					// x non positive, y positive
-					int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx);
+					int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx);
 					do {
 						assert(ix >= ixb && iy <= iyb);
 						if (ex < ey) {
@@ -369,7 +369,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 				}
 				else {
 					// x non positive, y non positive
-					int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx);
+					int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx);
 					do {
 						assert(ix >= ixb && iy >= iyb);
 						if (ex < ey) {
@@ -429,15 +429,15 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed)
 		Point p1 = p1src;
 		Point p2 = p2src;
 		// Discretize the line segment p1, p2.
-		p1.x -= m_bbox.min.x;
-		p1.y -= m_bbox.min.y;
-		p2.x -= m_bbox.min.x;
-		p2.y -= m_bbox.min.y;
+		p1(0) -= m_bbox.min(0);
+		p1(1) -= m_bbox.min(1);
+		p2(0) -= m_bbox.min(0);
+		p2(1) -= m_bbox.min(1);
 		// Get the cells of the end points.
-		coord_t ix = div_floor(p1.x, m_resolution);
-		coord_t iy = div_floor(p1.y, m_resolution);
-		coord_t ixb = div_floor(p2.x, m_resolution);
-		coord_t iyb = div_floor(p2.y, m_resolution);
+		coord_t ix = div_floor(p1(0), m_resolution);
+		coord_t iy = div_floor(p1(1), m_resolution);
+		coord_t ixb = div_floor(p2(0), m_resolution);
+		coord_t iyb = div_floor(p2(1), m_resolution);
 //		assert(ix >= 0 && ix < m_cols);
 //		assert(iy >= 0 && iy < m_rows);
 //		assert(ixb >= 0 && ixb < m_cols);
@@ -449,12 +449,12 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed)
 			// Both ends fall into the same cell.
 			continue;
 		// Raster the centeral part of the line.
-		coord_t dx = std::abs(p2.x - p1.x);
-		coord_t dy = std::abs(p2.y - p1.y);
-		if (p1.x < p2.x) {
-			int64_t ex = int64_t((ix + 1)*m_resolution - p1.x) * int64_t(dy);
-			if (p1.y < p2.y) {
-				int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx);
+		coord_t dx = std::abs(p2(0) - p1(0));
+		coord_t dy = std::abs(p2(1) - p1(1));
+		if (p1(0) < p2(0)) {
+			int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy);
+			if (p1(1) < p2(1)) {
+				int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx);
 				do {
 					assert(ix <= ixb && iy <= iyb);
 					if (ex < ey) {
@@ -479,7 +479,7 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed)
 				} while (ix != ixb || iy != iyb);
 			}
 			else {
-				int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx);
+				int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx);
 				do {
 					assert(ix <= ixb && iy >= iyb);
 					if (ex <= ey) {
@@ -498,9 +498,9 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed)
 			}
 		}
 		else {
-			int64_t ex = int64_t(p1.x - ix*m_resolution) * int64_t(dy);
-			if (p1.y < p2.y) {
-				int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx);
+			int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy);
+			if (p1(1) < p2(1)) {
+				int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx);
 				do {
 					assert(ix >= ixb && iy <= iyb);
 					if (ex < ey) {
@@ -519,7 +519,7 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed)
 				} while (ix != ixb || iy != iyb);
 			}
 			else {
-				int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx);
+				int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx);
 				do {
 					assert(ix >= ixb && iy >= iyb);
 					if (ex < ey) {
@@ -556,8 +556,8 @@ bool EdgeGrid::Grid::line_cell_intersect(const Point &p1a, const Point &p2a, con
 {
 	BoundingBox bbox(p1a, p1a);
 	bbox.merge(p2a);
-	int64_t va_x = p2a.x - p1a.x;
-	int64_t va_y = p2a.y - p1a.y;
+	int64_t va_x = p2a(0) - p1a(0);
+	int64_t va_y = p2a(1) - p1a(1);
 	for (size_t i = cell.begin; i != cell.end; ++ i) {
 		const std::pair<size_t, size_t> &cell_data = m_cell_data[i];
 		// Contour indexed by the ith line of this cell.
@@ -576,21 +576,21 @@ bool EdgeGrid::Grid::line_cell_intersect(const Point &p1a, const Point &p2a, con
 		if (! bbox.overlap(bbox2))
 			continue;
 		// Now intersect the two line segments using exact arithmetics.
-		int64_t w1_x = p1b.x - p1a.x;
-		int64_t w1_y = p1b.y - p1a.y;
-		int64_t w2_x = p2b.x - p1a.x;
-		int64_t w2_y = p2b.y - p1a.y;
+		int64_t w1_x = p1b(0) - p1a(0);
+		int64_t w1_y = p1b(1) - p1a(1);
+		int64_t w2_x = p2b(0) - p1a(0);
+		int64_t w2_y = p2b(1) - p1a(1);
 		int64_t side1 = va_x * w1_y - va_y * w1_x;
 		int64_t side2 = va_x * w2_y - va_y * w2_x;
 		if (side1 == side2 && side1 != 0)
 			// The line segments don't intersect.
 			continue;
-		w1_x = p1a.x - p1b.x;
-		w1_y = p1a.y - p1b.y;
-		w2_x = p2a.x - p1b.x;
-		w2_y = p2a.y - p1b.y;
-		int64_t vb_x = p2b.x - p1b.x;
-		int64_t vb_y = p2b.y - p1b.y;
+		w1_x = p1a(0) - p1b(0);
+		w1_y = p1a(1) - p1b(1);
+		w2_x = p2a(0) - p1b(0);
+		w2_y = p2a(1) - p1b(1);
+		int64_t vb_x = p2b(0) - p1b(0);
+		int64_t vb_y = p2b(1) - p1b(1);
 		side1 = vb_x * w1_y - vb_y * w1_x;
 		side2 = vb_x * w2_y - vb_y * w2_x;
 		if (side1 == side2 && side1 != 0)
@@ -607,13 +607,13 @@ bool EdgeGrid::Grid::line_cell_intersect(const Point &p1a, const Point &p2a, con
 bool EdgeGrid::Grid::inside(const Point &pt_src)
 {
 	Point p = pt_src;
-	p.x -= m_bbox.min.x;
-	p.y -= m_bbox.min.y;
+	p(0) -= m_bbox.min(0);
+	p(1) -= m_bbox.min(1);
 	// Get the cell of the point.
-	if (p.x < 0 || p.y < 0)
+	if (p(0) < 0 || p(1) < 0)
 		return false;
-	coord_t ix = p.x / m_resolution;
-	coord_t iy = p.y / m_resolution;
+	coord_t ix = p(0) / m_resolution;
+	coord_t iy = p(1) / m_resolution;
 	if (ix >= this->m_cols || iy >= this->m_rows)
 		return false;
 
@@ -634,21 +634,21 @@ bool EdgeGrid::Grid::inside(const Point &pt_src)
 				idx2 = 0;
 			const Point &p1 = contour[idx1];
 			const Point &p2 = contour[idx2];
-			if (p1.y < p2.y) {
-				if (p.y < p1.y || p.y > p2.y)
+			if (p1(1) < p2(1)) {
+				if (p(1) < p1(1) || p(1) > p2(1))
 					continue;
 				//FIXME finish this!
 				int64_t vx = 0;// pt_src
 				//FIXME finish this!
 				int64_t det = 0;
-			} else if (p1.y != p2.y) {
-				assert(p1.y > p2.y);
-				if (p.y < p2.y || p.y > p1.y)
+			} else if (p1(1) != p2(1)) {
+				assert(p1(1) > p2(1));
+				if (p(1) < p2(1) || p(1) > p1(1))
 					continue;
 			} else {
-				assert(p1.y == p2.y);
-				if (p1.y == p.y) {
-					if (p.x >= p1.x && p.x <= p2.x)
+				assert(p1(1) == p2(1));
+				if (p1(1) == p(1)) {
+					if (p(0) >= p1(0) && p(0) <= p2(0))
 						// On the segment.
 						return true;
 					// Before or after the segment.
@@ -767,9 +767,9 @@ void EdgeGrid::Grid::calculate_sdf()
 				const Slic3r::Point &p1 = pts[ipt];
 				const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1];
 				// Segment vector
-				const Slic3r::Point v_seg = p1.vector_to(p2);
+				const Slic3r::Point v_seg = p2 - p1;
 				// l2 of v_seg
-				const int64_t l2_seg = int64_t(v_seg.x) * int64_t(v_seg.x) + int64_t(v_seg.y) * int64_t(v_seg.y);
+				const int64_t l2_seg = int64_t(v_seg(0)) * int64_t(v_seg(0)) + int64_t(v_seg(1)) * int64_t(v_seg(1));
 				// For each corner of this cell and its 1 ring neighbours:
 				for (int corner_y = -1; corner_y < 3; ++ corner_y) {
 					coord_t corner_r = r + corner_y;
@@ -780,28 +780,28 @@ void EdgeGrid::Grid::calculate_sdf()
 						if (corner_c < 0 || corner_c >= ncols)
 							continue;
 						float  &d_min = m_signed_distance_field[corner_r * ncols + corner_c];
-						Slic3r::Point pt(m_bbox.min.x + corner_c * m_resolution, m_bbox.min.y + corner_r * m_resolution);
-						Slic3r::Point v_pt = p1.vector_to(pt);
+						Slic3r::Point pt(m_bbox.min(0) + corner_c * m_resolution, m_bbox.min(1) + corner_r * m_resolution);
+						Slic3r::Point v_pt = pt - p1;
 						// dot(p2-p1, pt-p1)
-						int64_t t_pt = int64_t(v_seg.x) * int64_t(v_pt.x) + int64_t(v_seg.y) * int64_t(v_pt.y);
+						int64_t t_pt = int64_t(v_seg(0)) * int64_t(v_pt(0)) + int64_t(v_seg(1)) * int64_t(v_pt(1));
 						if (t_pt < 0) {
 							// Closest to p1.
-							double dabs = sqrt(int64_t(v_pt.x) * int64_t(v_pt.x) + int64_t(v_pt.y) * int64_t(v_pt.y));
+							double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
 							if (dabs < d_min) {
 								// Previous point.
 								const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1];
-								Slic3r::Point v_seg_prev = p0.vector_to(p1);
-								int64_t t2_pt = int64_t(v_seg_prev.x) * int64_t(v_pt.x) + int64_t(v_seg_prev.y) * int64_t(v_pt.y);
+								Slic3r::Point v_seg_prev = p1 - p0;
+								int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1));
 								if (t2_pt > 0) {
 									// Inside the wedge between the previous and the next segment.
 									// Set the signum depending on whether the vertex is convex or reflex.
-									int64_t det = int64_t(v_seg_prev.x) * int64_t(v_seg.y) - int64_t(v_seg_prev.y) * int64_t(v_seg.x);
+									int64_t det = int64_t(v_seg_prev(0)) * int64_t(v_seg(1)) - int64_t(v_seg_prev(1)) * int64_t(v_seg(0));
 									assert(det != 0);
 									d_min = dabs;
 									// Fill in an unsigned vector towards the zero iso surface.
 									float *l = &L[(corner_r * ncols + corner_c) << 1];
-									l[0] = std::abs(v_pt.x);
-									l[1] = std::abs(v_pt.y);
+									l[0] = std::abs(v_pt(0));
+									l[1] = std::abs(v_pt(1));
 								#ifdef _DEBUG
 									double dabs2 = sqrt(l[0]*l[0]+l[1]*l[1]);
 									assert(std::abs(dabs-dabs2) < 1e-4 * std::max(dabs, dabs2));
@@ -816,7 +816,7 @@ void EdgeGrid::Grid::calculate_sdf()
 						} else {
 							// Closest to the segment.
 							assert(t_pt >= 0 && t_pt <= l2_seg);
-							int64_t d_seg = int64_t(v_seg.y) * int64_t(v_pt.x) - int64_t(v_seg.x) * int64_t(v_pt.y);
+							int64_t d_seg = int64_t(v_seg(1)) * int64_t(v_pt(0)) - int64_t(v_seg(0)) * int64_t(v_pt(1));
 							double d = double(d_seg) / sqrt(double(l2_seg));
 							double dabs = std::abs(d);
 							if (dabs < d_min) {
@@ -824,8 +824,8 @@ void EdgeGrid::Grid::calculate_sdf()
 								// Fill in an unsigned vector towards the zero iso surface.
 								float *l = &L[(corner_r * ncols + corner_c) << 1];
 								float linv = float(d_seg) / float(l2_seg);
-								l[0] = std::abs(float(v_seg.y) * linv);
-								l[1] = std::abs(float(v_seg.x) * linv);
+								l[0] = std::abs(float(v_seg(1)) * linv);
+								l[1] = std::abs(float(v_seg(0)) * linv);
 								#ifdef _DEBUG
 									double dabs2 = sqrt(l[0]*l[0]+l[1]*l[1]);
 									assert(std::abs(dabs-dabs2) <= 1e-4 * std::max(dabs, dabs2));
@@ -1059,8 +1059,8 @@ void EdgeGrid::Grid::calculate_sdf()
 
 float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const
 {
-	coord_t x = pt.x - m_bbox.min.x;
-	coord_t y = pt.y - m_bbox.min.y;
+	coord_t x = pt(0) - m_bbox.min(0);
+	coord_t y = pt(1) - m_bbox.min(1);
 	coord_t w = m_resolution * m_cols;
 	coord_t h = m_resolution * m_rows;
 	bool    clamped = false;
@@ -1124,39 +1124,39 @@ float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const
  
 bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment) const {
 	BoundingBox bbox;
-	bbox.min = bbox.max = Point(pt.x - m_bbox.min.x, pt.y - m_bbox.min.y);
+	bbox.min = bbox.max = Point(pt(0) - m_bbox.min(0), pt(1) - m_bbox.min(1));
 	bbox.defined = true;
 	// Upper boundary, round to grid and test validity.
-	bbox.max.x += search_radius;
-	bbox.max.y += search_radius;
-	if (bbox.max.x < 0 || bbox.max.y < 0)
+	bbox.max(0) += search_radius;
+	bbox.max(1) += search_radius;
+	if (bbox.max(0) < 0 || bbox.max(1) < 0)
 		return false;
-	bbox.max.x /= m_resolution;
-	bbox.max.y /= m_resolution;
-	if (bbox.max.x >= m_cols)
-		bbox.max.x = m_cols - 1;
-	if (bbox.max.y >= m_rows)
-		bbox.max.y = m_rows - 1;
+	bbox.max(0) /= m_resolution;
+	bbox.max(1) /= m_resolution;
+	if (bbox.max(0) >= m_cols)
+		bbox.max(0) = m_cols - 1;
+	if (bbox.max(1) >= m_rows)
+		bbox.max(1) = m_rows - 1;
 	// Lower boundary, round to grid and test validity.
-	bbox.min.x -= search_radius;
-	bbox.min.y -= search_radius;
-	if (bbox.min.x < 0)
-		bbox.min.x = 0;
-	if (bbox.min.y < 0)
-		bbox.min.y = 0;
-	bbox.min.x /= m_resolution;
-	bbox.min.y /= m_resolution;
+	bbox.min(0) -= search_radius;
+	bbox.min(1) -= search_radius;
+	if (bbox.min(0) < 0)
+		bbox.min(0) = 0;
+	if (bbox.min(1) < 0)
+		bbox.min(1) = 0;
+	bbox.min(0) /= m_resolution;
+	bbox.min(1) /= m_resolution;
 	// Is the interval empty?
-	if (bbox.min.x > bbox.max.x ||
-		bbox.min.y > bbox.max.y)
+	if (bbox.min(0) > bbox.max(0) ||
+		bbox.min(1) > bbox.max(1))
 		return false;
 	// Traverse all cells in the bounding box.
 	float d_min = search_radius;
 	// Signum of the distance field at pt.
 	int sign_min = 0;
 	bool on_segment = false;
-	for (int r = bbox.min.y; r <= bbox.max.y; ++ r) {
-		for (int c = bbox.min.x; c <= bbox.max.x; ++ c) {
+	for (int r = bbox.min(1); r <= bbox.max(1); ++ r) {
+		for (int c = bbox.min(0); c <= bbox.max(0); ++ c) {
 			const Cell &cell = m_cells[r * m_cols + c];
 			for (size_t i = cell.begin; i < cell.end; ++ i) {
 				const Slic3r::Points &pts = *m_contours[m_cell_data[i].first];
@@ -1164,25 +1164,25 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu
 				// End points of the line segment.
 				const Slic3r::Point &p1 = pts[ipt];
 				const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1];
-				Slic3r::Point v_seg = p1.vector_to(p2);
-				Slic3r::Point v_pt = p1.vector_to(pt);
+				Slic3r::Point v_seg = p2 - p1;
+				Slic3r::Point v_pt  = pt - p1;
 				// dot(p2-p1, pt-p1)
-				int64_t t_pt = int64_t(v_seg.x) * int64_t(v_pt.x) + int64_t(v_seg.y) * int64_t(v_pt.y);
+				int64_t t_pt = int64_t(v_seg(0)) * int64_t(v_pt(0)) + int64_t(v_seg(1)) * int64_t(v_pt(1));
 				// l2 of seg
-				int64_t l2_seg = int64_t(v_seg.x) * int64_t(v_seg.x) + int64_t(v_seg.y) * int64_t(v_seg.y);
+				int64_t l2_seg = int64_t(v_seg(0)) * int64_t(v_seg(0)) + int64_t(v_seg(1)) * int64_t(v_seg(1));
 				if (t_pt < 0) {
 					// Closest to p1.
-					double dabs = sqrt(int64_t(v_pt.x) * int64_t(v_pt.x) + int64_t(v_pt.y) * int64_t(v_pt.y));
+					double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
 					if (dabs < d_min) {
 						// Previous point.
 						const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1];
-						Slic3r::Point v_seg_prev = p0.vector_to(p1);
-						int64_t t2_pt = int64_t(v_seg_prev.x) * int64_t(v_pt.x) + int64_t(v_seg_prev.y) * int64_t(v_pt.y);
+						Slic3r::Point v_seg_prev = p1 - p0;
+						int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1));
 						if (t2_pt > 0) {
 							// Inside the wedge between the previous and the next segment.
 							d_min = dabs;
 							// Set the signum depending on whether the vertex is convex or reflex.
-							int64_t det = int64_t(v_seg_prev.x) * int64_t(v_seg.y) - int64_t(v_seg_prev.y) * int64_t(v_seg.x);
+							int64_t det = int64_t(v_seg_prev(0)) * int64_t(v_seg(1)) - int64_t(v_seg_prev(1)) * int64_t(v_seg(0));
 							assert(det != 0);
 							sign_min = (det > 0) ? 1 : -1;
 							on_segment = false;
@@ -1195,7 +1195,7 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu
 				} else {
 					// Closest to the segment.
 					assert(t_pt >= 0 && t_pt <= l2_seg);
-					int64_t d_seg = int64_t(v_seg.y) * int64_t(v_pt.x) - int64_t(v_seg.x) * int64_t(v_pt.y);
+					int64_t d_seg = int64_t(v_seg(1)) * int64_t(v_pt(0)) - int64_t(v_seg(0)) * int64_t(v_pt(1));
 					double d = double(d_seg) / sqrt(double(l2_seg));
 					double dabs = std::abs(d);
 					if (dabs < d_min) {
@@ -1307,7 +1307,7 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const
 					const Line &line_next = lines[it->second];
 					const Vector v1 = line_current.vector();
 					const Vector v2 = line_next.vector();
-					int64_t cross = int64_t(v1.x) * int64_t(v2.y) - int64_t(v2.x) * int64_t(v1.y);
+					int64_t cross = int64_t(v1(0)) * int64_t(v2(1)) - int64_t(v2(0)) * int64_t(v1(1));
 					if (cross > 0) {
 						// This has to be a convex right angle. There is no better next line.
 						i_next = it->second;
@@ -1328,10 +1328,10 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const
 		Polygon &poly = out[i];
 		for (size_t j = 0; j < poly.points.size(); ++ j) {
 			Point &p = poly.points[j];
-			p.x *= m_resolution;
-			p.y *= m_resolution;
-			p.x += m_bbox.min.x;
-			p.y += m_bbox.min.y;
+			p(0) *= m_resolution;
+			p(1) *= m_resolution;
+			p(0) += m_bbox.min(0);
+			p(1) += m_bbox.min(1);
 		}
 		// Shrink the contour slightly, so if the same contour gets discretized and simplified again, one will get the same result.
 		// Remove collineaer points.
@@ -1341,11 +1341,11 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const
 			size_t j0 = (j == 0) ? poly.points.size() - 1 : j - 1;
 			size_t j2 = (j + 1 == poly.points.size()) ? 0 : j + 1;
 			Point  v  = poly.points[j2] - poly.points[j0];
-			if (v.x != 0 && v.y != 0) {
+			if (v(0) != 0 && v(1) != 0) {
 				// This is a corner point. Copy it to the output contour.
 				Point p = poly.points[j];
-				p.y += (v.x < 0) ? - offset : offset;
-				p.x += (v.y > 0) ? - offset : offset;
+				p(1) += (v(0) < 0) ? - offset : offset;
+				p(0) += (v(1) > 0) ? - offset : offset;
 				pts.push_back(p);
 			} 
 		}
@@ -1357,8 +1357,8 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const
 #if 0
 void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path)
 {
-	unsigned int w = (bbox.max.x - bbox.min.x + resolution - 1) / resolution;
-	unsigned int h = (bbox.max.y - bbox.min.y + resolution - 1) / resolution;
+	unsigned int w = (bbox.max(0) - bbox.min(0) + resolution - 1) / resolution;
+	unsigned int h = (bbox.max(1) - bbox.min(1) + resolution - 1) / resolution;
 	wxImage img(w, h);
     unsigned char *data = img.GetData();
     memset(data, 0, w * h * 3);
@@ -1371,7 +1371,7 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo
 	for (coord_t r = 0; r < h; ++r) {
     	for (coord_t c = 0; c < w; ++ c) {
 			unsigned char *pxl = data + (((h - r - 1) * w) + c) * 3;
-			Point pt(c * resolution + bbox.min.x, r * resolution + bbox.min.y);
+			Point pt(c * resolution + bbox.min(0), r * resolution + bbox.min(1));
 			coordf_t min_dist;
 			bool on_segment = true;
 			#if 0
@@ -1409,8 +1409,8 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo
 				pxl[2] = 0;
 			}
 
-			float gridx = float(pt.x - grid.bbox().min.x) / float(grid.resolution());
-			float gridy = float(pt.y - grid.bbox().min.y) / float(grid.resolution());
+			float gridx = float(pt(0) - grid.bbox().min(0)) / float(grid.resolution());
+			float gridy = float(pt(1) - grid.bbox().min(1)) / float(grid.resolution());
 			if (gridx >= -0.4f && gridy >= -0.4f && gridx <= grid.cols() + 0.4f && gridy <= grid.rows() + 0.4f) {
 				int ix = int(floor(gridx + 0.5f));
 				int iy = int(floor(gridy + 0.5f));
diff --git a/xs/src/libslic3r/ExPolygon.cpp b/xs/src/libslic3r/ExPolygon.cpp
index cd57fd7b0..4294fe543 100644
--- a/xs/src/libslic3r/ExPolygon.cpp
+++ b/xs/src/libslic3r/ExPolygon.cpp
@@ -34,54 +34,43 @@ ExPolygon::operator Polylines() const
     return to_polylines(*this);
 }
 
-void
-ExPolygon::scale(double factor)
+void ExPolygon::scale(double factor)
 {
     contour.scale(factor);
-    for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) {
-        (*it).scale(factor);
-    }
+    for (Polygon &hole : holes)
+        hole.scale(factor);
 }
 
-void
-ExPolygon::translate(double x, double y)
+void ExPolygon::translate(double x, double y)
 {
     contour.translate(x, y);
-    for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) {
-        (*it).translate(x, y);
-    }
+    for (Polygon &hole : holes)
+        hole.translate(x, y);
 }
 
-void
-ExPolygon::rotate(double angle)
+void ExPolygon::rotate(double angle)
 {
     contour.rotate(angle);
-    for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) {
-        (*it).rotate(angle);
-    }
+    for (Polygon &hole : holes)
+        hole.rotate(angle);
 }
 
-void
-ExPolygon::rotate(double angle, const Point &center)
+void ExPolygon::rotate(double angle, const Point &center)
 {
     contour.rotate(angle, center);
-    for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) {
-        (*it).rotate(angle, center);
-    }
+    for (Polygon &hole : holes)
+        hole.rotate(angle, center);
 }
 
-double
-ExPolygon::area() const
+double ExPolygon::area() const
 {
     double a = this->contour.area();
-    for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
-        a -= -(*it).area();  // holes have negative area
-    }
+    for (const Polygon &hole : holes)
+        a -= - hole.area();  // holes have negative area
     return a;
 }
 
-bool
-ExPolygon::is_valid() const
+bool ExPolygon::is_valid() const
 {
     if (!this->contour.is_valid() || !this->contour.is_counter_clockwise()) return false;
     for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
@@ -90,20 +79,17 @@ ExPolygon::is_valid() const
     return true;
 }
 
-bool
-ExPolygon::contains(const Line &line) const
+bool ExPolygon::contains(const Line &line) const
 {
-    return this->contains((Polyline)line);
+    return this->contains(Polyline(line.a, line.b));
 }
 
-bool
-ExPolygon::contains(const Polyline &polyline) const
+bool ExPolygon::contains(const Polyline &polyline) const
 {
     return diff_pl((Polylines)polyline, *this).empty();
 }
 
-bool
-ExPolygon::contains(const Polylines &polylines) const
+bool ExPolygon::contains(const Polylines &polylines) const
 {
     #if 0
     BoundingBox bbox = get_extents(polylines);
@@ -120,8 +106,7 @@ ExPolygon::contains(const Polylines &polylines) const
     return pl_out.empty();
 }
 
-bool
-ExPolygon::contains(const Point &point) const
+bool ExPolygon::contains(const Point &point) const
 {
     if (!this->contour.contains(point)) return false;
     for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
@@ -131,8 +116,7 @@ ExPolygon::contains(const Point &point) const
 }
 
 // inclusive version of contains() that also checks whether point is on boundaries
-bool
-ExPolygon::contains_b(const Point &point) const
+bool ExPolygon::contains_b(const Point &point) const
 {
     return this->contains(point) || this->has_boundary_point(point);
 }
@@ -243,25 +227,24 @@ ExPolygon::medial_axis(double max_width, double min_width, ThickPolylines* polyl
         Point new_front = polyline.points.front();
         Point new_back  = polyline.points.back();
         if (polyline.endpoints.first && !this->has_boundary_point(new_front)) {
-            Line line(polyline.points.front(), polyline.points[1]);
-            
+            Vec2d p1 = polyline.points.front().cast<double>();
+            Vec2d p2 = polyline.points[1].cast<double>();
             // prevent the line from touching on the other side, otherwise intersection() might return that solution
-            if (polyline.points.size() == 2) line.b = line.midpoint();
-            
-            line.extend_start(max_width);
-            (void)this->contour.intersection(line, &new_front);
+            if (polyline.points.size() == 2)
+                p2 = (p1 + p2) * 0.5;
+            // Extend the start of the segment.
+            p1 -= (p2 - p1).normalized() * max_width;
+            this->contour.intersection(Line(p1.cast<coord_t>(), p2.cast<coord_t>()), &new_front);
         }
         if (polyline.endpoints.second && !this->has_boundary_point(new_back)) {
-            Line line(
-                *(polyline.points.end() - 2),
-                polyline.points.back()
-            );
-            
+            Vec2d p1 = (polyline.points.end() - 2)->cast<double>();
+            Vec2d p2 = polyline.points.back().cast<double>();
             // prevent the line from touching on the other side, otherwise intersection() might return that solution
-            if (polyline.points.size() == 2) line.a = line.midpoint();
-            line.extend_end(max_width);
-            
-            (void)this->contour.intersection(line, &new_back);
+            if (polyline.points.size() == 2)
+                p1 = (p1 + p2) * 0.5;
+            // Extend the start of the segment.
+            p2 += (p2 - p1).normalized() * max_width;
+            this->contour.intersection(Line(p1.cast<coord_t>(), p2.cast<coord_t>()), &new_back);
         }
         polyline.points.front() = new_front;
         polyline.points.back()  = new_back;
@@ -294,14 +277,14 @@ ExPolygon::medial_axis(double max_width, double min_width, ThickPolylines* polyl
             // find another polyline starting here
             for (size_t j = i+1; j < pp.size(); ++j) {
                 ThickPolyline& other = pp[j];
-                if (polyline.last_point().coincides_with(other.last_point())) {
+                if (polyline.last_point() == other.last_point()) {
                     other.reverse();
-                } else if (polyline.first_point().coincides_with(other.last_point())) {
+                } else if (polyline.first_point() == other.last_point()) {
                     polyline.reverse();
                     other.reverse();
-                } else if (polyline.first_point().coincides_with(other.first_point())) {
+                } else if (polyline.first_point() == other.first_point()) {
                     polyline.reverse();
-                } else if (!polyline.last_point().coincides_with(other.first_point())) {
+                } else if (polyline.last_point() != other.first_point()) {
                     continue;
                 }
                 
@@ -361,7 +344,7 @@ ExPolygon::get_trapezoids2(Polygons* polygons) const
     std::vector<coord_t> xx;
     xx.reserve(pp.size());
     for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
-        xx.push_back(p->x);
+        xx.push_back(p->x());
     std::sort(xx.begin(), xx.end());
     
     // find trapezoids by looping from first to next-to-last coordinate
@@ -372,14 +355,14 @@ ExPolygon::get_trapezoids2(Polygons* polygons) const
         // build rectangle
         Polygon poly;
         poly.points.resize(4);
-        poly[0].x = *x;
-        poly[0].y = bb.min.y;
-        poly[1].x = next_x;
-        poly[1].y = bb.min.y;
-        poly[2].x = next_x;
-        poly[2].y = bb.max.y;
-        poly[3].x = *x;
-        poly[3].y = bb.max.y;
+        poly[0](0) = *x;
+        poly[0](1) = bb.min(1);
+        poly[1](0) = next_x;
+        poly[1](1) = bb.min(1);
+        poly[2](0) = next_x;
+        poly[2](1) = bb.max(1);
+        poly[3](0) = *x;
+        poly[3](1) = bb.max(1);
         
         // intersect with this expolygon
         // append results to return value
@@ -425,10 +408,11 @@ ExPolygon::triangulate_pp(Polygons* polygons) const
             TPPLPoly p;
             p.Init(int(ex->contour.points.size()));
             //printf(PRINTF_ZU "\n0\n", ex->contour.points.size());
-            for (Points::const_iterator point = ex->contour.points.begin(); point != ex->contour.points.end(); ++point) {
-                p[ point-ex->contour.points.begin() ].x = point->x;
-                p[ point-ex->contour.points.begin() ].y = point->y;
-                //printf("%ld %ld\n", point->x, point->y);
+            for (const Point &point : ex->contour.points) {
+                size_t i = &point - &ex->contour.points.front();
+                p[i].x = point(0);
+                p[i].y = point(1);
+                //printf("%ld %ld\n", point->x(), point->y());
             }
             p.SetHole(false);
             input.push_back(p);
@@ -439,10 +423,11 @@ ExPolygon::triangulate_pp(Polygons* polygons) const
             TPPLPoly p;
             p.Init(hole->points.size());
             //printf(PRINTF_ZU "\n1\n", hole->points.size());
-            for (Points::const_iterator point = hole->points.begin(); point != hole->points.end(); ++point) {
-                p[ point-hole->points.begin() ].x = point->x;
-                p[ point-hole->points.begin() ].y = point->y;
-                //printf("%ld %ld\n", point->x, point->y);
+            for (const Point &point : hole->points) {
+                size_t i = &point - &hole->points.front();
+                p[i].x = point(0);
+                p[i].y = point(1);
+                //printf("%ld %ld\n", point->x(), point->y());
             }
             p.SetHole(true);
             input.push_back(p);
@@ -460,8 +445,8 @@ ExPolygon::triangulate_pp(Polygons* polygons) const
         Polygon p;
         p.points.resize(num_points);
         for (long i = 0; i < num_points; ++i) {
-            p.points[i].x = coord_t((*poly)[i].x);
-            p.points[i].y = coord_t((*poly)[i].y);
+            p.points[i](0) = coord_t((*poly)[i].x);
+            p.points[i](1) = coord_t((*poly)[i].y);
         }
         polygons->push_back(p);
     }
@@ -477,19 +462,17 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const
 
         // contour
         std::vector<p2t::Point*> ContourPoints;
-        for (Points::const_iterator point = ex->contour.points.begin(); point != ex->contour.points.end(); ++point) {
+        for (const Point &pt : ex->contour.points)
             // We should delete each p2t::Point object
-            ContourPoints.push_back(new p2t::Point(point->x, point->y));
-        }
+            ContourPoints.push_back(new p2t::Point(pt(0), pt(1)));
         p2t::CDT cdt(ContourPoints);
 
         // holes
         for (Polygons::const_iterator hole = ex->holes.begin(); hole != ex->holes.end(); ++hole) {
             std::vector<p2t::Point*> points;
-            for (Points::const_iterator point = hole->points.begin(); point != hole->points.end(); ++point) {
+            for (const Point &pt : hole->points)
                 // will be destructed in SweepContext::~SweepContext
-                points.push_back(new p2t::Point(point->x, point->y));
-            }
+                points.push_back(new p2t::Point(pt(0), pt(1)));
             cdt.AddHole(points);
         }
         
@@ -506,9 +489,8 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const
             polygons->push_back(p);
         }
 
-        for(std::vector<p2t::Point*>::iterator it = ContourPoints.begin(); it != ContourPoints.end(); ++it) {
-            delete *it;
-        }
+        for (p2t::Point *ptr : ContourPoints)
+            delete ptr;
     }
 }
 
@@ -523,17 +505,6 @@ ExPolygon::lines() const
     return lines;
 }
 
-std::string
-ExPolygon::dump_perl() const
-{
-    std::ostringstream ret;
-    ret << "[" << this->contour.dump_perl();
-    for (Polygons::const_iterator h = this->holes.begin(); h != this->holes.end(); ++h)
-        ret << "," << h->dump_perl();
-    ret << "]";
-    return ret.str();
-}
-
 BoundingBox get_extents(const ExPolygon &expolygon)
 {
     return get_extents(expolygon.contour);
diff --git a/xs/src/libslic3r/ExPolygon.hpp b/xs/src/libslic3r/ExPolygon.hpp
index f4782ba55..4833ee49e 100644
--- a/xs/src/libslic3r/ExPolygon.hpp
+++ b/xs/src/libslic3r/ExPolygon.hpp
@@ -63,7 +63,6 @@ public:
     void triangulate_pp(Polygons* polygons) const;
     void triangulate_p2t(Polygons* polygons) const;
     Lines lines() const;
-    std::string dump_perl() const;
 };
 
 // Count a nuber of polygons stored inside the vector of expolygons.
diff --git a/xs/src/libslic3r/ExtrusionEntity.cpp b/xs/src/libslic3r/ExtrusionEntity.cpp
index c6f67b169..92f0d3669 100644
--- a/xs/src/libslic3r/ExtrusionEntity.cpp
+++ b/xs/src/libslic3r/ExtrusionEntity.cpp
@@ -220,7 +220,7 @@ void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang)
         double min_non_overhang = std::numeric_limits<double>::max();
         for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) {
             Point p_tmp = point.projection_onto(path->polyline);
-            double dist = point.distance_to(p_tmp);
+            double dist = (p_tmp - point).cast<double>().norm();
             if (dist < min) {
                 p = p_tmp;
                 min = dist;
diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp
index 15363e8ed..90675c04a 100644
--- a/xs/src/libslic3r/ExtrusionEntity.hpp
+++ b/xs/src/libslic3r/ExtrusionEntity.hpp
@@ -149,7 +149,7 @@ public:
     // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
     double min_mm3_per_mm() const { return this->mm3_per_mm; }
     Polyline as_polyline() const { return this->polyline; }
-    virtual double total_volume() const { return mm3_per_mm * unscale(length()); }
+    virtual double total_volume() const { return mm3_per_mm * unscale<double>(length()); }
 
 private:
     void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const;
diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp
index 382455fe3..3b34145f8 100644
--- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp
+++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp
@@ -50,10 +50,15 @@ public:
             src.clear();
         }
     }
-    void append(const ExtrusionPaths &paths) { 
+    void append(const ExtrusionPaths &paths) {
         this->entities.reserve(this->entities.size() + paths.size());
-        for (ExtrusionPaths::const_iterator path = paths.begin(); path != paths.end(); ++path)
-            this->entities.push_back(path->clone());
+        for (const ExtrusionPath &path : paths)
+            this->entities.emplace_back(path.clone());
+    }
+    void append(ExtrusionPaths &&paths) {
+        this->entities.reserve(this->entities.size() + paths.size());
+        for (ExtrusionPath &path : paths)
+            this->entities.emplace_back(new ExtrusionPath(std::move(path)));
     }
     void replace(size_t i, const ExtrusionEntity &entity);
     void remove(size_t i);
diff --git a/xs/src/libslic3r/ExtrusionSimulator.cpp b/xs/src/libslic3r/ExtrusionSimulator.cpp
index daecbc0d1..fcb2fe825 100644
--- a/xs/src/libslic3r/ExtrusionSimulator.cpp
+++ b/xs/src/libslic3r/ExtrusionSimulator.cpp
@@ -893,24 +893,24 @@ ExtrusionSimulator::~ExtrusionSimulator()
 void ExtrusionSimulator::set_image_size(const Point &image_size)
 {
 	// printf("ExtrusionSimulator::set_image_size()\n");
-	if (this->image_size.x == image_size.x &&
-		this->image_size.y == image_size.y)
+	if (this->image_size.x() == image_size.x() &&
+		this->image_size.y() == image_size.y())
 		return;
 
 	// printf("Setting image size: %d, %d\n", image_size.x, image_size.y);
 	this->image_size = image_size;
 	// Allocate the image data in an RGBA format.
 	// printf("Allocating image data, size %d\n", image_size.x * image_size.y * 4);
-	pimpl->image_data.assign(image_size.x * image_size.y * 4, 0);
+	pimpl->image_data.assign(image_size.x() * image_size.y() * 4, 0);
 	// printf("Allocating image data, allocated\n");
 
 	//FIXME fill the image with red vertical lines.
-	for (size_t r = 0; r < image_size.y; ++ r) {
-		for (size_t c = 0; c < image_size.x; c += 2) {
+	for (size_t r = 0; r < image_size.y(); ++ r) {
+		for (size_t c = 0; c < image_size.x(); c += 2) {
 			// Color red
-			pimpl->image_data[r * image_size.x * 4 + c * 4] = 255;
+			pimpl->image_data[r * image_size.x() * 4 + c * 4] = 255;
 			// Opacity full
-			pimpl->image_data[r * image_size.x * 4 + c * 4 + 3] = 255;
+			pimpl->image_data[r * image_size.x() * 4 + c * 4 + 3] = 255;
 		}
 	}
 	// printf("Allocating image data, set\n");
@@ -922,8 +922,8 @@ void ExtrusionSimulator::set_viewport(const BoundingBox &viewport)
 	if (this->viewport != viewport) {
 		this->viewport = viewport;
 		Point sz = viewport.size();
-		pimpl->accumulator.resize(boost::extents[sz.y][sz.x]);
-		pimpl->bitmap.resize(boost::extents[sz.y*pimpl->bitmap_oversampled][sz.x*pimpl->bitmap_oversampled]);
+		pimpl->accumulator.resize(boost::extents[sz.y()][sz.x()]);
+		pimpl->bitmap.resize(boost::extents[sz.y()*pimpl->bitmap_oversampled][sz.x()*pimpl->bitmap_oversampled]);
 		// printf("Accumulator size: %d, %d\n", sz.y, sz.x);
 	}
 }
@@ -943,8 +943,8 @@ void ExtrusionSimulator::reset_accumulator()
 	// printf("ExtrusionSimulator::reset_accumulator()\n");
 	Point sz = viewport.size();
 	// printf("Reset accumulator, Accumulator size: %d, %d\n", sz.y, sz.x);
-	memset(&pimpl->accumulator[0][0], 0, sizeof(float) * sz.x * sz.y);
-	memset(&pimpl->bitmap[0][0], 0, sz.x * sz.y * pimpl->bitmap_oversampled * pimpl->bitmap_oversampled);
+	memset(&pimpl->accumulator[0][0], 0, sizeof(float) * sz.x() * sz.y());
+	memset(&pimpl->bitmap[0][0], 0, sz.x() * sz.y() * pimpl->bitmap_oversampled * pimpl->bitmap_oversampled);
 	pimpl->extrusion_points.clear();
 	// printf("Reset accumulator, done.\n");
 }
@@ -955,17 +955,17 @@ void ExtrusionSimulator::extrude_to_accumulator(const ExtrusionPath &path, const
 	// Convert the path to V2f points, shift and scale them to the viewport.
 	std::vector<V2f> polyline;
 	polyline.reserve(path.polyline.points.size());
-	float scalex  = float(viewport.size().x) / float(bbox.size().x);
-	float scaley  = float(viewport.size().y) / float(bbox.size().y);
+	float scalex  = float(viewport.size().x()) / float(bbox.size().x());
+	float scaley  = float(viewport.size().y()) / float(bbox.size().y());
 	float w = scale_(path.width) * scalex;
 	float h = scale_(path.height) * scalex;
 	w = scale_(path.mm3_per_mm / path.height) * scalex;
 	// printf("scalex: %f, scaley: %f\n", scalex, scaley);
-	// printf("bbox: %d,%d %d,%d\n", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y);
+	// printf("bbox: %d,%d %d,%d\n", bbox.min.x(), bbox.min.y, bbox.max.x(), bbox.max.y);
 	for (Points::const_iterator it = path.polyline.points.begin(); it != path.polyline.points.end(); ++ it) {
-		// printf("point %d,%d\n", it->x+shift.x, it->y+shift.y);
+		// printf("point %d,%d\n", it->x+shift.x(), it->y+shift.y);
 		ExtrusionPoint ept;
-		ept.center = V2f(float(it->x+shift.x-bbox.min.x) * scalex, float(it->y+shift.y-bbox.min.y) * scaley);
+		ept.center = V2f(float((*it)(0)+shift.x()-bbox.min.x()) * scalex, float((*it)(1)+shift.y()-bbox.min.y()) * scaley);
 		ept.radius = w/2.f;
 		ept.height = 0.5f;
 		polyline.push_back(ept.center);
@@ -989,9 +989,9 @@ void ExtrusionSimulator::evaluate_accumulator(ExtrusionSimulationType simulation
 
 	if (simulationType > ExtrusionSimulationDontSpread) {
 		// Average the cells of a bitmap into a lower resolution floating point mask.
-		A2f mask(boost::extents[sz.y][sz.x]);
-		for (int r = 0; r < sz.y; ++r) {
-			for (int c = 0; c < sz.x; ++c) {
+		A2f mask(boost::extents[sz.y()][sz.x()]);
+		for (int r = 0; r < sz.y(); ++r) {
+			for (int c = 0; c < sz.x(); ++c) {
 				float p = 0;
 				for (int j = 0; j < pimpl->bitmap_oversampled; ++ j) {
 					for (int i = 0; i < pimpl->bitmap_oversampled; ++ i) {
@@ -1009,9 +1009,9 @@ void ExtrusionSimulator::evaluate_accumulator(ExtrusionSimulationType simulation
 	}
 
 	// Color map the accumulator.
-	for (int r = 0; r < sz.y; ++r) {
-		unsigned char *ptr = &pimpl->image_data[(image_size.x * (viewport.min.y + r) + viewport.min.x) * 4];
-		for (int c = 0; c < sz.x; ++c) {
+	for (int r = 0; r < sz.y(); ++r) {
+		unsigned char *ptr = &pimpl->image_data[(image_size.x() * (viewport.min.y() + r) + viewport.min.x()) * 4];
+		for (int c = 0; c < sz.x(); ++c) {
 			#if 1
 			float p   = pimpl->accumulator[r][c];
 			#else
diff --git a/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp
index aa9774784..6a37e4369 100644
--- a/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp
+++ b/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp
@@ -54,9 +54,9 @@ static std::vector<coordf_t> perpendPoints(const coordf_t offset, const size_t b
 // components that are outside these limits are set to the limits.
 static inline void trim(Pointfs &pts, coordf_t minX, coordf_t minY, coordf_t maxX, coordf_t maxY)
 {
-    for (Pointfs::iterator it = pts.begin(); it != pts.end(); ++ it) {
-        it->x = clamp(minX, maxX, it->x);
-        it->y = clamp(minY, maxY, it->y);
+    for (Vec2d &pt : pts) {
+        pt(0) = clamp(minX, maxX, pt(0));
+        pt(1) = clamp(minY, maxY, pt(1));
     }
 }
 
@@ -66,7 +66,7 @@ static inline Pointfs zip(const std::vector<coordf_t> &x, const std::vector<coor
     Pointfs out;
     out.reserve(x.size());
     for (size_t i = 0; i < x.size(); ++ i)
-        out.push_back(Pointf(x[i], y[i]));
+        out.push_back(Vec2d(x[i], y[i]));
     return out;
 }
 
@@ -128,7 +128,7 @@ static Polylines makeGrid(coord_t z, coord_t gridSize, size_t gridWidth, size_t
         result.push_back(Polyline());
         Polyline &polyline = result.back();
         for (Pointfs::const_iterator it = it_polylines->begin(); it != it_polylines->end(); ++ it)
-            polyline.points.push_back(Point(coord_t(it->x * scaleFactor), coord_t(it->y * scaleFactor)));
+            polyline.points.push_back(Point(coord_t((*it)(0) * scaleFactor), coord_t((*it)(1) * scaleFactor)));
     }
     return result;
 }
@@ -153,13 +153,13 @@ void Fill3DHoneycomb::_fill_surface_single(
     Polylines   polylines = makeGrid(
         scale_(this->z),
         distance,
-        ceil(bb.size().x / distance) + 1,
-        ceil(bb.size().y / distance) + 1,
+        ceil(bb.size()(0) / distance) + 1,
+        ceil(bb.size()(1) / distance) + 1,
         ((this->layer_id/thickness_layers) % 2) + 1);
     
     // move pattern in place
     for (Polylines::iterator it = polylines.begin(); it != polylines.end(); ++ it)
-        it->translate(bb.min.x, bb.min.y);
+        it->translate(bb.min(0), bb.min(1));
 
     // clip pattern to boundaries
     polylines = intersection_pl(polylines, (Polygons)expolygon);
@@ -187,7 +187,7 @@ void Fill3DHoneycomb::_fill_surface_single(
                 const Point &last_point = pts_end.back();
                 // TODO: we should also check that both points are on a fill_boundary to avoid 
                 // connecting paths on the boundaries of internal regions
-                if (first_point.distance_to(last_point) <= 1.5 * distance && 
+                if ((last_point - first_point).cast<double>().norm() <= 1.5 * distance && 
                     expolygon_off.contains(Line(last_point, first_point))) {
                     // Append the polyline.
                     pts_end.insert(pts_end.end(), it_polyline->points.begin(), it_polyline->points.end());
diff --git a/xs/src/libslic3r/Fill/FillBase.hpp b/xs/src/libslic3r/Fill/FillBase.hpp
index 62d18e518..b67d14339 100644
--- a/xs/src/libslic3r/Fill/FillBase.hpp
+++ b/xs/src/libslic3r/Fill/FillBase.hpp
@@ -121,11 +121,11 @@ public:
         return aligned;
     }
     static Point   _align_to_grid(Point   coord, Point   spacing) 
-        { return Point(_align_to_grid(coord.x, spacing.x), _align_to_grid(coord.y, spacing.y)); }
+        { return Point(_align_to_grid(coord(0), spacing(0)), _align_to_grid(coord(1), spacing(1))); }
     static coord_t _align_to_grid(coord_t coord, coord_t spacing, coord_t base) 
         { return base + _align_to_grid(coord - base, spacing); }
     static Point   _align_to_grid(Point   coord, Point   spacing, Point   base)
-        { return Point(_align_to_grid(coord.x, spacing.x, base.x), _align_to_grid(coord.y, spacing.y, base.y)); }
+        { return Point(_align_to_grid(coord(0), spacing(0), base(0)), _align_to_grid(coord(1), spacing(1), base(1))); }
 };
 
 } // namespace Slic3r
diff --git a/xs/src/libslic3r/Fill/FillConcentric.cpp b/xs/src/libslic3r/Fill/FillConcentric.cpp
index b21ad2799..8a3a7ea89 100644
--- a/xs/src/libslic3r/Fill/FillConcentric.cpp
+++ b/xs/src/libslic3r/Fill/FillConcentric.cpp
@@ -20,8 +20,8 @@ void FillConcentric::_fill_surface_single(
     coord_t distance = coord_t(min_spacing / params.density);
     
     if (params.density > 0.9999f && !params.dont_adjust) {
-        distance = this->_adjust_solid_spacing(bounding_box.size().x, distance);
-        this->spacing = unscale(distance);
+        distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
+        this->spacing = unscale<double>(distance);
     }
 
     Polygons loops = (Polygons)expolygon;
diff --git a/xs/src/libslic3r/Fill/FillGyroid.cpp b/xs/src/libslic3r/Fill/FillGyroid.cpp
index 89d5d231e..d6bf03ce6 100644
--- a/xs/src/libslic3r/Fill/FillGyroid.cpp
+++ b/xs/src/libslic3r/Fill/FillGyroid.cpp
@@ -30,39 +30,39 @@ static inline double f(double x, double z_sin, double z_cos, bool vertical, bool
 }
 
 static inline Polyline make_wave(
-    const std::vector<Pointf>& one_period, double width, double height, double offset, double scaleFactor,
+    const std::vector<Vec2d>& one_period, double width, double height, double offset, double scaleFactor,
     double z_cos, double z_sin, bool vertical)
 {
-    std::vector<Pointf> points = one_period;
-    double period = points.back().x;
+    std::vector<Vec2d> points = one_period;
+    double period = points.back()(0);
     points.pop_back();
     int n = points.size();
     do {
-        points.emplace_back(Pointf(points[points.size()-n].x + period, points[points.size()-n].y));
-    } while (points.back().x < width);
-    points.back().x = width;
+        points.emplace_back(Vec2d(points[points.size()-n](0) + period, points[points.size()-n](1)));
+    } while (points.back()(0) < width);
+    points.back()(0) = width;
 
     // and construct the final polyline to return:
     Polyline polyline;
     for (auto& point : points) {
-        point.y += offset;
-        point.y = clamp(0., height, double(point.y));
+        point(1) += offset;
+        point(1) = clamp(0., height, double(point(1)));
         if (vertical)
-            std::swap(point.x, point.y);
-        polyline.points.emplace_back(convert_to<Point>(point * scaleFactor));
+            std::swap(point(0), point(1));
+        polyline.points.emplace_back((point * scaleFactor).cast<coord_t>());
     }
 
     return polyline;
 }
 
-static std::vector<Pointf> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip)
+static std::vector<Vec2d> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip)
 {
-    std::vector<Pointf> points;
+    std::vector<Vec2d> points;
     double dx = M_PI_4; // very coarse spacing to begin with
     double limit = std::min(2*M_PI, width);
     for (double x = 0.; x < limit + EPSILON; x += dx) {  // so the last point is there too
         x = std::min(x, limit);
-        points.emplace_back(Pointf(x,f(x, z_sin,z_cos, vertical, flip)));
+        points.emplace_back(Vec2d(x,f(x, z_sin,z_cos, vertical, flip)));
     }
 
     // now we will check all internal points and in case some are too far from the line connecting its neighbours,
@@ -71,17 +71,19 @@ static std::vector<Pointf> make_one_period(double width, double scaleFactor, dou
     for (unsigned int i=1;i<points.size()-1;++i) {
         auto& lp = points[i-1]; // left point
         auto& tp = points[i];   // this point
+        Vec2d lrv = tp - lp;
         auto& rp = points[i+1]; // right point
         // calculate distance of the point to the line:
-        double dist_mm = unscale(scaleFactor * std::abs( (rp.y - lp.y)*tp.x + (lp.x - rp.x)*tp.y + (rp.x*lp.y - rp.y*lp.x) ) / std::hypot((rp.y - lp.y),(lp.x - rp.x)));
-
+        double dist_mm = unscale<double>(scaleFactor) * std::abs(cross2(rp, lp) - cross2(rp - lp, tp)) / lrv.norm();
         if (dist_mm > tolerance) {                               // if the difference from straight line is more than this
-            double x = 0.5f * (points[i-1].x + points[i].x);
-            points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip)));
-            x = 0.5f * (points[i+1].x + points[i].x);
-            points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip)));
-            std::sort(points.begin(), points.end());            // we added the points to the end, but need them all in order
-            --i;                                                // decrement i so we also check the first newly added point
+            double x = 0.5f * (points[i-1](0) + points[i](0));
+            points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip)));
+            x = 0.5f * (points[i+1](0) + points[i](0));
+            points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip)));
+            // we added the points to the end, but need them all in order
+            std::sort(points.begin(), points.end(), [](const Vec2d &lhs, const Vec2d &rhs){ return lhs < rhs; });
+            // decrement i so we also check the first newly added point
+            --i;
         }
     }
     return points;
@@ -107,7 +109,7 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double
         std::swap(width,height);
     }
 
-    std::vector<Pointf> one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time
+    std::vector<Vec2d> one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time
     Polylines result;
 
     for (double y0 = lower_bound; y0 < upper_bound+EPSILON; y0 += 2*M_PI)           // creates odd polylines
@@ -143,12 +145,12 @@ void FillGyroid::_fill_surface_single(
         scale_(this->z),
         density_adjusted,
         this->spacing,
-        ceil(bb.size().x / distance) + 1.,
-        ceil(bb.size().y / distance) + 1.);
+        ceil(bb.size()(0) / distance) + 1.,
+        ceil(bb.size()(1) / distance) + 1.);
     
     // move pattern in place
     for (Polyline &polyline : polylines)
-        polyline.translate(bb.min.x, bb.min.y);
+        polyline.translate(bb.min(0), bb.min(1));
 
     // clip pattern to boundaries
     polylines = intersection_pl(polylines, (Polygons)expolygon);
@@ -177,7 +179,7 @@ void FillGyroid::_fill_surface_single(
                 // TODO: we should also check that both points are on a fill_boundary to avoid 
                 // connecting paths on the boundaries of internal regions
                 // TODO: avoid crossing current infill path
-                if (first_point.distance_to(last_point) <= 5 * distance && 
+                if ((last_point - first_point).cast<double>().norm() <= 5 * distance && 
                     expolygon_off.contains(Line(last_point, first_point))) {
                     // Append the polyline.
                     pts_end.insert(pts_end.end(), polyline.points.begin(), polyline.points.end());
diff --git a/xs/src/libslic3r/Fill/FillHoneycomb.cpp b/xs/src/libslic3r/Fill/FillHoneycomb.cpp
index aa0e0f6b0..6f26167a2 100644
--- a/xs/src/libslic3r/Fill/FillHoneycomb.cpp
+++ b/xs/src/libslic3r/Fill/FillHoneycomb.cpp
@@ -50,13 +50,13 @@ void FillHoneycomb::_fill_surface_single(
             bounding_box.merge(_align_to_grid(bounding_box.min, Point(m.hex_width, m.pattern_height)));
         }
 
-        coord_t x = bounding_box.min.x;
-        while (x <= bounding_box.max.x) {
+        coord_t x = bounding_box.min(0);
+        while (x <= bounding_box.max(0)) {
             Polygon p;
             coord_t ax[2] = { x + m.x_offset, x + m.distance - m.x_offset };
             for (size_t i = 0; i < 2; ++ i) {
                 std::reverse(p.points.begin(), p.points.end()); // turn first half upside down
-                for (coord_t y = bounding_box.min.y; y <= bounding_box.max.y; y += m.y_short + m.hex_side + m.y_short + m.hex_side) {
+                for (coord_t y = bounding_box.min(1); y <= bounding_box.max(1); y += m.y_short + m.hex_side + m.y_short + m.hex_side) {
                     p.points.push_back(Point(ax[1], y + m.y_offset));
                     p.points.push_back(Point(ax[0], y + m.y_short - m.y_offset));
                     p.points.push_back(Point(ax[0], y + m.y_short + m.hex_side + m.y_offset));
@@ -101,7 +101,7 @@ void FillHoneycomb::_fill_surface_single(
             for (Polylines::iterator it_path = chained.begin(); it_path != chained.end(); ++ it_path) {
                 if (! paths.empty()) {
                     // distance between first point of this path and last point of last path
-                    double distance = paths.back().last_point().distance_to(it_path->first_point());
+                    double distance = (it_path->first_point() - paths.back().last_point()).cast<double>().norm();
                     if (distance <= m.hex_width) {
                         paths.back().points.insert(paths.back().points.end(), it_path->points.begin(), it_path->points.end());
                         continue;
diff --git a/xs/src/libslic3r/Fill/FillPlanePath.cpp b/xs/src/libslic3r/Fill/FillPlanePath.cpp
index f71ef95a1..615cc6efe 100644
--- a/xs/src/libslic3r/Fill/FillPlanePath.cpp
+++ b/xs/src/libslic3r/Fill/FillPlanePath.cpp
@@ -24,14 +24,14 @@ void FillPlanePath::_fill_surface_single(
     Point shift = this->_centered() ? 
         bounding_box.center() :
         bounding_box.min;
-    expolygon.translate(-shift.x, -shift.y);
-    bounding_box.translate(-shift.x, -shift.y);
+    expolygon.translate(-shift(0), -shift(1));
+    bounding_box.translate(-shift(0), -shift(1));
 
     Pointfs pts = _generate(
-        coord_t(ceil(coordf_t(bounding_box.min.x) / distance_between_lines)),
-        coord_t(ceil(coordf_t(bounding_box.min.y) / distance_between_lines)),
-        coord_t(ceil(coordf_t(bounding_box.max.x) / distance_between_lines)),
-        coord_t(ceil(coordf_t(bounding_box.max.y) / distance_between_lines)));
+        coord_t(ceil(coordf_t(bounding_box.min(0)) / distance_between_lines)),
+        coord_t(ceil(coordf_t(bounding_box.min(1)) / distance_between_lines)),
+        coord_t(ceil(coordf_t(bounding_box.max(0)) / distance_between_lines)),
+        coord_t(ceil(coordf_t(bounding_box.max(1)) / distance_between_lines)));
 
     Polylines polylines;
     if (pts.size() >= 2) {
@@ -41,8 +41,8 @@ void FillPlanePath::_fill_surface_single(
         polyline.points.reserve(pts.size());
         for (Pointfs::iterator it = pts.begin(); it != pts.end(); ++ it)
             polyline.points.push_back(Point(
-                coord_t(floor(it->x * distance_between_lines + 0.5)), 
-                coord_t(floor(it->y * distance_between_lines + 0.5))));
+                coord_t(floor((*it)(0) * distance_between_lines + 0.5)), 
+                coord_t(floor((*it)(1) * distance_between_lines + 0.5))));
 //      intersection(polylines_src, offset((Polygons)expolygon, scale_(0.02)), &polylines);
         polylines = intersection_pl(polylines, to_polygons(expolygon));
 
@@ -62,7 +62,7 @@ void FillPlanePath::_fill_surface_single(
         
         // paths must be repositioned and rotated back
         for (Polylines::iterator it = polylines.begin(); it != polylines.end(); ++ it) {
-            it->translate(shift.x, shift.y);
+            it->translate(shift(0), shift(1));
             it->rotate(direction.first);
         }
     }
@@ -86,12 +86,12 @@ Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t m
     coordf_t r = 1;
     Pointfs out;
     //FIXME Vojtech: If used as a solid infill, there is a gap left at the center.
-    out.push_back(Pointf(0, 0));
-    out.push_back(Pointf(1, 0));
+    out.push_back(Vec2d(0, 0));
+    out.push_back(Vec2d(1, 0));
     while (r < rmax) {
         theta += 1. / r;
         r = a + b * theta;
-        out.push_back(Pointf(r * cos(theta), r * sin(theta)));
+        out.push_back(Vec2d(r * cos(theta), r * sin(theta)));
     }
     return out;
 }
@@ -162,7 +162,7 @@ Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x,
     line.reserve(sz2);
     for (size_t i = 0; i < sz2; ++ i) {
         Point p = hilbert_n_to_xy(i);
-        line.push_back(Pointf(p.x + min_x, p.y + min_y));
+        line.push_back(Vec2d(p(0) + min_x, p(1) + min_y));
     }
     return line;
 }
@@ -175,27 +175,27 @@ Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_
     coordf_t r = 0;
     coordf_t r_inc = sqrt(2.);
     Pointfs out;
-    out.push_back(Pointf(0, 0));
+    out.push_back(Vec2d(0, 0));
     while (r < rmax) {
         r += r_inc;
         coordf_t rx = r / sqrt(2.);
         coordf_t r2 = r + rx;
-        out.push_back(Pointf( r,  0.));
-        out.push_back(Pointf( r2, rx));
-        out.push_back(Pointf( rx, rx));
-        out.push_back(Pointf( rx, r2));
-        out.push_back(Pointf(0.,  r));
-        out.push_back(Pointf(-rx, r2));
-        out.push_back(Pointf(-rx, rx));
-        out.push_back(Pointf(-r2, rx));
-        out.push_back(Pointf(-r,  0.));
-        out.push_back(Pointf(-r2, -rx));
-        out.push_back(Pointf(-rx, -rx));
-        out.push_back(Pointf(-rx, -r2));
-        out.push_back(Pointf(0., -r));
-        out.push_back(Pointf( rx, -r2));
-        out.push_back(Pointf( rx, -rx));
-        out.push_back(Pointf( r2+r_inc, -rx));
+        out.push_back(Vec2d( r,  0.));
+        out.push_back(Vec2d( r2, rx));
+        out.push_back(Vec2d( rx, rx));
+        out.push_back(Vec2d( rx, r2));
+        out.push_back(Vec2d(0.,  r));
+        out.push_back(Vec2d(-rx, r2));
+        out.push_back(Vec2d(-rx, rx));
+        out.push_back(Vec2d(-r2, rx));
+        out.push_back(Vec2d(-r,  0.));
+        out.push_back(Vec2d(-r2, -rx));
+        out.push_back(Vec2d(-rx, -rx));
+        out.push_back(Vec2d(-rx, -r2));
+        out.push_back(Vec2d(0., -r));
+        out.push_back(Vec2d( rx, -r2));
+        out.push_back(Vec2d( rx, -rx));
+        out.push_back(Vec2d( r2+r_inc, -rx));
     }
     return out;
 }
diff --git a/xs/src/libslic3r/Fill/FillRectilinear.cpp b/xs/src/libslic3r/Fill/FillRectilinear.cpp
index 5ba30ba51..205eb1b66 100644
--- a/xs/src/libslic3r/Fill/FillRectilinear.cpp
+++ b/xs/src/libslic3r/Fill/FillRectilinear.cpp
@@ -26,8 +26,8 @@ void FillRectilinear::_fill_surface_single(
     
     // define flow spacing according to requested density
     if (params.density > 0.9999f && !params.dont_adjust) {
-        this->_line_spacing = this->_adjust_solid_spacing(bounding_box.size().x, this->_line_spacing);
-        this->spacing = unscale(this->_line_spacing);
+        this->_line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), this->_line_spacing);
+        this->spacing = unscale<double>(this->_line_spacing);
     } else {
         // extend bounding box so that our pattern will be aligned with other layers
         // Transform the reference point to the rotated coordinate system.
@@ -38,14 +38,14 @@ void FillRectilinear::_fill_surface_single(
     }
 
     // generate the basic pattern
-    coord_t x_max = bounding_box.max.x + SCALED_EPSILON;
+    coord_t x_max = bounding_box.max(0) + SCALED_EPSILON;
     Lines lines;
-    for (coord_t x = bounding_box.min.x; x <= x_max; x += this->_line_spacing)
-        lines.push_back(this->_line(lines.size(), x, bounding_box.min.y, bounding_box.max.y));
+    for (coord_t x = bounding_box.min(0); x <= x_max; x += this->_line_spacing)
+        lines.push_back(this->_line(lines.size(), x, bounding_box.min(1), bounding_box.max(1)));
     if (this->_horizontal_lines()) {
-        coord_t y_max = bounding_box.max.y + SCALED_EPSILON;
-        for (coord_t y = bounding_box.min.y; y <= y_max; y += this->_line_spacing)
-            lines.push_back(Line(Point(bounding_box.min.x, y), Point(bounding_box.max.x, y)));
+        coord_t y_max = bounding_box.max(1) + SCALED_EPSILON;
+        for (coord_t y = bounding_box.min(1); y <= y_max; y += this->_line_spacing)
+            lines.push_back(Line(Point(bounding_box.min(0), y), Point(bounding_box.max(0), y)));
     }
 
     // clip paths against a slightly larger expolygon, so that the first and last paths
@@ -72,10 +72,10 @@ void FillRectilinear::_fill_surface_single(
     for (Polylines::iterator it_polyline = polylines.begin(); it_polyline != polylines.end(); ++ it_polyline) {
         Point *first_point = &it_polyline->points.front();
         Point *last_point  = &it_polyline->points.back();
-        if (first_point->y > last_point->y)
+        if (first_point->y() > last_point->y())
             std::swap(first_point, last_point);
-        first_point->y -= extra;
-        last_point->y += extra;
+        first_point->y() -= extra;
+        last_point->y() += extra;
     }
 
     size_t n_polylines_out_old = polylines_out.size();
@@ -103,10 +103,10 @@ void FillRectilinear::_fill_surface_single(
                 const Point &first_point = it_polyline->points.front();
                 const Point &last_point = pts_end.back();
                 // Distance in X, Y.
-                const Vector distance = first_point.vector_to(last_point);
+                const Vector distance = last_point - first_point;
                 // TODO: we should also check that both points are on a fill_boundary to avoid 
                 // connecting paths on the boundaries of internal regions
-                if (this->_can_connect(std::abs(distance.x), std::abs(distance.y)) && 
+                if (this->_can_connect(std::abs(distance(0)), std::abs(distance(1))) && 
                     expolygon_off.contains(Line(last_point, first_point))) {
                     // Append the polyline.
                     pts_end.insert(pts_end.end(), it_polyline->points.begin(), it_polyline->points.end());
@@ -122,7 +122,7 @@ void FillRectilinear::_fill_surface_single(
     // paths must be rotated back
     for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_old; it != polylines_out.end(); ++ it) {
         // No need to translate, the absolute position is irrelevant.
-        // it->translate(- direction.second.x, - direction.second.y);
+        // it->translate(- direction.second(0), - direction.second(1));
         it->rotate(direction.first);
     }
 }
diff --git a/xs/src/libslic3r/Fill/FillRectilinear2.cpp b/xs/src/libslic3r/Fill/FillRectilinear2.cpp
index ddd785101..65440d0ef 100644
--- a/xs/src/libslic3r/Fill/FillRectilinear2.cpp
+++ b/xs/src/libslic3r/Fill/FillRectilinear2.cpp
@@ -42,12 +42,12 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po
         Point  px  = (i == 0) ? p1   : p2;
         Point  pa  = poly.points[((seg == 0) ? poly.points.size() : seg) - 1];
         Point  pb  = poly.points[seg];
-        if (pa.x > pb.x)
-            std::swap(pa.x, pb.x);
-        if (pa.y > pb.y)
-            std::swap(pa.y, pb.y);
-        assert(px.x >= pa.x && px.x <= pb.x);
-        assert(px.y >= pa.y && px.y <= pb.y);
+        if (pa(0) > pb(0))
+            std::swap(pa(0), pb(0));
+        if (pa(1) > pb(1))
+            std::swap(pa(1), pb(1));
+        assert(px(0) >= pa(0) && px(0) <= pb(0));
+        assert(px(1) >= pa(1) && px(1) <= pb(1));
     }
 #endif /* SLIC3R_DEBUG */
     const Point *pPrev = &p1;
@@ -55,14 +55,14 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po
     coordf_t len = 0;
     if (seg1 <= seg2) {
         for (size_t i = seg1; i < seg2; ++ i, pPrev = pThis)
-           len += pPrev->distance_to(*(pThis = &poly.points[i]));
+           len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm();
     } else {
         for (size_t i = seg1; i < poly.points.size(); ++ i, pPrev = pThis)
-           len += pPrev->distance_to(*(pThis = &poly.points[i]));
+           len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm();
         for (size_t i = 0; i < seg2; ++ i, pPrev = pThis)
-           len += pPrev->distance_to(*(pThis = &poly.points[i]));
+           len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm();
     }
-    len += pPrev->distance_to(p2);
+    len += (*pPrev - p2).cast<double>().norm();
     return len;
 }
 
@@ -791,15 +791,15 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
 
     // define flow spacing according to requested density
     if (params.full_infill() && !params.dont_adjust) {
-        line_spacing = this->_adjust_solid_spacing(bounding_box.size().x, line_spacing);
-        this->spacing = unscale(line_spacing);
+        line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
+        this->spacing = unscale<double>(line_spacing);
     } else {
         // extend bounding box so that our pattern will be aligned with other layers
         // Transform the reference point to the rotated coordinate system.
         Point refpt = rotate_vector.second.rotated(- rotate_vector.first);
         // _align_to_grid will not work correctly with positive pattern_shift.
         coord_t pattern_shift_scaled = coord_t(scale_(pattern_shift)) % line_spacing;
-        refpt.x -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
+        refpt(0) -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
         bounding_box.merge(_align_to_grid(
             bounding_box.min, 
             Point(line_spacing, line_spacing), 
@@ -808,8 +808,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
 
     // Intersect a set of euqally spaced vertical lines wiht expolygon.
     // n_vlines = ceil(bbox_width / line_spacing)
-    size_t  n_vlines = (bounding_box.max.x - bounding_box.min.x + line_spacing - 1) / line_spacing;
-	coord_t x0 = bounding_box.min.x;
+    size_t  n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing;
+	coord_t x0 = bounding_box.min(0);
 	if (params.full_infill())
 		x0 += (line_spacing + SCALED_EPSILON) / 2;
 
@@ -842,8 +842,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
             const Point &p1 = contour[iPrev];
             const Point &p2 = contour[iSegment];
             // Which of the equally spaced vertical lines is intersected by this segment?
-            coord_t l = p1.x;
-            coord_t r = p2.x;
+            coord_t l = p1(0);
+            coord_t r = p2(0);
             if (l > r)
                 std::swap(l, r);
             // il, ir are the left / right indices of vertical lines intersecting a segment
@@ -869,33 +869,33 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
                 assert(l <= this_x);
                 assert(r >= this_x);
                 // Calculate the intersection position in y axis. x is known.
-                if (p1.x == this_x) {
-                    if (p2.x == this_x) {
+                if (p1(0) == this_x) {
+                    if (p2(0) == this_x) {
                         // Ignore strictly vertical segments.
                         continue;
                     }
-                    is.pos_p = p1.y;
+                    is.pos_p = p1(1);
                     is.pos_q = 1;
-                } else if (p2.x == this_x) {
-                    is.pos_p = p2.y;
+                } else if (p2(0) == this_x) {
+                    is.pos_p = p2(1);
                     is.pos_q = 1;
                 } else {
                     // First calculate the intersection parameter 't' as a rational number with non negative denominator.
-                    if (p2.x > p1.x) {
-                        is.pos_p = this_x - p1.x;
-                        is.pos_q = p2.x - p1.x;
+                    if (p2(0) > p1(0)) {
+                        is.pos_p = this_x - p1(0);
+                        is.pos_q = p2(0) - p1(0);
                     } else {
-                        is.pos_p = p1.x - this_x;
-                        is.pos_q = p1.x - p2.x;
+                        is.pos_p = p1(0) - this_x;
+                        is.pos_q = p1(0) - p2(0);
                     }
                     assert(is.pos_p >= 0 && is.pos_p <= is.pos_q);
                     // Make an intersection point from the 't'.
-                    is.pos_p *= int64_t(p2.y - p1.y);
-                    is.pos_p += p1.y * int64_t(is.pos_q);
+                    is.pos_p *= int64_t(p2(1) - p1(1));
+                    is.pos_p += p1(1) * int64_t(is.pos_q);
                 }
                 // +-1 to take rounding into account.
-                assert(is.pos() + 1 >= std::min(p1.y, p2.y));
-                assert(is.pos() <= std::max(p1.y, p2.y) + 1);
+                assert(is.pos() + 1 >= std::min(p1(1), p2(1)));
+                assert(is.pos() <= std::max(p1(1), p2(1)) + 1);
                 segs[i].intersections.push_back(is);
             }
         }
@@ -919,7 +919,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
             const Points &contour = poly_with_offset.contour(iContour).points;
             size_t iSegment = sil.intersections[i].iSegment;
             size_t iPrev    = ((iSegment == 0) ? contour.size() : iSegment) - 1;
-            coord_t dir = contour[iSegment].x - contour[iPrev].x;
+            coord_t dir = contour[iSegment](0) - contour[iPrev](0);
             bool low = dir > 0;
             sil.intersections[i].type = poly_with_offset.is_contour_outer(iContour) ? 
                 (low ? SegmentIntersection::OUTER_LOW : SegmentIntersection::OUTER_HIGH) :
@@ -1066,7 +1066,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
                                 intrsctn.consumed_vertical_up : 
                                 seg.intersections[i-1].consumed_vertical_up;
                             if (! consumed) {
-                                coordf_t dist2 = sqr(coordf_t(pointLast.x - seg.pos)) + sqr(coordf_t(pointLast.y - intrsctn.pos()));
+                                coordf_t dist2 = sqr(coordf_t(pointLast(0) - seg.pos)) + sqr(coordf_t(pointLast(1) - intrsctn.pos()));
                                 if (dist2 < dist2min) {
                                     dist2min = dist2;
                                     i_vline = i_vline2;
@@ -1356,8 +1356,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
         // Handle nearly zero length edges.
         if (polyline_current->points.size() <= 1 ||
         	(polyline_current->points.size() == 2 &&
-        		std::abs(polyline_current->points.front().x - polyline_current->points.back().x) < SCALED_EPSILON &&
-				std::abs(polyline_current->points.front().y - polyline_current->points.back().y) < SCALED_EPSILON))
+        		std::abs(polyline_current->points.front()(0) - polyline_current->points.back()(0)) < SCALED_EPSILON &&
+				std::abs(polyline_current->points.front()(1) - polyline_current->points.back()(1)) < SCALED_EPSILON))
             polylines_out.pop_back();
         intrsctn = NULL;
         i_intersection = -1;
@@ -1383,7 +1383,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
     // paths must be rotated back
     for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) {
         // No need to translate, the absolute position is irrelevant.
-        // it->translate(- rotate_vector.second.x, - rotate_vector.second.y);
+        // it->translate(- rotate_vector.second(0), - rotate_vector.second(1));
         assert(! it->has_duplicate_points());
         it->rotate(rotate_vector.first);
         //FIXME rather simplify the paths to avoid very short edges?
diff --git a/xs/src/libslic3r/Fill/FillRectilinear3.cpp b/xs/src/libslic3r/Fill/FillRectilinear3.cpp
index cccea3030..8fc129eac 100644
--- a/xs/src/libslic3r/Fill/FillRectilinear3.cpp
+++ b/xs/src/libslic3r/Fill/FillRectilinear3.cpp
@@ -217,30 +217,30 @@ Point SegmentIntersection::pos() const
     const Point   &seg_start = poly.points[(this->iSegment == 0) ? poly.points.size() - 1 : this->iSegment - 1];
     const Point   &seg_end   = poly.points[this->iSegment];
     // Point, vector of the segment.
-    const Pointf   p1  = convert_to<Pointf>(seg_start);
-    const Pointf   v1  = convert_to<Pointf>(seg_end - seg_start);
+    const Vec2d   p1(seg_start.cast<coordf_t>());
+    const Vec2d   v1((seg_end - seg_start).cast<coordf_t>());
     // Point, vector of this hatching line.
-    const Pointf   p2  = convert_to<Pointf>(line->pos);
-    const Pointf   v2  = convert_to<Pointf>(line->dir);
+    const Vec2d   p2(line->pos.cast<coordf_t>());
+    const Vec2d   v2(line->dir.cast<coordf_t>());
     // Intersect the two rays.
-    double denom = v1.x * v2.y - v2.x * v1.y;
+    double denom = v1(0) * v2(1) - v2(0) * v1(1);
     Point out;
     if (denom == 0.) {
         // Lines are collinear. As the pos() method is not supposed to be called on collinear vectors,
         // the source vectors are not quite collinear. Return the center of the contour segment.
         out = seg_start + seg_end;
-        out.x >>= 1;
-        out.y >>= 1;
+        out(0) >>= 1;
+        out(1) >>= 1;
     } else {
         // Find the intersection point.
-        double t = (v2.x * (p1.y - p2.y) - v2.y * (p1.x - p2.x)) / denom;
+        double t = (v2(0) * (p1(1) - p2(1)) - v2(1) * (p1(0) - p2(0))) / denom;
         if (t < 0.)
             out = seg_start;
         else if (t > 1.)
             out = seg_end;
         else {
-            out.x = coord_t(floor(p1.x + t * v1.x + 0.5));
-            out.y = coord_t(floor(p1.y + t * v1.y + 0.5));
+            out(0) = coord_t(floor(p1(0) + t * v1(0) + 0.5));
+            out(1) = coord_t(floor(p1(1) + t * v1(1) + 0.5));
         }
     }
     return out;
@@ -276,13 +276,13 @@ int SegmentIntersection::ordering_along_line(const SegmentIntersection &other) c
             // other.iSegment succeeds this->iSegment
 			assert(seg_end_a == seg_start_b);
 			// Avoid calling the 128bit x 128bit multiplication below if this->line intersects the common point.
-			if (cross(this->line->dir, seg_end_b - this->line->pos) == 0)
+			if (cross2(Vec2i64(this->line->dir.cast<int64_t>()), (seg_end_b - this->line->pos).cast<int64_t>()) == 0)
 				return 0;
         } else if ((other.iSegment + 1) % poly_a.points.size() == this->iSegment) {
             // this->iSegment succeeds other.iSegment
 			assert(seg_start_a == seg_end_b);
 			// Avoid calling the 128bit x 128bit multiplication below if this->line intersects the common point.
-			if (cross(this->line->dir, seg_start_a - this->line->pos) == 0)
+			if (cross2(Vec2i64(this->line->dir.cast<int64_t>()), (seg_start_a - this->line->pos).cast<int64_t>()) == 0)
 				return 0;
         } else {
             // General case.
@@ -290,35 +290,35 @@ int SegmentIntersection::ordering_along_line(const SegmentIntersection &other) c
     }
 
     // First test, whether both points of one segment are completely in one half-plane of the other line.
-    const Point vec_b = seg_end_b - seg_start_b;
-    int side_start = signum(cross(vec_b, seg_start_a - seg_start_b));
-    int side_end   = signum(cross(vec_b, seg_end_a   - seg_start_b));
+    const Vec2i64 vec_b = (seg_end_b - seg_start_b).cast<int64_t>();
+    int side_start = signum(cross2(vec_b, (seg_start_a - seg_start_b).cast<int64_t>()));
+    int side_end   = signum(cross2(vec_b, (seg_end_a   - seg_start_b).cast<int64_t>()));
     int side       = side_start * side_end;
     if (side > 0)
         // This segment is completely inside one half-plane of the other line, therefore the ordering is trivial.
-        return signum(cross(vec_b, this->line->dir)) * side_start;
+        return signum(cross2(vec_b, this->line->dir.cast<int64_t>())) * side_start;
 
-    const Point vec_a = seg_end_a - seg_start_a;
-    int side_start2 = signum(cross(vec_a, seg_start_b - seg_start_a));
-    int side_end2   = signum(cross(vec_a, seg_end_b   - seg_start_a));
+    const Vec2i64 vec_a = (seg_end_a - seg_start_a).cast<int64_t>();
+    int side_start2 = signum(cross2(vec_a, (seg_start_b - seg_start_a).cast<int64_t>()));
+    int side_end2   = signum(cross2(vec_a, (seg_end_b   - seg_start_a).cast<int64_t>()));
     int side2       = side_start2 * side_end2;
     //if (side == 0 && side2 == 0)
         // The segments share one of their end points.
     if (side2 > 0)
         // This segment is completely inside one half-plane of the other line, therefore the ordering is trivial.
-        return signum(cross(this->line->dir, vec_a)) * side_start2;
+        return signum(cross2(this->line->dir.cast<int64_t>(), vec_a)) * side_start2;
 
     // The two segments intersect and they are not sucessive segments of the same contour.
     // Ordering of the points depends on the position of the segment intersection (left / right from this->line),
     // therefore a simple test over the input segment end points is not sufficient.
 
     // Find the parameters of intersection of the two segmetns with this->line.
-	int64_t denom1 = cross(this->line->dir, vec_a);
-	int64_t denom2 = cross(this->line->dir, vec_b);
-	Point   vx_a   = seg_start_a - this->line->pos;
-	Point   vx_b   = seg_start_b - this->line->pos;
-	int64_t t1_times_denom1 = int64_t(vx_a.x) * int64_t(vec_a.y) - int64_t(vx_a.y) * int64_t(vec_a.x);
-	int64_t t2_times_denom2 = int64_t(vx_b.x) * int64_t(vec_b.y) - int64_t(vx_b.y) * int64_t(vec_b.x);
+	int64_t denom1 = cross2(this->line->dir.cast<int64_t>(), vec_a);
+	int64_t denom2 = cross2(this->line->dir.cast<int64_t>(), vec_b);
+	Vec2i64 vx_a   = (seg_start_a - this->line->pos).cast<int64_t>();
+	Vec2i64 vx_b   = (seg_start_b - this->line->pos).cast<int64_t>();
+	int64_t t1_times_denom1 = vx_a(0) * vec_a(1) - vx_a(1) * vec_a(0);
+	int64_t t2_times_denom2 = vx_b(0) * vec_b(1) - vx_b(1) * vec_b(0);
 	assert(denom1 != 0);
     assert(denom2 != 0);
     return Int128::compare_rationals_filtered(t1_times_denom1, denom1, t2_times_denom2, denom2);
@@ -330,7 +330,7 @@ bool SegmentIntersection::operator<(const SegmentIntersection &other) const
 #ifdef _DEBUG
     Point p1 = this->pos();
     Point p2 = other.pos();
-    int64_t d = dot(this->line->dir, p2 - p1);
+    int64_t d = this->line->dir.cast<int64_t>().dot((p2 - p1).cast<int64_t>());
 #endif /* _DEBUG */
     int   ordering = this->ordering_along_line(other);
 #ifdef _DEBUG
@@ -389,16 +389,16 @@ static bool prepare_infill_hatching_segments(
     // Define the flow spacing according to requested density.
     if (params.full_infill() && ! params.dont_adjust) {
         // Full infill, adjust the line spacing to fit an integer number of lines.
-        out.line_spacing = Fill::_adjust_solid_spacing(bounding_box.size().x, line_spacing);
+        out.line_spacing = Fill::_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
         // Report back the adjusted line spacing.
-        fill_dir_params.spacing = float(unscale(line_spacing));
+        fill_dir_params.spacing = unscale<double>(line_spacing);
     } else {
         // Extend bounding box so that our pattern will be aligned with the other layers.
         // Transform the reference point to the rotated coordinate system.
         Point refpt = rotate_vector.second.rotated(- out.angle);
         // _align_to_grid will not work correctly with positive pattern_shift.
         coord_t pattern_shift_scaled = coord_t(scale_(fill_dir_params.pattern_shift)) % line_spacing;
-        refpt.x -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
+        refpt(0) -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
         bounding_box.merge(Fill::_align_to_grid(
             bounding_box.min, 
             Point(line_spacing, line_spacing), 
@@ -407,13 +407,13 @@ static bool prepare_infill_hatching_segments(
 
     // Intersect a set of euqally spaced vertical lines wiht expolygon.
     // n_vlines = ceil(bbox_width / line_spacing)
-    size_t  n_vlines = (bounding_box.max.x - bounding_box.min.x + line_spacing - 1) / line_spacing;
-    coord_t x0 = bounding_box.min.x;
+    size_t  n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing;
+    coord_t x0 = bounding_box.min(0);
     if (params.full_infill())
         x0 += coord_t((line_spacing + SCALED_EPSILON) / 2);
 
     out.line_spacing = line_spacing;
-    out.start_point = Point(x0, bounding_box.min.y);
+    out.start_point = Point(x0, bounding_box.min(1));
     out.start_point.rotate(out.angle);
 
 #ifdef SLIC3R_DEBUG
@@ -436,10 +436,10 @@ static bool prepare_infill_hatching_segments(
     for (size_t i = 0; i < n_vlines; ++ i) {
         auto &seg = out.segs[i];
         seg.idx = i;
-        // seg.x   = x0 + coord_t(i) * line_spacing;
+        // seg(0)   = x0 + coord_t(i) * line_spacing;
         coord_t x = x0 + coord_t(i) * line_spacing;
-        seg.pos.x = coord_t(floor(cos_a * x                  - sin_a * bounding_box.min.y + 0.5));
-        seg.pos.y = coord_t(floor(cos_a * bounding_box.min.y + sin_a * x                  + 0.5));
+        seg.pos(0) = coord_t(floor(cos_a * x                  - sin_a * bounding_box.min(1) + 0.5));
+        seg.pos(1) = coord_t(floor(cos_a * bounding_box.min(1) + sin_a * x                  + 0.5));
         seg.dir = out.direction;
     }
 
@@ -454,7 +454,7 @@ static bool prepare_infill_hatching_segments(
             const Point *pr = &contour[iSegment];
             // Orient the segment to the direction vector.
             const Point  v  = *pr - *pl;
-            int   orientation = Int128::sign_determinant_2x2_filtered(v.x, v.y, out.direction.x, out.direction.y);
+            int   orientation = Int128::sign_determinant_2x2_filtered(v(0), v(1), out.direction(0), out.direction(1));
             if (orientation == 0)
                 // Ignore strictly vertical segments.
                 continue;
@@ -462,8 +462,8 @@ static bool prepare_infill_hatching_segments(
                 // Always orient the input segment consistently towards the hatching direction.
                 std::swap(pl, pr);
             // Which of the equally spaced vertical lines is intersected by this segment?
-            coord_t l = (coord_t)floor(cos_a * pl->x + sin_a * pl->y - SCALED_EPSILON);
-            coord_t r = (coord_t)ceil (cos_a * pr->x + sin_a * pr->y + SCALED_EPSILON);
+            coord_t l = (coord_t)floor(cos_a * (*pl)(0) + sin_a * (*pl)(1) - SCALED_EPSILON);
+            coord_t r = (coord_t)ceil (cos_a * (*pr)(0) + sin_a * (*pr)(1) + SCALED_EPSILON);
 			assert(l < r - SCALED_EPSILON);
             // il, ir are the left / right indices of vertical lines intersecting a segment
             int il = std::max<int>(0, (l - x0 + line_spacing) / line_spacing);
@@ -479,9 +479,9 @@ static bool prepare_infill_hatching_segments(
             // 2) all lines from il to ir intersect <pl, pr>.
             assert(il >= 0 && ir < int(out.segs.size()));
             for (int i = il; i <= ir; ++ i) {
-                // assert(out.segs[i].x == i * line_spacing + x0);
-                // assert(l <= out.segs[i].x);
-                // assert(r >= out.segs[i].x);
+                // assert(out.segs[i](0) == i * line_spacing + x0);
+                // assert(l <= out.segs[i](0));
+                // assert(r >= out.segs[i](0));
                 SegmentIntersection is;
                 is.line     = &out.segs[i];
                 is.expoly_with_offset = &poly_with_offset;
@@ -491,10 +491,10 @@ static bool prepare_infill_hatching_segments(
                 // +-1 to take rounding into account.
                 assert(int128::orient(out.segs[i].pos, out.segs[i].pos + out.direction, *pl) >= 0);
                 assert(int128::orient(out.segs[i].pos, out.segs[i].pos + out.direction, *pr) <= 0);
-                assert(is.pos().x + 1 >= std::min(pl->x, pr->x));
-                assert(is.pos().y + 1 >= std::min(pl->y, pr->y));
-                assert(is.pos().x     <= std::max(pl->x, pr->x) + 1);
-                assert(is.pos().y     <= std::max(pl->y, pr->y) + 1);
+                assert(is.pos()(0) + 1 >= std::min((*pl)(0), (*pr)(0)));
+                assert(is.pos()(1) + 1 >= std::min((*pl)(1), (*pr)(1)));
+                assert(is.pos()(0)     <= std::max((*pl)(0), (*pr)(0)) + 1);
+                assert(is.pos()(1)     <= std::max((*pl)(1), (*pr)(1)) + 1);
                 out.segs[i].intersections.push_back(is);
             }
         }
@@ -510,7 +510,7 @@ static bool prepare_infill_hatching_segments(
         for (size_t i = 1; i < sil.intersections.size(); ++ i) {
             Point p1 = sil.intersections[i - 1].pos();
             Point p2 = sil.intersections[i].pos();
-            int64_t d = dot(sil.dir, p2 - p1);
+            int64_t d = sil.dir.cast<int64_t>().dot((p2 - p1).cast<int64_t>());
             assert(d >= - int64_t(SCALED_EPSILON));
         }
 #endif /* _DEBUG */
@@ -659,12 +659,12 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po
         Point  px  = (i == 0) ? p1   : p2;
         Point  pa  = poly.points[((seg == 0) ? poly.points.size() : seg) - 1];
         Point  pb  = poly.points[seg];
-        if (pa.x > pb.x)
-            std::swap(pa.x, pb.x);
-        if (pa.y > pb.y)
-            std::swap(pa.y, pb.y);
-        assert(px.x >= pa.x && px.x <= pb.x);
-        assert(px.y >= pa.y && px.y <= pb.y);
+        if (pa(0) > pb(0))
+            std::swap(pa(0), pb(0));
+        if (pa(1) > pb(1))
+            std::swap(pa(1), pb(1));
+        assert(px(0) >= pa(0) && px(0) <= pb(0));
+        assert(px(1) >= pa(1) && px(1) <= pb(1));
     }
 #endif /* SLIC3R_DEBUG */
     const Point *pPrev = &p1;
@@ -672,14 +672,14 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po
     coordf_t len = 0;
     if (seg1 <= seg2) {
         for (size_t i = seg1; i < seg2; ++ i, pPrev = pThis)
-           len += pPrev->distance_to(*(pThis = &poly.points[i]));
+           len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm();
     } else {
         for (size_t i = seg1; i < poly.points.size(); ++ i, pPrev = pThis)
-           len += pPrev->distance_to(*(pThis = &poly.points[i]));
+           len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm();
         for (size_t i = 0; i < seg2; ++ i, pPrev = pThis)
-           len += pPrev->distance_to(*(pThis = &poly.points[i]));
+           len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm();
     }
-    len += pPrev->distance_to(p2);
+    len += (*pPrev - p2).cast<double>().norm();
     return len;
 }
 
@@ -1191,7 +1191,7 @@ static bool fill_hatching_segments_legacy(
                                 intrsctn.consumed_vertical_up : 
                                 seg.intersections[i-1].consumed_vertical_up;
                             if (! consumed) {
-                                coordf_t dist2 = pointLast.distance_to(intrsctn.pos());
+                                coordf_t dist2 = (intrsctn.pos() - pointLast).cast<double>().norm();
                                 if (dist2 < dist2min) {
                                     dist2min = dist2;
                                     i_vline = i_vline2;
@@ -1481,8 +1481,8 @@ static bool fill_hatching_segments_legacy(
         // Handle nearly zero length edges.
         if (polyline_current->points.size() <= 1 ||
             (polyline_current->points.size() == 2 &&
-                std::abs(polyline_current->points.front().x - polyline_current->points.back().x) < SCALED_EPSILON &&
-                std::abs(polyline_current->points.front().y - polyline_current->points.back().y) < SCALED_EPSILON))
+                std::abs(polyline_current->points.front()(0) - polyline_current->points.back()(0)) < SCALED_EPSILON &&
+                std::abs(polyline_current->points.front()(1) - polyline_current->points.back()(1)) < SCALED_EPSILON))
             polylines_out.pop_back();
         intrsctn = NULL;
         i_intersection = -1;
@@ -1510,7 +1510,7 @@ static bool fill_hatching_segments_legacy(
     // paths must be rotated back
     for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) {
         // No need to translate, the absolute position is irrelevant.
-        // it->translate(- rotate_vector.second.x, - rotate_vector.second.y);
+        // it->translate(- rotate_vector.second(0), - rotate_vector.second(1));
         assert(! it->has_duplicate_points());
         //it->rotate(rotate_vector.first);
         //FIXME rather simplify the paths to avoid very short edges?
diff --git a/xs/src/libslic3r/Format/3mf.cpp b/xs/src/libslic3r/Format/3mf.cpp
index 5de1d26c5..d05460408 100644
--- a/xs/src/libslic3r/Format/3mf.cpp
+++ b/xs/src/libslic3r/Format/3mf.cpp
@@ -1352,8 +1352,8 @@ namespace Slic3r {
         double angle_z = (rotation.axis() == Eigen::Vector3d::UnitZ()) ? rotation.angle() : -rotation.angle();
 #endif 
 
-        instance.offset.x = offset_x;
-        instance.offset.y = offset_y;
+        instance.offset(0) = offset_x;
+        instance.offset(1) = offset_y;
         instance.scaling_factor = sx;
         instance.rotation = angle_z;
     }
@@ -1485,7 +1485,7 @@ namespace Slic3r {
                 stl_facet& facet = stl.facet_start[i];
                 for (unsigned int v = 0; v < 3; ++v)
                 {
-                    ::memcpy((void*)&facet.vertex[v].x, (const void*)&geometry.vertices[geometry.triangles[src_start_id + ii + v] * 3], 3 * sizeof(float));
+                    ::memcpy(facet.vertex[v].data(), (const void*)&geometry.vertices[geometry.triangles[src_start_id + ii + v] * 3], 3 * sizeof(float));
                 }
             }
 
@@ -1802,7 +1802,7 @@ namespace Slic3r {
             }
 
             Eigen::Affine3f transform;
-            transform = Eigen::Translation3f((float)instance->offset.x, (float)instance->offset.y, 0.0f) * Eigen::AngleAxisf((float)instance->rotation, Eigen::Vector3f::UnitZ()) * Eigen::Scaling((float)instance->scaling_factor);
+            transform = Eigen::Translation3f((float)instance->offset(0), (float)instance->offset(1), 0.0f) * Eigen::AngleAxisf((float)instance->rotation, Eigen::Vector3f::UnitZ()) * Eigen::Scaling((float)instance->scaling_factor);
             build_items.emplace_back(instance_id, transform.matrix());
 
             stream << "  </" << OBJECT_TAG << ">\n";
@@ -1845,9 +1845,9 @@ namespace Slic3r {
             for (int i = 0; i < stl.stats.shared_vertices; ++i)
             {
                 stream << "     <" << VERTEX_TAG << " ";
-                stream << "x=\"" << stl.v_shared[i].x << "\" ";
-                stream << "y=\"" << stl.v_shared[i].y << "\" ";
-                stream << "z=\"" << stl.v_shared[i].z << "\" />\n";
+                stream << "x=\"" << stl.v_shared[i](0) << "\" ";
+                stream << "y=\"" << stl.v_shared[i](1) << "\" ";
+                stream << "z=\"" << stl.v_shared[i](2) << "\" />\n";
             }
         }
 
diff --git a/xs/src/libslic3r/Format/AMF.cpp b/xs/src/libslic3r/Format/AMF.cpp
index 886bbae97..81617ad72 100644
--- a/xs/src/libslic3r/Format/AMF.cpp
+++ b/xs/src/libslic3r/Format/AMF.cpp
@@ -402,7 +402,7 @@ void AMFParserContext::endElement(const char * /* name */)
         for (size_t i = 0; i < m_volume_facets.size();) {
             stl_facet &facet = stl.facet_start[i/3];
             for (unsigned int v = 0; v < 3; ++ v)
-                memcpy(&facet.vertex[v].x, &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float));
+                memcpy(facet.vertex[v].data(), &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float));
         }
         stl_get_size(&stl);
         m_volume->mesh.repair();
@@ -498,8 +498,8 @@ void AMFParserContext::endDocument()
         for (const Instance &instance : object.second.instances)
             if (instance.deltax_set && instance.deltay_set) {
                 ModelInstance *mi = m_model.objects[object.second.idx]->add_instance();
-                mi->offset.x = instance.deltax;
-                mi->offset.y = instance.deltay;
+                mi->offset(0) = instance.deltax;
+                mi->offset(1) = instance.deltay;
                 mi->rotation = instance.rz_set ? instance.rz : 0.f;
                 mi->scaling_factor = instance.scale_set ? instance.scale : 1.f;
             }
@@ -761,9 +761,9 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
             for (size_t i = 0; i < stl.stats.shared_vertices; ++ i) {
                 stream << "         <vertex>\n";
                 stream << "           <coordinates>\n";
-                stream << "             <x>" << stl.v_shared[i].x << "</x>\n";
-                stream << "             <y>" << stl.v_shared[i].y << "</y>\n";
-                stream << "             <z>" << stl.v_shared[i].z << "</z>\n";
+                stream << "             <x>" << stl.v_shared[i](0) << "</x>\n";
+                stream << "             <y>" << stl.v_shared[i](1) << "</y>\n";
+                stream << "             <z>" << stl.v_shared[i](2) << "</z>\n";
                 stream << "           </coordinates>\n";
                 stream << "         </vertex>\n";
             }
@@ -804,8 +804,8 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
                     "      <scale>%lf</scale>\n"
                     "    </instance>\n",
                     object_id,
-                    instance->offset.x,
-                    instance->offset.y,
+                    instance->offset(0),
+                    instance->offset(1),
                     instance->rotation,
                     instance->scaling_factor);
                 //FIXME missing instance->scaling_factor
diff --git a/xs/src/libslic3r/Format/OBJ.cpp b/xs/src/libslic3r/Format/OBJ.cpp
index ea6b5604c..ee5756083 100644
--- a/xs/src/libslic3r/Format/OBJ.cpp
+++ b/xs/src/libslic3r/Format/OBJ.cpp
@@ -57,14 +57,14 @@ bool load_obj(const char *path, Model *model, const char *object_name_in)
             continue;
         stl_facet &facet = stl.facet_start[i_face ++];
         size_t     num_normals = 0;
-        stl_normal normal = { 0.f };
+        stl_normal normal(stl_normal::Zero());
         for (unsigned int v = 0; v < 3; ++ v) {
             const ObjParser::ObjVertex &vertex = data.vertices[i++];
-            memcpy(&facet.vertex[v].x, &data.coordinates[vertex.coordIdx*4], 3 * sizeof(float));
+            memcpy(facet.vertex[v].data(), &data.coordinates[vertex.coordIdx*4], 3 * sizeof(float));
             if (vertex.normalIdx != -1) {
-                normal.x += data.normals[vertex.normalIdx*3];
-                normal.y += data.normals[vertex.normalIdx*3+1];
-                normal.z += data.normals[vertex.normalIdx*3+2];
+                normal(0) += data.normals[vertex.normalIdx*3];
+                normal(1) += data.normals[vertex.normalIdx*3+1];
+                normal(2) += data.normals[vertex.normalIdx*3+2];
                 ++ num_normals;
             }
         }
@@ -74,33 +74,27 @@ bool load_obj(const char *path, Model *model, const char *object_name_in)
             facet2.vertex[0] = facet.vertex[0];
             facet2.vertex[1] = facet.vertex[2];
 			const ObjParser::ObjVertex &vertex = data.vertices[i++];
-			memcpy(&facet2.vertex[2].x, &data.coordinates[vertex.coordIdx * 4], 3 * sizeof(float));
+			memcpy(facet2.vertex[2].data(), &data.coordinates[vertex.coordIdx * 4], 3 * sizeof(float));
 			if (vertex.normalIdx != -1) {
-                normal.x += data.normals[vertex.normalIdx*3];
-                normal.y += data.normals[vertex.normalIdx*3+1];
-                normal.z += data.normals[vertex.normalIdx*3+2];
+                normal(0) += data.normals[vertex.normalIdx*3];
+                normal(1) += data.normals[vertex.normalIdx*3+1];
+                normal(2) += data.normals[vertex.normalIdx*3+2];
                 ++ num_normals;
             }
             if (num_normals == 4) {
                 // Normalize an average normal of a quad.
-                float len = sqrt(facet.normal.x*facet.normal.x + facet.normal.y*facet.normal.y + facet.normal.z*facet.normal.z);
+                float len = facet.normal.norm();
                 if (len > EPSILON) {
-                    normal.x /= len;
-                    normal.y /= len;
-                    normal.z /= len;
+                    normal /= len;
                     facet.normal = normal;
                     facet2.normal = normal;
                 }
             }
         } else if (num_normals == 3) {
             // Normalize an average normal of a triangle.
-            float len = sqrt(facet.normal.x*facet.normal.x + facet.normal.y*facet.normal.y + facet.normal.z*facet.normal.z);
-            if (len > EPSILON) {
-                normal.x /= len;
-                normal.y /= len;
-                normal.z /= len;
-                facet.normal = normal;
-            }
+            float len = facet.normal.norm();
+            if (len > EPSILON)
+                facet.normal = normal / len;
         }
 	}
     stl_get_size(&stl);
diff --git a/xs/src/libslic3r/Format/PRUS.cpp b/xs/src/libslic3r/Format/PRUS.cpp
index 1809eaead..3cf3fc075 100644
--- a/xs/src/libslic3r/Format/PRUS.cpp
+++ b/xs/src/libslic3r/Format/PRUS.cpp
@@ -166,7 +166,7 @@ bool load_prus(const char *path, Model *model)
             float  trafo[3][4] = { 0 };
             double instance_rotation = 0.;
             double instance_scaling_factor = 1.f;
-            Pointf instance_offset(0., 0.); 
+            Vec2d instance_offset(0., 0.); 
             bool   trafo_set = false;
             unsigned int group_id     = (unsigned int)-1;
             unsigned int extruder_id  = (unsigned int)-1;
@@ -207,8 +207,8 @@ bool load_prus(const char *path, Model *model)
                         for (size_t c = 0; c < 3; ++ c)
                             trafo[r][c] += mat_trafo(r, c);
                     }
-                    instance_offset.x = position[0] - zero[0];
-                    instance_offset.y = position[1] - zero[1];
+                    instance_offset(0) = position[0] - zero[0];
+                    instance_offset(1) = position[1] - zero[1];
                     trafo[2][3] = position[2] / instance_scaling_factor;
                     trafo_set = true;
                 }
@@ -260,8 +260,8 @@ bool load_prus(const char *path, Model *model)
 							mesh.repair();
 							// Transform the model.
 							stl_transform(&stl, &trafo[0][0]);
-							if (std::abs(stl.stats.min.z) < EPSILON)
-								stl.stats.min.z = 0.;
+							if (std::abs(stl.stats.min(2)) < EPSILON)
+								stl.stats.min(2) = 0.;
 							// Add a mesh to a model.
 							if (mesh.facets_count() > 0)
                                 mesh_valid = true;
@@ -309,11 +309,11 @@ bool load_prus(const char *path, Model *model)
 						assert(res_normal == 3);
                         int res_outer_loop	= line_reader.next_line_scanf(" outer loop");
 						assert(res_outer_loop == 0);
-						int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0].x, &facet.vertex[0].y, &facet.vertex[0].z);
+						int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
 						assert(res_vertex1 == 3);
-						int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1].x, &facet.vertex[1].y, &facet.vertex[1].z);
+						int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
 						assert(res_vertex2 == 3);
-						int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2].x, &facet.vertex[2].y, &facet.vertex[2].z);
+						int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
 						assert(res_vertex3 == 3);
 						int res_endloop = line_reader.next_line_scanf(" endloop");
 						assert(res_endloop == 0);
@@ -324,9 +324,9 @@ bool load_prus(const char *path, Model *model)
                             break;
                         }
                         // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
-                        if (sscanf(normal_buf[0], "%f", &facet.normal.x) != 1 ||
-                            sscanf(normal_buf[1], "%f", &facet.normal.y) != 1 ||
-                            sscanf(normal_buf[2], "%f", &facet.normal.z) != 1) {
+                        if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
+                            sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
+                            sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
                             // Normal was mangled. Maybe denormals or "not a number" were stored?
                             // Just reset the normal and silently ignore it.
                             memset(&facet.normal, 0, sizeof(facet.normal));
diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp
index b34ba5441..fa18ddf3f 100644
--- a/xs/src/libslic3r/GCode.cpp
+++ b/xs/src/libslic3r/GCode.cpp
@@ -49,11 +49,11 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point &
     // If use_external, then perform the path planning in the world coordinate system (correcting for the gcodegen offset).
     // Otherwise perform the path planning in the coordinate system of the active object.
     bool  use_external  = this->use_external_mp || this->use_external_mp_once;
-    Point scaled_origin = use_external ? Point::new_scale(gcodegen.origin().x, gcodegen.origin().y) : Point(0, 0);
+    Point scaled_origin = use_external ? Point::new_scale(gcodegen.origin()(0), gcodegen.origin()(1)) : Point(0, 0);
     Polyline result = (use_external ? m_external_mp.get() : m_layer_mp.get())->
         shortest_path(gcodegen.last_pos() + scaled_origin, point + scaled_origin);
     if (use_external)
-        result.translate(scaled_origin.negative());
+        result.translate(- scaled_origin);
     return result;
 }
 
@@ -64,8 +64,8 @@ std::string OozePrevention::pre_toolchange(GCode &gcodegen)
     // move to the nearest standby point
     if (!this->standby_points.empty()) {
         // get current position in print coordinates
-        Pointf3 writer_pos = gcodegen.writer().get_position();
-        Point pos = Point::new_scale(writer_pos.x, writer_pos.y);
+        Vec3d writer_pos = gcodegen.writer().get_position();
+        Point pos = Point::new_scale(writer_pos(0), writer_pos(1));
         
         // find standby point
         Point standby_point;
@@ -74,7 +74,7 @@ std::string OozePrevention::pre_toolchange(GCode &gcodegen)
         /*  We don't call gcodegen.travel_to() because we don't need retraction (it was already
             triggered by the caller) nor avoid_crossing_perimeters and also because the coordinates
             of the destination point must not be transformed by origin nor current extruder offset.  */
-        gcode += gcodegen.writer().travel_to_xy(Pointf::new_unscale(standby_point), 
+        gcode += gcodegen.writer().travel_to_xy(unscale(standby_point), 
             "move to standby position");
     }
     
@@ -160,7 +160,7 @@ Wipe::wipe(GCode &gcodegen, bool toolchange)
 
 static inline Point wipe_tower_point_to_object_point(GCode &gcodegen, const WipeTower::xy &wipe_tower_pt)
 {
-    return Point(scale_(wipe_tower_pt.x - gcodegen.origin().x), scale_(wipe_tower_pt.y - gcodegen.origin().y));
+    return Point(scale_(wipe_tower_pt.x - gcodegen.origin()(0)), scale_(wipe_tower_pt.y - gcodegen.origin()(1)));
 }
 
 std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const
@@ -207,7 +207,7 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
         check_add_eol(gcode);
     }
     // A phony move to the end position at the wipe tower.
-    gcodegen.writer().travel_to_xy(Pointf(end_pos.x, end_pos.y));
+    gcodegen.writer().travel_to_xy(Vec2d(end_pos.x, end_pos.y));
     gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
 
     // Prepare a future wipe.
@@ -293,7 +293,7 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen)
         gcodegen.writer().toolchange(current_extruder_id);
         gcodegen.placeholder_parser().set("current_extruder", current_extruder_id);
         // A phony move to the end position at the wipe tower.
-        gcodegen.writer().travel_to_xy(Pointf(m_priming.end_pos.x, m_priming.end_pos.y));
+        gcodegen.writer().travel_to_xy(Vec2d(m_priming.end_pos.x, m_priming.end_pos.y));
         gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, m_priming.end_pos));
         // Prepare a future wipe.
         gcodegen.m_wipe.path.points.clear();
@@ -325,7 +325,7 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id,
 std::string WipeTowerIntegration::finalize(GCode &gcodegen)
 {
     std::string gcode;
-    if (std::abs(gcodegen.writer().get_position().z - m_final_purge.print_z) > EPSILON)
+    if (std::abs(gcodegen.writer().get_position()(2) - m_final_purge.print_z) > EPSILON)
         gcode += gcodegen.change_layer(m_final_purge.print_z);
     gcode += append_tcr(gcodegen, m_final_purge, -1);
     return gcode;
@@ -767,7 +767,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
                 for (const ExPolygon &expoly : layer->slices.expolygons)
                     for (const Point &copy : object->_shifted_copies) {
                         islands.emplace_back(expoly.contour);
-                        islands.back().translate(copy);
+                        islands.back().translate(- copy);
                     }
         //FIXME Mege the islands in parallel.
         m_avoid_crossing_perimeters.init_external_mp(union_ex(islands));
@@ -783,9 +783,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
             Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
             Polygons skirts;
             for (unsigned int extruder_id : print.extruders()) {
-                const Pointf &extruder_offset = print.config.extruder_offset.get_at(extruder_id);
+                const Vec2d &extruder_offset = print.config.extruder_offset.get_at(extruder_id);
                 Polygon s(outer_skirt);
-                s.translate(-scale_(extruder_offset.x), -scale_(extruder_offset.y));
+                s.translate(Point::new_scale(- extruder_offset(0), - extruder_offset(1)));
                 skirts.emplace_back(std::move(s));
             }
             m_ooze_prevention.enable = true;
@@ -814,7 +814,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
         // Print objects from the smallest to the tallest to avoid collisions
         // when moving onto next object starting point.
         std::vector<PrintObject*> objects(printable_objects);
-        std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; });        
+        std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size(2) < po2->size(2); });       
         size_t finished_objects = 0;
         for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) {
             const PrintObject &object = *objects[object_id];
@@ -831,7 +831,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
                     final_extruder_id   = tool_ordering.last_extruder();
                     assert(final_extruder_id != (unsigned int)-1);
                 }
-                this->set_origin(unscale(copy.x), unscale(copy.y));
+                this->set_origin(unscale(copy));
                 if (finished_objects > 0) {
                     // Move to the origin position for the copy we're going to print.
                     // This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
@@ -940,7 +940,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
     {
         DynamicConfig config;
         config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
-        config.set_key_value("layer_z",   new ConfigOptionFloat(m_writer.get_position().z - m_config.z_offset.value));
+        config.set_key_value("layer_z",   new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value));
         if (print.config.single_extruder_multi_material) {
             // Process the end_filament_gcode for the active filament only.
             _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config.end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id(), &config));
@@ -1396,8 +1396,8 @@ void GCode::process_layer(
                 layer_surface_bboxes.push_back(get_extents(expoly.contour));
             auto point_inside_surface = [&layer, &layer_surface_bboxes](const size_t i, const Point &point) { 
                 const BoundingBox &bbox = layer_surface_bboxes[i];
-                return point.x >= bbox.min.x && point.x < bbox.max.x &&
-                       point.y >= bbox.min.y && point.y < bbox.max.y &&
+                return point(0) >= bbox.min(0) && point(0) < bbox.max(0) &&
+                       point(1) >= bbox.min(1) && point(1) < bbox.max(1) &&
                        layer.slices.expolygons[i].contour.contains(point);
             };
 
@@ -1547,7 +1547,7 @@ void GCode::process_layer(
                     if (m_last_obj_copy != this_object_copy)
                         m_avoid_crossing_perimeters.use_external_mp_once = true;
                     m_last_obj_copy = this_object_copy;
-                    this->set_origin(unscale(copy.x), unscale(copy.y));
+                    this->set_origin(unscale(copy));
                     if (object_by_extruder.support != nullptr && !print_wipe_extrusions) {
                         m_layer = layers[layer_id].support_layer;
                         gcode += this->extrude_support(
@@ -1632,14 +1632,14 @@ void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids)
         }
 }
 
-void GCode::set_origin(const Pointf &pointf)
+void GCode::set_origin(const Vec2d &pointf)
 {    
     // if origin increases (goes towards right), last_pos decreases because it goes towards left
     const Point translate(
-        scale_(m_origin.x - pointf.x),
-        scale_(m_origin.y - pointf.y)
+        scale_(m_origin(0) - pointf(0)),
+        scale_(m_origin(1) - pointf(1))
     );
-    m_last_pos.translate(translate);
+    m_last_pos += translate;
     m_wipe.path.translate(translate);
     m_origin = pointf;
 }
@@ -1770,13 +1770,13 @@ static Points::iterator project_point_to_polygon_and_insert(Polygon &polygon, co
             j = 0;
         const Point &p1 = polygon.points[i];
         const Point &p2 = polygon.points[j];
-        const Slic3r::Point v_seg = p1.vector_to(p2);
-        const Slic3r::Point v_pt  = p1.vector_to(pt);
-        const int64_t l2_seg = int64_t(v_seg.x) * int64_t(v_seg.x) + int64_t(v_seg.y) * int64_t(v_seg.y);
-        int64_t t_pt = int64_t(v_seg.x) * int64_t(v_pt.x) + int64_t(v_seg.y) * int64_t(v_pt.y);
+        const Slic3r::Point v_seg = p2 - p1;
+        const Slic3r::Point v_pt  = pt - p1;
+        const int64_t l2_seg = int64_t(v_seg(0)) * int64_t(v_seg(0)) + int64_t(v_seg(1)) * int64_t(v_seg(1));
+        int64_t t_pt = int64_t(v_seg(0)) * int64_t(v_pt(0)) + int64_t(v_seg(1)) * int64_t(v_pt(1));
         if (t_pt < 0) {
             // Closest to p1.
-            double dabs = sqrt(int64_t(v_pt.x) * int64_t(v_pt.x) + int64_t(v_pt.y) * int64_t(v_pt.y));
+            double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
             if (dabs < d_min) {
                 d_min  = dabs;
                 i_min  = i;
@@ -1789,7 +1789,7 @@ static Points::iterator project_point_to_polygon_and_insert(Polygon &polygon, co
         } else {
             // Closest to the segment.
             assert(t_pt >= 0 && t_pt <= l2_seg);
-            int64_t d_seg = int64_t(v_seg.y) * int64_t(v_pt.x) - int64_t(v_seg.x) * int64_t(v_pt.y);
+            int64_t d_seg = int64_t(v_seg(1)) * int64_t(v_pt(0)) - int64_t(v_seg(0)) * int64_t(v_pt(1));
             double d = double(d_seg) / sqrt(double(l2_seg));
             double dabs = std::abs(d);
             if (dabs < d_min) {
@@ -1798,15 +1798,15 @@ static Points::iterator project_point_to_polygon_and_insert(Polygon &polygon, co
                 // Evaluate the foot point.
                 pt_min = p1;
                 double linv = double(d_seg) / double(l2_seg);
-                pt_min.x = pt.x - coord_t(floor(double(v_seg.y) * linv + 0.5));
-				pt_min.y = pt.y + coord_t(floor(double(v_seg.x) * linv + 0.5));
+                pt_min(0) = pt(0) - coord_t(floor(double(v_seg(1)) * linv + 0.5));
+				pt_min(1) = pt(1) + coord_t(floor(double(v_seg(0)) * linv + 0.5));
 				assert(Line(p1, p2).distance_to(pt_min) < scale_(1e-5));
             }
         }
     }
 
 	assert(i_min != size_t(-1));
-    if (pt_min.distance_to(polygon.points[i_min]) > eps) {
+    if ((pt_min - polygon.points[i_min]).cast<double>().norm() > eps) {
         // Insert a new point on the segment i_min, i_min+1.
         return polygon.points.insert(polygon.points.begin() + (i_min + 1), pt_min);
     }
@@ -1818,8 +1818,8 @@ std::vector<float> polygon_parameter_by_length(const Polygon &polygon)
     // Parametrize the polygon by its length.
     std::vector<float> lengths(polygon.points.size()+1, 0.);
     for (size_t i = 1; i < polygon.points.size(); ++ i)
-        lengths[i] = lengths[i-1] + float(polygon.points[i].distance_to(polygon.points[i-1]));
-    lengths.back() = lengths[lengths.size()-2] + float(polygon.points.front().distance_to(polygon.points.back()));
+        lengths[i] = lengths[i-1] + (polygon.points[i] - polygon.points[i-1]).cast<float>().norm();
+    lengths.back() = lengths[lengths.size()-2] + (polygon.points.front() - polygon.points.back()).cast<float>().norm();
     return lengths;
 }
 
@@ -1867,10 +1867,10 @@ std::vector<float> polygon_angles_at_vertices(const Polygon &polygon, const std:
         const Point &p0 = polygon.points[idx_prev];
         const Point &p1 = polygon.points[idx_curr];
         const Point &p2 = polygon.points[idx_next];
-        const Point  v1 = p0.vector_to(p1);
-        const Point  v2 = p1.vector_to(p2);
-		int64_t dot   = int64_t(v1.x)*int64_t(v2.x) + int64_t(v1.y)*int64_t(v2.y);
-		int64_t cross = int64_t(v1.x)*int64_t(v2.y) - int64_t(v1.y)*int64_t(v2.x);
+        const Point  v1 = p1 - p0;
+        const Point  v2 = p2 - p1;
+		int64_t dot   = int64_t(v1(0))*int64_t(v2(0)) + int64_t(v1(1))*int64_t(v2(1));
+		int64_t cross = int64_t(v1(0))*int64_t(v2(1)) - int64_t(v1(1))*int64_t(v2(0));
 		float angle = float(atan2(double(cross), double(dot)));
         angles[idx_curr] = angle;
     }
@@ -1894,10 +1894,10 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
             {
                 static int iRun = 0;
                 BoundingBox bbox = (*lower_layer_edge_grid)->bbox();
-                bbox.min.x -= scale_(5.f);
-                bbox.min.y -= scale_(5.f);
-                bbox.max.x += scale_(5.f);
-                bbox.max.y += scale_(5.f);
+                bbox.min(0) -= scale_(5.f);
+                bbox.min(1) -= scale_(5.f);
+                bbox.max(0) += scale_(5.f);
+                bbox.max(1) += scale_(5.f);
                 EdgeGrid::save_png(*(*lower_layer_edge_grid), bbox, scale_(0.1f), debug_out_path("GCode_extrude_loop_edge_grid-%d.png", iRun++));
             }
             #endif
@@ -1933,7 +1933,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
             break;
         case spRear:
             last_pos = m_layer->object()->bounding_box().center();
-            last_pos.y += coord_t(3. * m_layer->object()->bounding_box().radius());
+            last_pos(1) += coord_t(3. * m_layer->object()->bounding_box().radius());
             last_pos_weight = 5.f;
             break;
         }
@@ -2066,7 +2066,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
             //FIXME Better parametrize the loop by its length.
             Polygon polygon = loop.polygon();
             Point centroid = polygon.centroid();
-            last_pos = Point(polygon.bounding_box().max.x, centroid.y);
+            last_pos = Point(polygon.bounding_box().max(0), centroid(1));
             last_pos.rotate(fmod((float)rand()/16.0, 2.0*PI), centroid);
         }
         // Find the closest point, avoid overhangs.
@@ -2123,19 +2123,17 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
         // create the destination point along the first segment and rotate it
         // we make sure we don't exceed the segment length because we don't know
         // the rotation of the second segment so we might cross the object boundary
-        Line first_segment(
-            paths.front().polyline.points[0],
-            paths.front().polyline.points[1]
-        );
-        double distance = std::min<double>(
-            scale_(EXTRUDER_CONFIG(nozzle_diameter)),
-            first_segment.length()
-        );
-        Point point = first_segment.point_at(distance);
-        point.rotate(angle, first_segment.a);
-        
+        Vec2d  p1 = paths.front().polyline.points.front().cast<double>();
+        Vec2d  p2 = paths.front().polyline.points[1].cast<double>();
+        Vec2d  v  = p2 - p1;
+        double nd = scale_(EXTRUDER_CONFIG(nozzle_diameter));
+        double l2 = v.squaredNorm();
+        // Shift by no more than a nozzle diameter.
+        //FIXME Hiding the seams will not work nicely for very densely discretized contours!
+        Point  pt = ((nd * nd >= l2) ? p2 : (p1 + v * (nd / sqrt(l2)))).cast<coord_t>();
+        pt.rotate(angle, paths.front().polyline.points.front());
         // generate the travel move
-        gcode += m_writer.travel_to_xy(this->point_to_gcode(point), "move inwards before travel");
+        gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), "move inwards before travel");
     }
     
     return gcode;
@@ -2305,7 +2303,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
     std::string gcode;
     
     // go to first point of extrusion path
-    if (!m_last_pos_defined || !m_last_pos.coincides_with(path.first_point())) {
+    if (!m_last_pos_defined || m_last_pos != path.first_point()) {
         gcode += this->travel_to(
             path.first_point(),
             path.role(),
@@ -2620,24 +2618,21 @@ std::string GCode::set_extruder(unsigned int extruder_id)
 }
 
 // convert a model-space scaled point into G-code coordinates
-Pointf GCode::point_to_gcode(const Point &point) const
+Vec2d GCode::point_to_gcode(const Point &point) const
 {
-    Pointf extruder_offset = EXTRUDER_CONFIG(extruder_offset);
-    return Pointf(
-        unscale(point.x) + m_origin.x - extruder_offset.x,
-        unscale(point.y) + m_origin.y - extruder_offset.y);
+    Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
+    return unscale(point) + m_origin - extruder_offset;
 }
 
 // convert a model-space scaled point into G-code coordinates
-Point GCode::gcode_to_point(const Pointf &point) const
+Point GCode::gcode_to_point(const Vec2d &point) const
 {
-    Pointf extruder_offset = EXTRUDER_CONFIG(extruder_offset);
+    Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
     return Point(
-        scale_(point.x - m_origin.x + extruder_offset.x),
-        scale_(point.y - m_origin.y + extruder_offset.y));
+        scale_(point(0) - m_origin(0) + extruder_offset(0)),
+        scale_(point(1) - m_origin(1) + extruder_offset(1)));
 }
 
-
 // Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
 // during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
 // Returns a reference to member to avoid copying.
diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp
index 4953c39fe..dc8a32135 100644
--- a/xs/src/libslic3r/GCode.hpp
+++ b/xs/src/libslic3r/GCode.hpp
@@ -125,6 +125,7 @@ private:
 class GCode {
 public:        
     GCode() : 
+    	m_origin(Vec2d::Zero()),
         m_enable_loop_clipping(true), 
         m_enable_cooling_markers(false), 
         m_enable_extrusion_role_markers(false), 
@@ -152,12 +153,12 @@ public:
     void            do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
 
     // Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
-    const Pointf&   origin() const { return m_origin; }
-    void            set_origin(const Pointf &pointf);
-    void            set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Pointf(x, y)); }
+    const Vec2d&   origin() const { return m_origin; }
+    void            set_origin(const Vec2d &pointf);
+    void            set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); }
     const Point&    last_pos() const { return m_last_pos; }
-    Pointf          point_to_gcode(const Point &point) const;
-    Point           gcode_to_point(const Pointf &point) const;
+    Vec2d          point_to_gcode(const Point &point) const;
+    Point           gcode_to_point(const Vec2d &point) const;
     const FullPrintConfig &config() const { return m_config; }
     const Layer*    layer() const { return m_layer; }
     GCodeWriter&    writer() { return m_writer; }
@@ -258,7 +259,7 @@ protected:
     /* Origin of print coordinates expressed in unscaled G-code coordinates.
        This affects the input arguments supplied to the extrude*() and travel_to()
        methods. */
-    Pointf                              m_origin;
+    Vec2d                              m_origin;
     FullPrintConfig                     m_config;
     GCodeWriter                         m_writer;
     PlaceholderParser                   m_placeholder_parser;
diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp
index b7ecee5a4..51d5b1a06 100644
--- a/xs/src/libslic3r/GCode/Analyzer.cpp
+++ b/xs/src/libslic3r/GCode/Analyzer.cpp
@@ -14,7 +14,7 @@ static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
 static const float INCHES_TO_MM = 25.4f;
 static const float DEFAULT_FEEDRATE = 0.0f;
 static const unsigned int DEFAULT_EXTRUDER_ID = 0;
-static const Slic3r::Pointf3 DEFAULT_START_POSITION = Slic3r::Pointf3(0.0f, 0.0f, 0.0f);
+static const Slic3r::Vec3d DEFAULT_START_POSITION = Slic3r::Vec3d(0.0f, 0.0f, 0.0f);
 static const float DEFAULT_START_EXTRUSION = 0.0f;
 
 namespace Slic3r {
@@ -71,7 +71,7 @@ bool GCodeAnalyzer::Metadata::operator != (const GCodeAnalyzer::Metadata& other)
     return false;
 }
 
-GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder)
+GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder)
     : type(type)
     , data(extrusion_role, extruder_id, mm3_per_mm, width, height, feedrate)
     , start_position(start_position)
@@ -80,7 +80,7 @@ GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusi
 {
 }
 
-GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder)
+GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder)
     : type(type)
     , data(data)
     , start_position(start_position)
@@ -587,12 +587,12 @@ void GCodeAnalyzer::_reset_axes_position()
     ::memset((void*)m_state.position, 0, Num_Axis * sizeof(float));
 }
 
-void GCodeAnalyzer::_set_start_position(const Pointf3& position)
+void GCodeAnalyzer::_set_start_position(const Vec3d& position)
 {
     m_state.start_position = position;
 }
 
-const Pointf3& GCodeAnalyzer::_get_start_position() const
+const Vec3d& GCodeAnalyzer::_get_start_position() const
 {
     return m_state.start_position;
 }
@@ -612,9 +612,9 @@ float GCodeAnalyzer::_get_delta_extrusion() const
     return _get_axis_position(E) - m_state.start_extrusion;
 }
 
-Pointf3 GCodeAnalyzer::_get_end_position() const
+Vec3d GCodeAnalyzer::_get_end_position() const
 {
-    return Pointf3(m_state.position[X], m_state.position[Y], m_state.position[Z]);
+    return Vec3d(m_state.position[X], m_state.position[Y], m_state.position[Z]);
 }
 
 void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type)
@@ -673,7 +673,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
     Metadata data;
     float z = FLT_MAX;
     Polyline polyline;
-    Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX);
+    Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX);
     float volumetric_rate = FLT_MAX;
     GCodePreviewData::Range height_range;
     GCodePreviewData::Range width_range;
@@ -683,7 +683,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
     // constructs the polylines while traversing the moves
     for (const GCodeMove& move : extrude_moves->second)
     {
-        if ((data != move.data) || (z != move.start_position.z) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm))
+        if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm))
         {
             // store current polyline
             polyline.remove_duplicate_points();
@@ -693,12 +693,12 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
             polyline = Polyline();
 
             // add both vertices of the move
-            polyline.append(Point(scale_(move.start_position.x), scale_(move.start_position.y)));
-            polyline.append(Point(scale_(move.end_position.x), scale_(move.end_position.y)));
+            polyline.append(Point(scale_(move.start_position.x()), scale_(move.start_position.y())));
+            polyline.append(Point(scale_(move.end_position.x()), scale_(move.end_position.y())));
 
             // update current values
             data = move.data;
-            z = move.start_position.z;
+            z = move.start_position.z();
             volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm;
             height_range.update_from(move.data.height);
             width_range.update_from(move.data.width);
@@ -707,7 +707,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
         }
         else
             // append end vertex of the move to current polyline
-            polyline.append(Point(scale_(move.end_position.x), scale_(move.end_position.y)));
+            polyline.append(Point(scale_(move.end_position.x()), scale_(move.end_position.y())));
 
         // update current values
         position = move.end_position;
@@ -742,7 +742,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
         return;
 
     Polyline3 polyline;
-    Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX);
+    Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX);
     GCodePreviewData::Travel::EType type = GCodePreviewData::Travel::Num_Types;
     GCodePreviewData::Travel::Polyline::EDirection direction = GCodePreviewData::Travel::Polyline::Num_Directions;
     float feedrate = FLT_MAX;
@@ -756,7 +756,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
     for (const GCodeMove& move : travel_moves->second)
     {
         GCodePreviewData::Travel::EType move_type = (move.delta_extruder < 0.0f) ? GCodePreviewData::Travel::Retract : ((move.delta_extruder > 0.0f) ? GCodePreviewData::Travel::Extrude : GCodePreviewData::Travel::Move);
-        GCodePreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x != move.end_position.x) || (move.start_position.y != move.end_position.y)) ? GCodePreviewData::Travel::Polyline::Generic : GCodePreviewData::Travel::Polyline::Vertical;
+        GCodePreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x() != move.end_position.x()) || (move.start_position.y() != move.end_position.y())) ? GCodePreviewData::Travel::Polyline::Generic : GCodePreviewData::Travel::Polyline::Vertical;
 
         if ((type != move_type) || (direction != move_direction) || (feedrate != move.data.feedrate) || (position != move.start_position) || (extruder_id != move.data.extruder_id))
         {
@@ -768,12 +768,12 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
             polyline = Polyline3();
 
             // add both vertices of the move
-            polyline.append(Point3(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z)));
-            polyline.append(Point3(scale_(move.end_position.x), scale_(move.end_position.y), scale_(move.end_position.z)));
+            polyline.append(Vec3crd(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())));
+            polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z())));
         }
         else
             // append end vertex of the move to current polyline
-            polyline.append(Point3(scale_(move.end_position.x), scale_(move.end_position.y), scale_(move.end_position.z)));
+            polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z())));
 
         // update current values
         position = move.end_position;
@@ -804,7 +804,7 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da
     for (const GCodeMove& move : retraction_moves->second)
     {
         // store position
-        Point3 position(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z));
+        Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
         preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height);
     }
 }
@@ -818,7 +818,7 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_
     for (const GCodeMove& move : unretraction_moves->second)
     {
         // store position
-        Point3 position(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z));
+        Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
         preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height);
     }
 }
diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp
index 03dbab338..27a49b869 100644
--- a/xs/src/libslic3r/GCode/Analyzer.hpp
+++ b/xs/src/libslic3r/GCode/Analyzer.hpp
@@ -75,12 +75,12 @@ public:
 
         EType type;
         Metadata data;
-        Pointf3 start_position;
-        Pointf3 end_position;
+        Vec3d start_position;
+        Vec3d end_position;
         float delta_extruder;
 
-        GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder);
-        GCodeMove(EType type, const Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder);
+        GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder);
+        GCodeMove(EType type, const Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder);
     };
 
     typedef std::vector<GCodeMove> GCodeMovesList;
@@ -93,7 +93,7 @@ private:
         EPositioningType global_positioning_type;
         EPositioningType e_local_positioning_type;
         Metadata data;
-        Pointf3 start_position;
+        Vec3d start_position = Vec3d::Zero();
         float start_extrusion;
         float position[Num_Axis];
     };
@@ -206,15 +206,15 @@ private:
     // Sets axes position to zero
     void _reset_axes_position();
 
-    void _set_start_position(const Pointf3& position);
-    const Pointf3& _get_start_position() const;
+    void _set_start_position(const Vec3d& position);
+    const Vec3d& _get_start_position() const;
 
     void _set_start_extrusion(float extrusion);
     float _get_start_extrusion() const;
     float _get_delta_extrusion() const;
 
     // Returns current xyz position (from m_state.position[])
-    Pointf3 _get_end_position() const;
+    Vec3d _get_end_position() const;
 
     // Adds a new move with the given data
     void _store_move(GCodeMove::EType type);
diff --git a/xs/src/libslic3r/GCode/CoolingBuffer.cpp b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
index a15247693..40ccc7b09 100644
--- a/xs/src/libslic3r/GCode/CoolingBuffer.cpp
+++ b/xs/src/libslic3r/GCode/CoolingBuffer.cpp
@@ -23,10 +23,10 @@ CoolingBuffer::CoolingBuffer(GCode &gcodegen) : m_gcodegen(gcodegen), m_current_
 void CoolingBuffer::reset()
 {
     m_current_pos.assign(5, 0.f);
-    Pointf3 pos = m_gcodegen.writer().get_position();
-    m_current_pos[0] = float(pos.x);
-    m_current_pos[1] = float(pos.y);
-    m_current_pos[2] = float(pos.z);
+    Vec3d pos = m_gcodegen.writer().get_position();
+    m_current_pos[0] = float(pos(0));
+    m_current_pos[1] = float(pos(1));
+    m_current_pos[2] = float(pos(2));
     m_current_pos[4] = float(m_gcodegen.config().travel_speed.value);
 }
 
diff --git a/xs/src/libslic3r/GCode/PreviewData.cpp b/xs/src/libslic3r/GCode/PreviewData.cpp
index 3833bca06..9cf9716e0 100644
--- a/xs/src/libslic3r/GCode/PreviewData.cpp
+++ b/xs/src/libslic3r/GCode/PreviewData.cpp
@@ -226,7 +226,7 @@ void GCodePreviewData::Travel::set_default()
 
 const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f);
 
-GCodePreviewData::Retraction::Position::Position(const Point3& position, float width, float height)
+GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height)
     : position(position)
     , width(width)
     , height(height)
diff --git a/xs/src/libslic3r/GCode/PreviewData.hpp b/xs/src/libslic3r/GCode/PreviewData.hpp
index ea8ca6d58..ab74993f5 100644
--- a/xs/src/libslic3r/GCode/PreviewData.hpp
+++ b/xs/src/libslic3r/GCode/PreviewData.hpp
@@ -151,11 +151,11 @@ public:
 
         struct Position
         {
-            Point3 position;
+            Vec3crd position;
             float width;
             float height;
 
-            Position(const Point3& position, float width, float height);
+            Position(const Vec3crd& position, float width, float height);
         };
 
         typedef std::vector<Position> PositionsList;
diff --git a/xs/src/libslic3r/GCode/PrintExtents.cpp b/xs/src/libslic3r/GCode/PrintExtents.cpp
index 37b79f343..2ed607769 100644
--- a/xs/src/libslic3r/GCode/PrintExtents.cpp
+++ b/xs/src/libslic3r/GCode/PrintExtents.cpp
@@ -19,10 +19,10 @@ static inline BoundingBox extrusion_polyline_extents(const Polyline &polyline, c
     if (! polyline.points.empty())
         bbox.merge(polyline.points.front());
     for (const Point &pt : polyline.points) {
-        bbox.min.x = std::min(bbox.min.x, pt.x - radius);
-        bbox.min.y = std::min(bbox.min.y, pt.y - radius);
-        bbox.max.x = std::max(bbox.max.x, pt.x + radius);
-        bbox.max.y = std::max(bbox.max.y, pt.y + radius);
+        bbox.min(0) = std::min(bbox.min(0), pt(0) - radius);
+        bbox.min(1) = std::min(bbox.min(1), pt(1) - radius);
+        bbox.max(0) = std::max(bbox.max(0), pt(0) + radius);
+        bbox.max(1) = std::max(bbox.max(1), pt(1) + radius);
     }
     return bbox;
 }
@@ -32,8 +32,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionPath &extrusio
     BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width));
     BoundingBoxf bboxf;
     if (! empty(bbox)) {
-        bboxf.min = Pointf::new_unscale(bbox.min);
-        bboxf.max = Pointf::new_unscale(bbox.max);
+        bboxf.min = unscale(bbox.min);
+        bboxf.max = unscale(bbox.max);
 		bboxf.defined = true;
     }
     return bboxf;
@@ -46,8 +46,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionLoop &extrusio
         bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
     BoundingBoxf bboxf;
     if (! empty(bbox)) {
-        bboxf.min = Pointf::new_unscale(bbox.min);
-        bboxf.max = Pointf::new_unscale(bbox.max);
+        bboxf.min = unscale(bbox.min);
+        bboxf.max = unscale(bbox.max);
 		bboxf.defined = true;
 	}
     return bboxf;
@@ -60,8 +60,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionMultiPath &ext
         bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
     BoundingBoxf bboxf;
     if (! empty(bbox)) {
-        bboxf.min = Pointf::new_unscale(bbox.min);
-        bboxf.max = Pointf::new_unscale(bbox.max);
+        bboxf.min = unscale(bbox.min);
+        bboxf.max = unscale(bbox.max);
 		bboxf.defined = true;
 	}
     return bboxf;
@@ -123,7 +123,7 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object
                 bbox_this.merge(extrusionentity_extents(extrusion_entity));
         for (const Point &offset : print_object._shifted_copies) {
             BoundingBoxf bbox_translated(bbox_this);
-            bbox_translated.translate(Pointf::new_unscale(offset));
+            bbox_translated.translate(unscale(offset));
             bbox.merge(bbox_translated);
         }
     }
@@ -136,8 +136,9 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_
 {
     // Wipe tower extrusions are saved as if the tower was at the origin with no rotation
     // We need to get position and angle of the wipe tower to transform them to actual position.
-    Pointf wipe_tower_pos(print.config.wipe_tower_x.value, print.config.wipe_tower_y.value);
-    float wipe_tower_angle = print.config.wipe_tower_rotation_angle.value;
+    Transform2d trafo =
+        Eigen::Translation2d(print.config.wipe_tower_x.value, print.config.wipe_tower_y.value) *
+        Eigen::Rotation2Dd(print.config.wipe_tower_rotation_angle.value);
 
     BoundingBoxf bbox;
     for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.m_wipe_tower_tool_changes) {
@@ -147,19 +148,11 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_
             for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
                 const WipeTower::Extrusion &e = tcr.extrusions[i];
                 if (e.width > 0) {
-                    Pointf  p1((&e - 1)->pos.x, (&e - 1)->pos.y);
-                    Pointf  p2(e.pos.x, e.pos.y);
-                    p1.rotate(wipe_tower_angle);
-                    p1.translate(wipe_tower_pos);
-                    p2.rotate(wipe_tower_angle);
-                    p2.translate(wipe_tower_pos);
-
-                    bbox.merge(p1);
-                    coordf_t radius = 0.5 * e.width;
-                    bbox.min.x = std::min(bbox.min.x, std::min(p1.x, p2.x) - radius);
-                    bbox.min.y = std::min(bbox.min.y, std::min(p1.y, p2.y) - radius);
-                    bbox.max.x = std::max(bbox.max.x, std::max(p1.x, p2.x) + radius);
-                    bbox.max.y = std::max(bbox.max.y, std::max(p1.y, p2.y) + radius);
+                    Vec2d delta = 0.5 * Vec2d(e.width, e.width);
+                    Vec2d p1 = trafo * Vec2d((&e - 1)->pos.x, (&e - 1)->pos.y);
+                    Vec2d p2 = trafo * Vec2d(e.pos.x, e.pos.y);
+                    bbox.merge(p1.cwiseMin(p2) - delta);
+                    bbox.merge(p1.cwiseMax(p2) + delta);
                 }
             }
         }
@@ -176,14 +169,14 @@ BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print)
         for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
             const WipeTower::Extrusion &e = tcr.extrusions[i];
             if (e.width > 0) {
-                Pointf  p1((&e - 1)->pos.x, (&e - 1)->pos.y);
-                Pointf  p2(e.pos.x, e.pos.y);
+                Vec2d  p1((&e - 1)->pos.x, (&e - 1)->pos.y);
+                Vec2d  p2(e.pos.x, e.pos.y);
                 bbox.merge(p1);
                 coordf_t radius = 0.5 * e.width;
-                bbox.min.x = std::min(bbox.min.x, std::min(p1.x, p2.x) - radius);
-                bbox.min.y = std::min(bbox.min.y, std::min(p1.y, p2.y) - radius);
-                bbox.max.x = std::max(bbox.max.x, std::max(p1.x, p2.x) + radius);
-                bbox.max.y = std::max(bbox.max.y, std::max(p1.y, p2.y) + radius);
+                bbox.min(0) = std::min(bbox.min(0), std::min(p1(0), p2(0)) - radius);
+                bbox.min(1) = std::min(bbox.min(1), std::min(p1(1), p2(1)) - radius);
+                bbox.max(0) = std::max(bbox.max(0), std::max(p1(0), p2(0)) + radius);
+                bbox.max(1) = std::max(bbox.max(1), std::max(p1(1), p2(1)) + radius);
             }
         }
     }
diff --git a/xs/src/libslic3r/GCode/WipeTower.hpp b/xs/src/libslic3r/GCode/WipeTower.hpp
index 9bf350328..c35a0feb3 100644
--- a/xs/src/libslic3r/GCode/WipeTower.hpp
+++ b/xs/src/libslic3r/GCode/WipeTower.hpp
@@ -30,10 +30,9 @@ public:
 			xy out(0,0);
 			float temp_x = x - width / 2.f;
 			float temp_y = y - depth / 2.f;
-			angle *= M_PI/180.;
+			angle *= float(M_PI/180.);
 			out.x += temp_x * cos(angle)  -  temp_y * sin(angle) + width / 2.f;
 			out.y += temp_x * sin(angle)  +  temp_y * cos(angle) + depth / 2.f;
-
 			return out;
 		}
         
diff --git a/xs/src/libslic3r/GCodeWriter.cpp b/xs/src/libslic3r/GCodeWriter.cpp
index 34e6b7ec3..6ef17f4f4 100644
--- a/xs/src/libslic3r/GCodeWriter.cpp
+++ b/xs/src/libslic3r/GCodeWriter.cpp
@@ -276,30 +276,30 @@ std::string GCodeWriter::set_speed(double F, const std::string &comment, const s
     return gcode.str();
 }
 
-std::string GCodeWriter::travel_to_xy(const Pointf &point, const std::string &comment)
+std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &comment)
 {
-    m_pos.x = point.x;
-    m_pos.y = point.y;
+    m_pos(0) = point(0);
+    m_pos(1) = point(1);
     
     std::ostringstream gcode;
-    gcode << "G1 X" << XYZF_NUM(point.x)
-          <<   " Y" << XYZF_NUM(point.y)
+    gcode << "G1 X" << XYZF_NUM(point(0))
+          <<   " Y" << XYZF_NUM(point(1))
           <<   " F" << XYZF_NUM(this->config.travel_speed.value * 60.0);
     COMMENT(comment);
     gcode << "\n";
     return gcode.str();
 }
 
-std::string GCodeWriter::travel_to_xyz(const Pointf3 &point, const std::string &comment)
+std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &comment)
 {
     /*  If target Z is lower than current Z but higher than nominal Z we
         don't perform the Z move but we only move in the XY plane and
         adjust the nominal Z by reducing the lift amount that will be 
         used for unlift. */
-    if (!this->will_move_z(point.z)) {
-        double nominal_z = m_pos.z - m_lifted;
-        m_lifted = m_lifted - (point.z - nominal_z);
-        return this->travel_to_xy(point);
+    if (!this->will_move_z(point(2))) {
+        double nominal_z = m_pos(2) - m_lifted;
+        m_lifted = m_lifted - (point(2) - nominal_z);
+        return this->travel_to_xy(to_2d(point));
     }
     
     /*  In all the other cases, we perform an actual XYZ move and cancel
@@ -308,9 +308,9 @@ std::string GCodeWriter::travel_to_xyz(const Pointf3 &point, const std::string &
     m_pos = point;
     
     std::ostringstream gcode;
-    gcode << "G1 X" << XYZF_NUM(point.x)
-          <<   " Y" << XYZF_NUM(point.y)
-          <<   " Z" << XYZF_NUM(point.z)
+    gcode << "G1 X" << XYZF_NUM(point(0))
+          <<   " Y" << XYZF_NUM(point(1))
+          <<   " Z" << XYZF_NUM(point(2))
           <<   " F" << XYZF_NUM(this->config.travel_speed.value * 60.0);
     COMMENT(comment);
     gcode << "\n";
@@ -323,7 +323,7 @@ std::string GCodeWriter::travel_to_z(double z, const std::string &comment)
         we don't perform the move but we only adjust the nominal Z by
         reducing the lift amount that will be used for unlift. */
     if (!this->will_move_z(z)) {
-        double nominal_z = m_pos.z - m_lifted;
+        double nominal_z = m_pos(2) - m_lifted;
         m_lifted = m_lifted - (z - nominal_z);
         return "";
     }
@@ -336,7 +336,7 @@ std::string GCodeWriter::travel_to_z(double z, const std::string &comment)
 
 std::string GCodeWriter::_travel_to_z(double z, const std::string &comment)
 {
-    m_pos.z = z;
+    m_pos(2) = z;
     
     std::ostringstream gcode;
     gcode << "G1 Z" << XYZF_NUM(z)
@@ -351,38 +351,38 @@ bool GCodeWriter::will_move_z(double z) const
     /* If target Z is lower than current Z but higher than nominal Z
         we don't perform an actual Z move. */
     if (m_lifted > 0) {
-        double nominal_z = m_pos.z - m_lifted;
-        if (z >= nominal_z && z <= m_pos.z)
+        double nominal_z = m_pos(2) - m_lifted;
+        if (z >= nominal_z && z <= m_pos(2))
             return false;
     }
     return true;
 }
 
-std::string GCodeWriter::extrude_to_xy(const Pointf &point, double dE, const std::string &comment)
+std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std::string &comment)
 {
-    m_pos.x = point.x;
-    m_pos.y = point.y;
+    m_pos(0) = point(0);
+    m_pos(1) = point(1);
     m_extruder->extrude(dE);
     
     std::ostringstream gcode;
-    gcode << "G1 X" << XYZF_NUM(point.x)
-          <<   " Y" << XYZF_NUM(point.y)
+    gcode << "G1 X" << XYZF_NUM(point(0))
+          <<   " Y" << XYZF_NUM(point(1))
           <<    " " << m_extrusion_axis << E_NUM(m_extruder->E());
     COMMENT(comment);
     gcode << "\n";
     return gcode.str();
 }
 
-std::string GCodeWriter::extrude_to_xyz(const Pointf3 &point, double dE, const std::string &comment)
+std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment)
 {
     m_pos = point;
     m_lifted = 0;
     m_extruder->extrude(dE);
     
     std::ostringstream gcode;
-    gcode << "G1 X" << XYZF_NUM(point.x)
-          <<   " Y" << XYZF_NUM(point.y)
-          <<   " Z" << XYZF_NUM(point.z)
+    gcode << "G1 X" << XYZF_NUM(point(0))
+          <<   " Y" << XYZF_NUM(point(1))
+          <<   " Z" << XYZF_NUM(point(2))
           <<    " " << m_extrusion_axis << E_NUM(m_extruder->E());
     COMMENT(comment);
     gcode << "\n";
@@ -486,12 +486,12 @@ std::string GCodeWriter::lift()
     {
         double above = this->config.retract_lift_above.get_at(m_extruder->id());
         double below = this->config.retract_lift_below.get_at(m_extruder->id());
-        if (m_pos.z >= above && (below == 0 || m_pos.z <= below))
+        if (m_pos(2) >= above && (below == 0 || m_pos(2) <= below))
             target_lift = this->config.retract_lift.get_at(m_extruder->id());
     }
     if (m_lifted == 0 && target_lift > 0) {
         m_lifted = target_lift;
-        return this->_travel_to_z(m_pos.z + target_lift, "lift Z");
+        return this->_travel_to_z(m_pos(2) + target_lift, "lift Z");
     }
     return "";
 }
@@ -500,7 +500,7 @@ std::string GCodeWriter::unlift()
 {
     std::string gcode;
     if (m_lifted > 0) {
-        gcode += this->_travel_to_z(m_pos.z - m_lifted, "restore layer Z");
+        gcode += this->_travel_to_z(m_pos(2) - m_lifted, "restore layer Z");
         m_lifted = 0;
     }
     return gcode;
diff --git a/xs/src/libslic3r/GCodeWriter.hpp b/xs/src/libslic3r/GCodeWriter.hpp
index f706b8768..664b0e3a1 100644
--- a/xs/src/libslic3r/GCodeWriter.hpp
+++ b/xs/src/libslic3r/GCodeWriter.hpp
@@ -55,18 +55,18 @@ public:
     std::string toolchange_prefix() const;
     std::string toolchange(unsigned int extruder_id);
     std::string set_speed(double F, const std::string &comment = std::string(), const std::string &cooling_marker = std::string()) const;
-    std::string travel_to_xy(const Pointf &point, const std::string &comment = std::string());
-    std::string travel_to_xyz(const Pointf3 &point, const std::string &comment = std::string());
+    std::string travel_to_xy(const Vec2d &point, const std::string &comment = std::string());
+    std::string travel_to_xyz(const Vec3d &point, const std::string &comment = std::string());
     std::string travel_to_z(double z, const std::string &comment = std::string());
     bool        will_move_z(double z) const;
-    std::string extrude_to_xy(const Pointf &point, double dE, const std::string &comment = std::string());
-    std::string extrude_to_xyz(const Pointf3 &point, double dE, const std::string &comment = std::string());
+    std::string extrude_to_xy(const Vec2d &point, double dE, const std::string &comment = std::string());
+    std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment = std::string());
     std::string retract(bool before_wipe = false);
     std::string retract_for_toolchange(bool before_wipe = false);
     std::string unretract();
     std::string lift();
     std::string unlift();
-    Pointf3     get_position() const { return m_pos; }
+    Vec3d       get_position() const { return m_pos; }
 
 private:
     std::vector<Extruder>    m_extruders;
@@ -81,7 +81,7 @@ private:
     unsigned int    m_last_bed_temperature;
     bool            m_last_bed_temperature_reached;
     double          m_lifted;
-    Pointf3         m_pos;
+    Vec3d           m_pos = Vec3d::Zero();
 
     std::string _travel_to_z(double z, const std::string &comment);
     std::string _retract(double length, double restart_extra, const std::string &comment);
diff --git a/xs/src/libslic3r/Geometry.cpp b/xs/src/libslic3r/Geometry.cpp
index 39b626ee3..c978d46b6 100644
--- a/xs/src/libslic3r/Geometry.cpp
+++ b/xs/src/libslic3r/Geometry.cpp
@@ -198,7 +198,7 @@ namespace Slic3r { namespace Geometry {
 static bool
 sort_points (Point a, Point b)
 {
-    return (a.x < b.x) || (a.x == b.x && a.y < b.y);
+    return (a(0) < b(0)) || (a(0) == b(0) && a(1) < b(1));
 }
 
 /* This implementation is based on Andrew's monotone chain 2D convex hull algorithm */
@@ -229,7 +229,7 @@ convex_hull(Points points)
 
         hull.points.resize(k);
         
-        assert( hull.points.front().coincides_with(hull.points.back()) );
+        assert( hull.points.front() == hull.points.back() );
         hull.points.pop_back();
     }
     
@@ -345,54 +345,54 @@ linint(double value, double oldmin, double oldmax, double newmin, double newmax)
 // If the points have the same weight, sort them lexicographically by their positions.
 struct ArrangeItem {
     ArrangeItem() {}
-    Pointf    pos;
+    Vec2d    pos;
     coordf_t  weight;
     bool operator<(const ArrangeItem &other) const {
         return weight < other.weight ||
-            ((weight == other.weight) && (pos.y < other.pos.y || (pos.y == other.pos.y && pos.x < other.pos.x)));
+            ((weight == other.weight) && (pos(1) < other.pos(1) || (pos(1) == other.pos(1) && pos(0) < other.pos(0))));
     }
 };
 
-Pointfs arrange(size_t num_parts, const Pointf &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box)
+Pointfs arrange(size_t num_parts, const Vec2d &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box)
 {
     // Use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm.
-    const Pointf       cell_size(part_size.x + gap, part_size.y + gap);
+    const Vec2d       cell_size(part_size(0) + gap, part_size(1) + gap);
 
     const BoundingBoxf bed_bbox = (bed_bounding_box != NULL && bed_bounding_box->defined) ? 
         *bed_bounding_box :
         // Bogus bed size, large enough not to trigger the unsufficient bed size error.
         BoundingBoxf(
-            Pointf(0, 0),
-            Pointf(cell_size.x * num_parts, cell_size.y * num_parts));
+            Vec2d(0, 0),
+            Vec2d(cell_size(0) * num_parts, cell_size(1) * num_parts));
 
     // This is how many cells we have available into which to put parts.
-    size_t cellw = size_t(floor((bed_bbox.size().x + gap) / cell_size.x));
-    size_t cellh = size_t(floor((bed_bbox.size().y + gap) / cell_size.y));
+    size_t cellw = size_t(floor((bed_bbox.size()(0) + gap) / cell_size(0)));
+    size_t cellh = size_t(floor((bed_bbox.size()(1) + gap) / cell_size(1)));
     if (num_parts > cellw * cellh)
         CONFESS(PRINTF_ZU " parts won't fit in your print area!\n", num_parts);
     
     // Get a bounding box of cellw x cellh cells, centered at the center of the bed.
-    Pointf       cells_size(cellw * cell_size.x - gap, cellh * cell_size.y - gap);
-    Pointf       cells_offset(bed_bbox.center() - 0.5 * cells_size);
+    Vec2d       cells_size(cellw * cell_size(0) - gap, cellh * cell_size(1) - gap);
+    Vec2d       cells_offset(bed_bbox.center() - 0.5 * cells_size);
     BoundingBoxf cells_bb(cells_offset, cells_size + cells_offset);
     
     // List of cells, sorted by distance from center.
     std::vector<ArrangeItem> cellsorder(cellw * cellh, ArrangeItem());
     for (size_t j = 0; j < cellh; ++ j) {
         // Center of the jth row on the bed.
-        coordf_t cy = linint(j + 0.5, 0., double(cellh), cells_bb.min.y, cells_bb.max.y);
+        coordf_t cy = linint(j + 0.5, 0., double(cellh), cells_bb.min(1), cells_bb.max(1));
         // Offset from the bed center.
-        coordf_t yd = cells_bb.center().y - cy;
+        coordf_t yd = cells_bb.center()(1) - cy;
         for (size_t i = 0; i < cellw; ++ i) {
             // Center of the ith column on the bed.
-            coordf_t cx = linint(i + 0.5, 0., double(cellw), cells_bb.min.x, cells_bb.max.x);
+            coordf_t cx = linint(i + 0.5, 0., double(cellw), cells_bb.min(0), cells_bb.max(0));
             // Offset from the bed center.
-            coordf_t xd = cells_bb.center().x - cx;
+            coordf_t xd = cells_bb.center()(0) - cx;
             // Cell with a distance from the bed center.
             ArrangeItem &ci = cellsorder[j * cellw + i];
             // Cell center
-            ci.pos.x = cx;
-            ci.pos.y = cy;
+            ci.pos(0) = cx;
+            ci.pos(1) = cy;
             // Square distance of the cell center to the bed center.
             ci.weight = xd * xd + yd * yd;
         }
@@ -405,61 +405,61 @@ Pointfs arrange(size_t num_parts, const Pointf &part_size, coordf_t gap, const B
     Pointfs positions;
     positions.reserve(num_parts);
     for (std::vector<ArrangeItem>::const_iterator it = cellsorder.begin(); it != cellsorder.end(); ++ it)
-        positions.push_back(Pointf(it->pos.x - 0.5 * part_size.x, it->pos.y - 0.5 * part_size.y));
+        positions.push_back(Vec2d(it->pos(0) - 0.5 * part_size(0), it->pos(1) - 0.5 * part_size(1)));
     return positions;
 }
 #else
 class ArrangeItem {
-    public:
-    Pointf pos;
+public:
+    Vec2d pos = Vec2d::Zero();
     size_t index_x, index_y;
     coordf_t dist;
 };
 class ArrangeItemIndex {
-    public:
+public:
     coordf_t index;
     ArrangeItem item;
     ArrangeItemIndex(coordf_t _index, ArrangeItem _item) : index(_index), item(_item) {};
 };
 
 bool
-arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const BoundingBoxf* bb, Pointfs &positions)
+arrange(size_t total_parts, const Vec2d &part_size, coordf_t dist, const BoundingBoxf* bb, Pointfs &positions)
 {
     positions.clear();
 
-    Pointf part = part_size;
+    Vec2d part = part_size;
 
     // use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm
-    part.x += dist;
-    part.y += dist;
+    part(0) += dist;
+    part(1) += dist;
     
-    Pointf area;
+    Vec2d area(Vec2d::Zero());
     if (bb != NULL && bb->defined) {
         area = bb->size();
     } else {
         // bogus area size, large enough not to trigger the error below
-        area.x = part.x * total_parts;
-        area.y = part.y * total_parts;
+        area(0) = part(0) * total_parts;
+        area(1) = part(1) * total_parts;
     }
     
     // this is how many cells we have available into which to put parts
-    size_t cellw = floor((area.x + dist) / part.x);
-    size_t cellh = floor((area.y + dist) / part.y);
+    size_t cellw = floor((area(0) + dist) / part(0));
+    size_t cellh = floor((area(1) + dist) / part(1));
     if (total_parts > (cellw * cellh))
         return false;
     
     // total space used by cells
-    Pointf cells(cellw * part.x, cellh * part.y);
+    Vec2d cells(cellw * part(0), cellh * part(1));
     
     // bounding box of total space used by cells
     BoundingBoxf cells_bb;
-    cells_bb.merge(Pointf(0,0)); // min
+    cells_bb.merge(Vec2d(0,0)); // min
     cells_bb.merge(cells);  // max
     
     // center bounding box to area
     cells_bb.translate(
-        (area.x - cells.x) / 2,
-        (area.y - cells.y) / 2
+        (area(0) - cells(0)) / 2,
+        (area(1) - cells(1)) / 2
     );
     
     // list of cells, sorted by distance from center
@@ -468,15 +468,15 @@ arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const Boundi
     // work out distance for all cells, sort into list
     for (size_t i = 0; i <= cellw-1; ++i) {
         for (size_t j = 0; j <= cellh-1; ++j) {
-            coordf_t cx = linint(i + 0.5, 0, cellw, cells_bb.min.x, cells_bb.max.x);
-            coordf_t cy = linint(j + 0.5, 0, cellh, cells_bb.min.y, cells_bb.max.y);
+            coordf_t cx = linint(i + 0.5, 0, cellw, cells_bb.min(0), cells_bb.max(0));
+            coordf_t cy = linint(j + 0.5, 0, cellh, cells_bb.min(1), cells_bb.max(1));
             
-            coordf_t xd = fabs((area.x / 2) - cx);
-            coordf_t yd = fabs((area.y / 2) - cy);
+            coordf_t xd = fabs((area(0) / 2) - cx);
+            coordf_t yd = fabs((area(1) / 2) - cy);
             
             ArrangeItem c;
-            c.pos.x = cx;
-            c.pos.y = cy;
+            c.pos(0) = cx;
+            c.pos(1) = cy;
             c.index_x = i;
             c.index_y = j;
             c.dist = xd * xd + yd * yd - fabs((cellw / 2) - (i + 0.5));
@@ -533,13 +533,13 @@ arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const Boundi
         coordf_t cx = c.item.index_x - lx;
         coordf_t cy = c.item.index_y - ty;
         
-        positions.push_back(Pointf(cx * part.x, cy * part.y));
+        positions.push_back(Vec2d(cx * part(0), cy * part(1)));
     }
     
     if (bb != NULL && bb->defined) {
         for (Pointfs::iterator p = positions.begin(); p != positions.end(); ++p) {
-            p->x += bb->min.x;
-            p->y += bb->min.y;
+            p->x() += bb->min(0);
+            p->y() += bb->min(1);
         }
     }
     
@@ -608,15 +608,15 @@ namespace Voronoi { namespace Internal {
         if (cell1.contains_point() && cell2.contains_point()) {
             point_type p1 = retrieve_point(segments, cell1);
             point_type p2 = retrieve_point(segments, cell2);
-            origin.x((p1.x() + p2.x()) * 0.5);
-            origin.y((p1.y() + p2.y()) * 0.5);
-            direction.x(p1.y() - p2.y());
-            direction.y(p2.x() - p1.x());
+            origin.x((p1(0) + p2(0)) * 0.5);
+            origin.y((p1(1) + p2(1)) * 0.5);
+            direction.x(p1(1) - p2(1));
+            direction.y(p2(0) - p1(0));
         } else {
             origin = cell1.contains_segment() ? retrieve_point(segments, cell2) : retrieve_point(segments, cell1);
             segment_type segment = cell1.contains_segment() ? segments[cell1.source_index()] : segments[cell2.source_index()];
-            coordinate_type dx = high(segment).x() - low(segment).x();
-            coordinate_type dy = high(segment).y() - low(segment).y();
+            coordinate_type dx = high(segment)(0) - low(segment)(0);
+            coordinate_type dy = high(segment)(1) - low(segment)(1);
             if ((low(segment) == origin) ^ cell1.contains_point()) {
                 direction.x(dy);
                 direction.y(-dx);
@@ -625,19 +625,19 @@ namespace Voronoi { namespace Internal {
                 direction.y(dx);
             }
         }
-        coordinate_type koef = bbox_max_size / (std::max)(fabs(direction.x()), fabs(direction.y()));
+        coordinate_type koef = bbox_max_size / (std::max)(fabs(direction(0)), fabs(direction(1)));
         if (edge.vertex0() == NULL) {
             clipped_edge->push_back(point_type(
-                origin.x() - direction.x() * koef,
-                origin.y() - direction.y() * koef));
+                origin(0) - direction(0) * koef,
+                origin(1) - direction(1) * koef));
         } else {
             clipped_edge->push_back(
                 point_type(edge.vertex0()->x(), edge.vertex0()->y()));
         }
         if (edge.vertex1() == NULL) {
             clipped_edge->push_back(point_type(
-                origin.x() + direction.x() * koef,
-                origin.y() + direction.y() * koef));
+                origin(0) + direction(0) * koef,
+                origin(1) + direction(1) * koef));
         } else {
             clipped_edge->push_back(
                 point_type(edge.vertex1()->x(), edge.vertex1()->y()));
@@ -676,10 +676,10 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d
     const bool          primaryEdgesOnly            = false;
 
     BoundingBox bbox = BoundingBox(lines);
-    bbox.min.x -= coord_t(1. / SCALING_FACTOR);
-    bbox.min.y -= coord_t(1. / SCALING_FACTOR);
-    bbox.max.x += coord_t(1. / SCALING_FACTOR);
-    bbox.max.y += coord_t(1. / SCALING_FACTOR);
+    bbox.min(0) -= coord_t(1. / SCALING_FACTOR);
+    bbox.min(1) -= coord_t(1. / SCALING_FACTOR);
+    bbox.max(0) += coord_t(1. / SCALING_FACTOR);
+    bbox.max(1) += coord_t(1. / SCALING_FACTOR);
 
     ::Slic3r::SVG svg(path, bbox);
 
@@ -689,7 +689,7 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d
 //    bbox.scale(1.2);
     // For clipping of half-lines to some reasonable value.
     // The line will then be clipped by the SVG viewer anyway.
-    const double bbox_dim_max = double(bbox.max.x - bbox.min.x) + double(bbox.max.y - bbox.min.y);
+    const double bbox_dim_max = double(bbox.max(0) - bbox.min(0)) + double(bbox.max(1) - bbox.min(1));
     // For the discretization of the Voronoi parabolic segments.
     const double discretization_step = 0.0005 * bbox_dim_max;
 
@@ -697,8 +697,8 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d
     std::vector<Voronoi::Internal::segment_type> segments;
     for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++ it)
         segments.push_back(Voronoi::Internal::segment_type(
-            Voronoi::Internal::point_type(double(it->a.x), double(it->a.y)), 
-            Voronoi::Internal::point_type(double(it->b.x), double(it->b.y))));
+            Voronoi::Internal::point_type(double(it->a(0)), double(it->a(1))), 
+            Voronoi::Internal::point_type(double(it->b(0)), double(it->b(1)))));
     
     // Color exterior edges.
     for (voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it)
@@ -712,13 +712,13 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d
     }
     // Draw the input polygon.
     for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it)
-        svg.draw(Line(Point(coord_t(it->a.x), coord_t(it->a.y)), Point(coord_t(it->b.x), coord_t(it->b.y))), inputSegmentColor, inputSegmentLineWidth);
+        svg.draw(Line(Point(coord_t(it->a(0)), coord_t(it->a(1))), Point(coord_t(it->b(0)), coord_t(it->b(1)))), inputSegmentColor, inputSegmentLineWidth);
 
 #if 1
     // Draw voronoi vertices.
     for (voronoi_diagram<double>::const_vertex_iterator it = vd.vertices().begin(); it != vd.vertices().end(); ++it)
         if (! internalEdgesOnly || it->color() != Voronoi::Internal::EXTERNAL_COLOR)
-            svg.draw(Point(coord_t(it->x()), coord_t(it->y())), voronoiPointColor, voronoiPointRadius);
+            svg.draw(Point(coord_t((*it)(0)), coord_t((*it)(1))), voronoiPointColor, voronoiPointRadius);
 
     for (voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) {
         if (primaryEdgesOnly && !it->is_primary())
@@ -743,7 +743,7 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d
                 color = voronoiLineColorSecondary;
         }
         for (std::size_t i = 0; i + 1 < samples.size(); ++i)
-            svg.draw(Line(Point(coord_t(samples[i].x()), coord_t(samples[i].y())), Point(coord_t(samples[i+1].x()), coord_t(samples[i+1].y()))), color, voronoiLineWidth);
+            svg.draw(Line(Point(coord_t(samples[i](0)), coord_t(samples[i](1))), Point(coord_t(samples[i+1](0)), coord_t(samples[i+1](1)))), color, voronoiLineWidth);
     }
 #endif
 
@@ -758,8 +758,8 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d
 template<typename T>
 T dist(const boost::polygon::point_data<T> &p1,const boost::polygon::point_data<T> &p2)
 {
-	T dx = p2.x() - p1.x();
-	T dy = p2.y() - p1.y();
+	T dx = p2(0) - p1(0);
+	T dy = p2(1) - p1(1);
 	return sqrt(dx*dx+dy*dy);
 }
 
@@ -770,11 +770,11 @@ inline point_type project_point_to_segment(segment_type &seg, point_type &px)
     typedef typename point_type::coordinate_type T;
     const point_type &p0 = low(seg);
     const point_type &p1 = high(seg);
-    const point_type  dir(p1.x()-p0.x(), p1.y()-p0.y());
-    const point_type  dproj(px.x()-p0.x(), px.y()-p0.y());
-    const T           t = (dir.x()*dproj.x() + dir.y()*dproj.y()) / (dir.x()*dir.x() + dir.y()*dir.y());
+    const point_type  dir(p1(0)-p0(0), p1(1)-p0(1));
+    const point_type  dproj(px(0)-p0(0), px(1)-p0(1));
+    const T           t = (dir(0)*dproj(0) + dir(1)*dproj(1)) / (dir(0)*dir(0) + dir(1)*dir(1));
     assert(t >= T(-1e-6) && t <= T(1. + 1e-6));
-    return point_type(p0.x() + t*dir.x(), p0.y() + t*dir.y());
+    return point_type(p0(0) + t*dir(0), p0(1) + t*dir(1));
 }
 
 template<typename VD, typename SEGMENTS>
@@ -828,8 +828,8 @@ public:
     Lines2VDSegments(const Lines &alines) : lines(alines) {}
     typename VD::segment_type operator[](size_t idx) const {
         return typename VD::segment_type(
-            typename VD::point_type(typename VD::coord_type(lines[idx].a.x), typename VD::coord_type(lines[idx].a.y)),
-            typename VD::point_type(typename VD::coord_type(lines[idx].b.x), typename VD::coord_type(lines[idx].b.y)));
+            typename VD::point_type(typename VD::coord_type(lines[idx].a(0)), typename VD::coord_type(lines[idx].a(1))),
+            typename VD::point_type(typename VD::coord_type(lines[idx].b(0)), typename VD::coord_type(lines[idx].b(1))));
     }
 private:
     const Lines &lines;
@@ -910,7 +910,7 @@ MedialAxis::build(ThickPolylines* polylines)
         assert(polyline.width.size() == polyline.points.size()*2 - 2);
         
         // prevent loop endpoints from being extended
-        if (polyline.first_point().coincides_with(polyline.last_point())) {
+        if (polyline.first_point() == polyline.last_point()) {
             polyline.endpoints.first = false;
             polyline.endpoints.second = false;
         }
@@ -1003,7 +1003,7 @@ MedialAxis::validate_edge(const VD::edge_type* edge)
     // this could maybe be optimized (checking inclusion of the endpoints
     // might give false positives as they might belong to the contour itself)
     if (this->expolygon != NULL) {
-        if (line.a.coincides_with(line.b)) {
+        if (line.a == line.b) {
             // in this case, contains(line) returns a false positive
             if (!this->expolygon->contains(line.a)) return false;
         } else {
@@ -1042,12 +1042,12 @@ MedialAxis::validate_edge(const VD::edge_type* edge)
         calculate the distance to that endpoint instead.  */
     
     coordf_t w0 = cell_r->contains_segment()
-        ? line.a.distance_to(segment_r)*2
-        : line.a.distance_to(this->retrieve_endpoint(cell_r))*2;
+        ? segment_r.distance_to(line.a)*2
+        : (this->retrieve_endpoint(cell_r) - line.a).cast<double>().norm()*2;
     
     coordf_t w1 = cell_l->contains_segment()
-        ? line.b.distance_to(segment_l)*2
-        : line.b.distance_to(this->retrieve_endpoint(cell_l))*2;
+        ? segment_l.distance_to(line.b)*2
+        : (this->retrieve_endpoint(cell_l) - line.b).cast<double>().norm()*2;
     
     if (cell_l->contains_segment() && cell_r->contains_segment()) {
         // calculate the relative angle between the two boundary segments
diff --git a/xs/src/libslic3r/Geometry.hpp b/xs/src/libslic3r/Geometry.hpp
index c2c3dc8b7..194534007 100644
--- a/xs/src/libslic3r/Geometry.hpp
+++ b/xs/src/libslic3r/Geometry.hpp
@@ -30,9 +30,9 @@ enum Orientation
 static inline Orientation orient(const Point &a, const Point &b, const Point &c)
 {
     // BOOST_STATIC_ASSERT(sizeof(coord_t) * 2 == sizeof(int64_t));
-    int64_t u = int64_t(b.x) * int64_t(c.y) - int64_t(b.y) * int64_t(c.x);
-    int64_t v = int64_t(a.x) * int64_t(c.y) - int64_t(a.y) * int64_t(c.x);
-    int64_t w = int64_t(a.x) * int64_t(b.y) - int64_t(a.y) * int64_t(b.x);
+    int64_t u = int64_t(b(0)) * int64_t(c(1)) - int64_t(b(1)) * int64_t(c(0));
+    int64_t v = int64_t(a(0)) * int64_t(c(1)) - int64_t(a(1)) * int64_t(c(0));
+    int64_t w = int64_t(a(0)) * int64_t(b(1)) - int64_t(a(1)) * int64_t(b(0));
     int64_t d = u - v + w;
     return (d > 0) ? ORIENTATION_CCW : ((d == 0) ? ORIENTATION_COLINEAR : ORIENTATION_CW);
 }
@@ -52,7 +52,7 @@ static inline bool is_ccw(const Polygon &poly)
     for (unsigned int i = 1; i < poly.points.size(); ++ i) {
         const Point &pmin = poly.points[imin];
         const Point &p    = poly.points[i];
-        if (p.x < pmin.x || (p.x == pmin.x && p.y < pmin.y))
+        if (p(0) < pmin(0) || (p(0) == pmin(0) && p(1) < pmin(1)))
             imin = i;
     }
 
@@ -66,26 +66,26 @@ static inline bool is_ccw(const Polygon &poly)
     return o == ORIENTATION_CCW;
 }
 
-inline bool ray_ray_intersection(const Pointf &p1, const Vectorf &v1, const Pointf &p2, const Vectorf &v2, Pointf &res)
+inline bool ray_ray_intersection(const Vec2d &p1, const Vec2d &v1, const Vec2d &p2, const Vec2d &v2, Vec2d &res)
 {
-    double denom = v1.x * v2.y - v2.x * v1.y;
+    double denom = v1(0) * v2(1) - v2(0) * v1(1);
     if (std::abs(denom) < EPSILON)
         return false;
-    double t = (v2.x * (p1.y - p2.y) - v2.y * (p1.x - p2.x)) / denom;
-    res.x = p1.x + t * v1.x;
-    res.y = p1.y + t * v1.y;
+    double t = (v2(0) * (p1(1) - p2(1)) - v2(1) * (p1(0) - p2(0))) / denom;
+    res(0) = p1(0) + t * v1(0);
+    res(1) = p1(1) + t * v1(1);
     return true;
 }
 
-inline bool segment_segment_intersection(const Pointf &p1, const Vectorf &v1, const Pointf &p2, const Vectorf &v2, Pointf &res)
+inline bool segment_segment_intersection(const Vec2d &p1, const Vec2d &v1, const Vec2d &p2, const Vec2d &v2, Vec2d &res)
 {
-    double denom = v1.x * v2.y - v2.x * v1.y;
+    double denom = v1(0) * v2(1) - v2(0) * v1(1);
     if (std::abs(denom) < EPSILON)
         // Lines are collinear.
         return false;
-    double s12_x = p1.x - p2.x;
-    double s12_y = p1.y - p2.y;
-    double s_numer = v1.x * s12_y - v1.y * s12_x;
+    double s12_x = p1(0) - p2(0);
+    double s12_y = p1(1) - p2(1);
+    double s_numer = v1(0) * s12_y - v1(1) * s12_x;
     bool   denom_is_positive = false;
     if (denom < 0.) {
         denom_is_positive = true;
@@ -95,7 +95,7 @@ inline bool segment_segment_intersection(const Pointf &p1, const Vectorf &v1, co
     if (s_numer < 0.)
         // Intersection outside of the 1st segment.
         return false;
-    double t_numer = v2.x * s12_y - v2.y * s12_x;
+    double t_numer = v2(0) * s12_y - v2(1) * s12_x;
     if (! denom_is_positive)
         t_numer = - t_numer;
     if (t_numer < 0. || s_numer > denom || t_numer > denom)
@@ -103,8 +103,8 @@ inline bool segment_segment_intersection(const Pointf &p1, const Vectorf &v1, co
         return false;
     // Intersection inside both of the segments.
     double t = t_numer / denom;
-    res.x = p1.x + t * v1.x;
-    res.y = p1.y + t * v1.y;
+    res(0) = p1(0) + t * v1(0);
+    res(1) = p1(1) + t * v1(1);
     return true;
 }
 
@@ -123,7 +123,7 @@ void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* ret
 double linint(double value, double oldmin, double oldmax, double newmin, double newmax);
 bool arrange(
     // input
-    size_t num_parts, const Pointf &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box, 
+    size_t num_parts, const Vec2d &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box, 
     // output
     Pointfs &positions);
 
diff --git a/xs/src/libslic3r/Layer.cpp b/xs/src/libslic3r/Layer.cpp
index 652bcdaa0..20e8f8ae1 100644
--- a/xs/src/libslic3r/Layer.cpp
+++ b/xs/src/libslic3r/Layer.cpp
@@ -168,8 +168,8 @@ void Layer::export_region_slices_to_svg(const char *path) const
         for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface)
             bbox.merge(get_extents(surface->expolygon));
     Point legend_size = export_surface_type_legend_to_svg_box_size();
-    Point legend_pos(bbox.min.x, bbox.max.y);
-    bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
+    Point legend_pos(bbox.min(0), bbox.max(1));
+    bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
 
     SVG svg(path, bbox);
     const float transparency = 0.5f;
@@ -194,8 +194,8 @@ void Layer::export_region_fill_surfaces_to_svg(const char *path) const
         for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface)
             bbox.merge(get_extents(surface->expolygon));
     Point legend_size = export_surface_type_legend_to_svg_box_size();
-    Point legend_pos(bbox.min.x, bbox.max.y);
-    bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
+    Point legend_pos(bbox.min(0), bbox.max(1));
+    bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
 
     SVG svg(path, bbox);
     const float transparency = 0.5f;
diff --git a/xs/src/libslic3r/LayerRegion.cpp b/xs/src/libslic3r/LayerRegion.cpp
index 68e17407e..afdc9c5a2 100644
--- a/xs/src/libslic3r/LayerRegion.cpp
+++ b/xs/src/libslic3r/LayerRegion.cpp
@@ -395,8 +395,8 @@ void LayerRegion::export_region_slices_to_svg(const char *path) const
     for (Surfaces::const_iterator surface = this->slices.surfaces.begin(); surface != this->slices.surfaces.end(); ++surface)
         bbox.merge(get_extents(surface->expolygon));
     Point legend_size = export_surface_type_legend_to_svg_box_size();
-    Point legend_pos(bbox.min.x, bbox.max.y);
-    bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
+    Point legend_pos(bbox.min(0), bbox.max(1));
+    bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
 
     SVG svg(path, bbox);
     const float transparency = 0.5f;
@@ -422,8 +422,8 @@ void LayerRegion::export_region_fill_surfaces_to_svg(const char *path) const
     for (Surfaces::const_iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface)
         bbox.merge(get_extents(surface->expolygon));
     Point legend_size = export_surface_type_legend_to_svg_box_size();
-    Point legend_pos(bbox.min.x, bbox.max.y);
-    bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
+    Point legend_pos(bbox.min(0), bbox.max(1));
+    bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
 
     SVG svg(path, bbox);
     const float transparency = 0.5f;
diff --git a/xs/src/libslic3r/Line.cpp b/xs/src/libslic3r/Line.cpp
index e9d5d7742..a29e4ce4e 100644
--- a/xs/src/libslic3r/Line.cpp
+++ b/xs/src/libslic3r/Line.cpp
@@ -7,133 +7,58 @@
 
 namespace Slic3r {
 
-std::string
-Line::wkt() const
+bool Line::intersection_infinite(const Line &other, Point* point) const
 {
-    std::ostringstream ss;
-    ss << "LINESTRING(" << this->a.x << " " << this->a.y << ","
-        << this->b.x << " " << this->b.y << ")";
-    return ss.str();
-}
-
-Line::operator Lines() const
-{
-    Lines lines;
-    lines.push_back(*this);
-    return lines;
-}
-
-Line::operator Polyline() const
-{
-    Polyline pl;
-    pl.points.push_back(this->a);
-    pl.points.push_back(this->b);
-    return pl;
-}
-
-void
-Line::scale(double factor)
-{
-    this->a.scale(factor);
-    this->b.scale(factor);
-}
-
-void
-Line::translate(double x, double y)
-{
-    this->a.translate(x, y);
-    this->b.translate(x, y);
-}
-
-void
-Line::rotate(double angle, const Point &center)
-{
-    this->a.rotate(angle, center);
-    this->b.rotate(angle, center);
-}
-
-void
-Line::reverse()
-{
-    std::swap(this->a, this->b);
-}
-
-double
-Line::length() const
-{
-    return this->a.distance_to(this->b);
-}
-
-Point
-Line::midpoint() const
-{
-    return Point((this->a.x + this->b.x) / 2.0, (this->a.y + this->b.y) / 2.0);
-}
-
-void
-Line::point_at(double distance, Point* point) const
-{
-    double len = this->length();
-    *point = this->a;
-    if (this->a.x != this->b.x)
-        point->x = this->a.x + (this->b.x - this->a.x) * distance / len;
-    if (this->a.y != this->b.y)
-        point->y = this->a.y + (this->b.y - this->a.y) * distance / len;
-}
-
-Point
-Line::point_at(double distance) const
-{
-    Point p;
-    this->point_at(distance, &p);
-    return p;
-}
-
-bool
-Line::intersection_infinite(const Line &other, Point* point) const
-{
-    Vector x = this->a.vector_to(other.a);
-    Vector d1 = this->vector();
-    Vector d2 = other.vector();
-
-    double cross = d1.x * d2.y - d1.y * d2.x;
-    if (std::fabs(cross) < EPSILON)
+    Vec2d a1 = this->a.cast<double>();
+    Vec2d a2 = other.a.cast<double>();
+    Vec2d v12 = (other.a - this->a).cast<double>();
+    Vec2d v1 = (this->b - this->a).cast<double>();
+    Vec2d v2 = (other.b - other.a).cast<double>();
+    double denom = cross2(v1, v2);
+    if (std::fabs(denom) < EPSILON)
         return false;
-
-    double t1 = (x.x * d2.y - x.y * d2.x)/cross;
-    point->x = this->a.x + d1.x * t1;
-    point->y = this->a.y + d1.y * t1;
+    double t1 = cross2(v12, v2) / denom;
+    *point = (a1 + t1 * v1).cast<coord_t>();
     return true;
 }
 
-bool
-Line::coincides_with(const Line &line) const
+/* distance to the closest point of line */
+double Line::distance_to(const Point &point) const
 {
-    return this->a.coincides_with(line.a) && this->b.coincides_with(line.b);
+    const Line   &line = *this;
+    const Vec2d   v  = (line.b - line.a).cast<double>();
+    const Vec2d   va = (point  - line.a).cast<double>();
+    const double  l2 = v.squaredNorm();  // avoid a sqrt
+    if (l2 == 0.0) 
+        // line.a == line.b case
+        return va.norm();
+    // Consider the line extending the segment, parameterized as line.a + t (line.b - line.a).
+    // We find projection of this point onto the line. 
+    // It falls where t = [(this-line.a) . (line.b-line.a)] / |line.b-line.a|^2
+    const double t = va.dot(v) / l2;
+    if (t < 0.0)      return va.norm();  // beyond the 'a' end of the segment
+    else if (t > 1.0) return (point - line.b).cast<double>().norm();  // beyond the 'b' end of the segment
+    return (t * v - va).norm();
 }
 
-double
-Line::distance_to(const Point &point) const
+double Line::perp_distance_to(const Point &point) const
 {
-    return point.distance_to(*this);
+    const Line  &line = *this;
+    const Vec2d  v  = (line.b - line.a).cast<double>();
+    const Vec2d  va = (point - line.a).cast<double>();
+    if (line.a == line.b)
+        return va.norm();
+    return std::abs(cross2(v, va)) / v.norm();
 }
 
-double
-Line::atan2_() const
-{
-    return atan2(this->b.y - this->a.y, this->b.x - this->a.x);
-}
-
-double
-Line::orientation() const
+double Line::orientation() const
 {
     double angle = this->atan2_();
     if (angle < 0) angle = 2*PI + angle;
     return angle;
 }
 
-double
-Line::direction() const
+double Line::direction() const
 {
     double atan2 = this->atan2_();
     return (fabs(atan2 - PI) < EPSILON) ? 0
@@ -141,108 +66,42 @@ Line::direction() const
         : atan2;
 }
 
-bool
-Line::parallel_to(double angle) const {
+bool Line::parallel_to(double angle) const
+{
     return Slic3r::Geometry::directions_parallel(this->direction(), angle);
 }
 
-bool
-Line::parallel_to(const Line &line) const {
-    return this->parallel_to(line.direction());
-}
-
-Vector
-Line::vector() const
+bool Line::intersection(const Line &l2, Point *intersection) const
 {
-    return Vector(this->b.x - this->a.x, this->b.y - this->a.y);
-}
-
-Vector
-Line::normal() const
-{
-    return Vector((this->b.y - this->a.y), -(this->b.x - this->a.x));
-}
-
-void
-Line::extend_end(double distance)
-{
-    // relocate last point by extending the segment by the specified length
-    Line line = *this;
-    line.reverse();
-    this->b = line.point_at(-distance);
-}
-
-void
-Line::extend_start(double distance)
-{
-    // relocate first point by extending the first segment by the specified length
-    this->a = this->point_at(-distance);
-}
-
-bool
-Line::intersection(const Line& line, Point* intersection) const
-{
-    double denom = ((double)(line.b.y - line.a.y)*(this->b.x - this->a.x)) -
-                   ((double)(line.b.x - line.a.x)*(this->b.y - this->a.y));
-
-    double nume_a = ((double)(line.b.x - line.a.x)*(this->a.y - line.a.y)) -
-                    ((double)(line.b.y - line.a.y)*(this->a.x - line.a.x));
-
-    double nume_b = ((double)(this->b.x - this->a.x)*(this->a.y - line.a.y)) -
-                    ((double)(this->b.y - this->a.y)*(this->a.x - line.a.x));
-    
-    if (fabs(denom) < EPSILON) {
-        if (fabs(nume_a) < EPSILON && fabs(nume_b) < EPSILON) {
-            return false; // coincident
-        }
-        return false; // parallel
-    }
-
-    double ua = nume_a / denom;
-    double ub = nume_b / denom;
-
-    if (ua >= 0 && ua <= 1.0f && ub >= 0 && ub <= 1.0f)
-    {
+    const Line  &l1  = *this;
+    const Vec2d  v1  = (l1.b - l1.a).cast<double>();
+    const Vec2d  v2  = (l2.b - l2.a).cast<double>();
+    const Vec2d  v12 = (l1.a - l2.a).cast<double>();
+    double       denom  = cross2(v1, v2);
+    double       nume_a = cross2(v2, v12);
+    double       nume_b = cross2(v1, v12);
+    if (fabs(denom) < EPSILON)
+#if 0
+        // Lines are collinear. Return true if they are coincident (overlappign).
+        return ! (fabs(nume_a) < EPSILON && fabs(nume_b) < EPSILON);
+#else
+        return false;
+#endif
+    double t1 = nume_a / denom;
+    double t2 = nume_b / denom;
+    if (t1 >= 0 && t1 <= 1.0f && t2 >= 0 && t2 <= 1.0f) {
         // Get the intersection point.
-        intersection->x = this->a.x + ua*(this->b.x - this->a.x);
-        intersection->y = this->a.y + ua*(this->b.y - this->a.y);
+        (*intersection) = (l1.a.cast<double>() + t1 * v1).cast<coord_t>();
         return true;
     }
-    
     return false;  // not intersecting
 }
 
-double
-Line::ccw(const Point& point) const
+Vec3d Linef3::intersect_plane(double z) const
 {
-    return point.ccw(*this);
-}
-
-double Line3::length() const
-{
-    return a.distance_to(b);
-}
-
-Vector3 Line3::vector() const
-{
-    return Vector3(b.x - a.x, b.y - a.y, b.z - a.z);
-}
-
-Pointf3
-Linef3::intersect_plane(double z) const
-{
-    return Pointf3(
-        this->a.x + (this->b.x - this->a.x) * (z - this->a.z) / (this->b.z - this->a.z),
-        this->a.y + (this->b.y - this->a.y) * (z - this->a.z) / (this->b.z - this->a.z),
-        z
-    );
-}
-
-void
-Linef3::scale(double factor)
-{
-    this->a.scale(factor);
-    this->b.scale(factor);
+    auto   v = (this->b - this->a).cast<double>();
+    double t = (z - this->a(2)) / v(2);
+    return Vec3d(this->a(0) + v(0) * t, this->a(1) + v(1) * t, z);
 }
 
 }
diff --git a/xs/src/libslic3r/Line.hpp b/xs/src/libslic3r/Line.hpp
index 7dd1a83d5..5b77a4b61 100644
--- a/xs/src/libslic3r/Line.hpp
+++ b/xs/src/libslic3r/Line.hpp
@@ -18,81 +18,80 @@ typedef std::vector<ThickLine> ThickLines;
 class Line
 {
 public:
-    Point a;
-    Point b;
-    Line() {};
-    explicit Line(Point _a, Point _b): a(_a), b(_b) {};
-    std::string wkt() const;
-    operator Lines() const;
-    operator Polyline() const;
-    void scale(double factor);
-    void translate(double x, double y);
-    void rotate(double angle, const Point &center);
-    void reverse();
-    double length() const;
-    Point midpoint() const;
-    void point_at(double distance, Point* point) const;
-    Point point_at(double distance) const;
-    bool intersection_infinite(const Line &other, Point* point) const;
-    bool coincides_with(const Line &line) const;
+    Line() {}
+    Line(const Point& _a, const Point& _b) : a(_a), b(_b) {}
+    explicit operator Lines() const { Lines lines; lines.emplace_back(*this); return lines; }
+    void   scale(double factor) { this->a *= factor; this->b *= factor; }
+    void   translate(double x, double y) { Vector v(x, y); this->a += v; this->b += v; }
+    void   rotate(double angle, const Point &center) { this->a.rotate(angle, center); this->b.rotate(angle, center); }
+    void   reverse() { std::swap(this->a, this->b); }
+    double length() const { return (b - a).cast<double>().norm(); }
+    Point  midpoint() const { return (this->a + this->b) / 2; }
+    bool   intersection_infinite(const Line &other, Point* point) const;
+    bool   operator==(const Line &rhs) const { return this->a == rhs.a && this->b == rhs.b; }
     double distance_to(const Point &point) const;
-    bool parallel_to(double angle) const;
-    bool parallel_to(const Line &line) const;
-    double atan2_() const;
+    double perp_distance_to(const Point &point) const;
+    bool   parallel_to(double angle) const;
+    bool   parallel_to(const Line &line) const { return this->parallel_to(line.direction()); }
+    double atan2_() const { return atan2(this->b(1) - this->a(1), this->b(0) - this->a(0)); }
     double orientation() const;
     double direction() const;
-    Vector vector() const;
-    Vector normal() const;
-    void extend_end(double distance);
-    void extend_start(double distance);
-    bool intersection(const Line& line, Point* intersection) const;
-    double ccw(const Point& point) const;
+    Vector vector() const { return this->b - this->a; }
+    Vector normal() const { return Vector((this->b(1) - this->a(1)), -(this->b(0) - this->a(0))); }
+    bool   intersection(const Line& line, Point* intersection) const;
+    double ccw(const Point& point) const { return point.ccw(*this); }
+
+    Point a;
+    Point b;
 };
 
 class ThickLine : public Line
 {
-    public:
-    coordf_t a_width, b_width;
-    
-    ThickLine() : a_width(0), b_width(0) {};
-    ThickLine(Point _a, Point _b) : Line(_a, _b), a_width(0), b_width(0) {};
+public:
+    ThickLine() : a_width(0), b_width(0) {}
+    ThickLine(const Point& a, const Point& b) : Line(a, b), a_width(0), b_width(0) {}
+    ThickLine(const Point& a, const Point& b, double wa, double wb) : Line(a, b), a_width(wa), b_width(wb) {}
+
+    double a_width, b_width;
 };
 
 class Line3
 {
 public:
-    Point3 a;
-    Point3 b;
+    Line3() : a(Vec3crd::Zero()), b(Vec3crd::Zero()) {}
+    Line3(const Vec3crd& _a, const Vec3crd& _b) : a(_a), b(_b) {}
 
-    Line3() {}
-    Line3(const Point3& _a, const Point3& _b) : a(_a), b(_b) {}
+    double  length() const { return (this->a - this->b).cast<double>().norm(); }
+    Vec3crd vector() const { return this->b - this->a; }
 
-    double length() const;
-    Vector3 vector() const;
+    Vec3crd a;
+    Vec3crd b;
 };
 
 class Linef
 {
-    public:
-    Pointf a;
-    Pointf b;
-    Linef() {};
-    explicit Linef(Pointf _a, Pointf _b): a(_a), b(_b) {};
+public:
+    Linef() : a(Vec2d::Zero()), b(Vec2d::Zero()) {}
+    Linef(const Vec2d& _a, const Vec2d& _b) : a(_a), b(_b) {}
+
+    Vec2d a;
+    Vec2d b;
 };
 
 class Linef3
 {
-    public:
-    Pointf3 a;
-    Pointf3 b;
-    Linef3() {};
-    explicit Linef3(Pointf3 _a, Pointf3 _b): a(_a), b(_b) {};
-    Pointf3 intersect_plane(double z) const;
-    void scale(double factor);
+public:
+    Linef3() : a(Vec3d::Zero()), b(Vec3d::Zero()) {}
+    Linef3(const Vec3d& _a, const Vec3d& _b) : a(_a), b(_b) {}
 
-    double length() const { return this->a.distance_to(this->b); }
-    Vectorf3 vector() const { return Vectorf3(this->b.x - this->a.x, this->b.y - this->a.y, this->b.z - this->a.z); }
-    Vectorf3 unit_vector() const { return (length() == 0.0) ? Vectorf3(0.0, 0.0, 0.0) : normalize(vector()); }
+    Vec3d   intersect_plane(double z) const;
+    void    scale(double factor) { this->a *= factor; this->b *= factor; }
+    Vec3d   vector() const { return this->b - this->a; }
+    Vec3d   unit_vector() const { return (length() == 0.0) ? Vec3d::Zero() : vector().normalized(); }
+    double  length() const { return vector().norm(); }
+
+    Vec3d a;
+    Vec3d b;
 };
 
 } // namespace Slic3r
diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp
index 23d447748..d046a8ef2 100644
--- a/xs/src/libslic3r/Model.cpp
+++ b/xs/src/libslic3r/Model.cpp
@@ -17,11 +17,6 @@
 #include "SVG.hpp"
 #include <Eigen/Dense>
 
-static const float UNIT_MATRIX[] = { 1.0f, 0.0f, 0.0f, 0.0f,
-                                     0.0f, 1.0f, 0.0f, 0.0f,
-                                     0.0f, 0.0f, 1.0f, 0.0f,
-                                     0.0f, 0.0f, 0.0f, 1.0f };
-
 namespace Slic3r {
 
     unsigned int Model::s_auto_extruder_id = 1;
@@ -240,7 +235,7 @@ BoundingBoxf3 Model::bounding_box() const
     return bb;
 }
 
-void Model::center_instances_around_point(const Pointf &point)
+void Model::center_instances_around_point(const Vec2d &point)
 {
 //    BoundingBoxf3 bb = this->bounding_box();
     BoundingBoxf3 bb;
@@ -248,12 +243,10 @@ void Model::center_instances_around_point(const Pointf &point)
         for (size_t i = 0; i < o->instances.size(); ++ i)
             bb.merge(o->instance_bounding_box(i, false));
 
-    Sizef3 size = bb.size();
-    coordf_t shift_x = -bb.min.x + point.x - size.x/2;
-    coordf_t shift_y = -bb.min.y + point.y - size.y/2;
+    Vec2d shift = point - 0.5 * to_2d(bb.size()) - to_2d(bb.min);
     for (ModelObject *o : this->objects) {
         for (ModelInstance *i : o->instances)
-            i->offset.translate(shift_x, shift_y);
+            i->offset += shift;
         o->invalidate_bounding_box();
     }
 }
@@ -308,8 +301,8 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
         for (size_t i = 0; i < o->instances.size(); ++ i) {
             // an accurate snug bounding box around the transformed mesh.
             BoundingBoxf3 bbox(o->instance_bounding_box(i, true));
-            instance_sizes.push_back(bbox.size());
-            instance_centers.push_back(bbox.center());
+            instance_sizes.emplace_back(to_2d(bbox.size()));
+            instance_centers.emplace_back(to_2d(bbox.center()));
         }
 
     Pointfs positions;
@@ -331,7 +324,7 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
 // Duplicate the entire model preserving instance relative positions.
 void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb)
 {
-    Pointfs model_sizes(copies_num-1, this->bounding_box().size());
+    Pointfs model_sizes(copies_num-1, to_2d(this->bounding_box().size()));
     Pointfs positions;
     if (! _arrange(model_sizes, dist, bb, positions))
         CONFESS("Cannot duplicate part as the resulting objects would not fit on the print bed.\n");
@@ -342,9 +335,9 @@ void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb)
         // make a copy of the pointers in order to avoid recursion when appending their copies
         ModelInstancePtrs instances = o->instances;
         for (const ModelInstance *i : instances) {
-            for (const Pointf &pos : positions) {
+            for (const Vec2d &pos : positions) {
                 ModelInstance *instance = o->add_instance(*i);
-                instance->offset.translate(pos);
+                instance->offset += pos;
             }
         }
         o->invalidate_bounding_box();
@@ -374,13 +367,13 @@ void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist)
     ModelObject* object = this->objects.front();
     object->clear_instances();
 
-    Sizef3 size = object->bounding_box().size();
+    Vec3d size = object->bounding_box().size();
 
     for (size_t x_copy = 1; x_copy <= x; ++x_copy) {
         for (size_t y_copy = 1; y_copy <= y; ++y_copy) {
             ModelInstance* instance = object->add_instance();
-            instance->offset.x = (size.x + dist) * (x_copy-1);
-            instance->offset.y = (size.y + dist) * (y_copy-1);
+            instance->offset(0) = (size(0) + dist) * (x_copy-1);
+            instance->offset(1) = (size(1) + dist) * (y_copy-1);
         }
     }
 }
@@ -394,7 +387,7 @@ bool Model::looks_like_multipart_object() const
         if (obj->volumes.size() > 1 || obj->config.keys().size() > 1)
             return false;
         for (const ModelVolume *vol : obj->volumes) {
-            double zmin_this = vol->mesh.bounding_box().min.z;
+            double zmin_this = vol->mesh.bounding_box().min(2);
             if (zmin == std::numeric_limits<double>::max())
                 zmin = zmin_this;
             else if (std::abs(zmin - zmin_this) > EPSILON)
@@ -438,13 +431,13 @@ void Model::adjust_min_z()
     if (objects.empty())
         return;
 
-    if (bounding_box().min.z < 0.0)
+    if (bounding_box().min(2) < 0.0)
     {
         for (ModelObject* obj : objects)
         {
             if (obj != nullptr)
             {
-                coordf_t obj_min_z = obj->bounding_box().min.z;
+                coordf_t obj_min_z = obj->bounding_box().min(2);
                 if (obj_min_z < 0.0)
                     obj->translate(0.0, 0.0, -obj_min_z);
             }
@@ -677,25 +670,22 @@ void ModelObject::center_around_origin()
         if (! v->modifier)
 			bb.merge(v->mesh.bounding_box());
     
-    // first align to origin on XYZ
-    Vectorf3 vector(-bb.min.x, -bb.min.y, -bb.min.z);
+    // First align to origin on XYZ, then center it on XY.
+    Vec3d size = bb.size();
+    size(2) = 0.;
+    Vec3d shift3 = - bb.min - 0.5 * size;
+    // Unaligned vector, for the Rotation2D to work on Visual Studio 2013.
+    Eigen::Vector2d shift2 = to_2d(shift3);
     
-    // then center it on XY
-    Sizef3 size = bb.size();
-    vector.x -= size.x/2;
-    vector.y -= size.y/2;
-    
-    this->translate(vector);
-    this->origin_translation.translate(vector);
+    this->translate(shift3);
+    this->origin_translation += shift3;
     
     if (!this->instances.empty()) {
         for (ModelInstance *i : this->instances) {
             // apply rotation and scaling to vector as well before translating instance,
             // in order to leave final position unaltered
-            Vectorf3 v = vector.negative();
-            v.rotate(i->rotation);
-            v.scale(i->scaling_factor);
-            i->offset.translate(v.x, v.y);
+            Eigen::Rotation2Dd rot(i->rotation);
+            i->offset -= rot * shift2 * i->scaling_factor;
         }
         this->invalidate_bounding_box();
     }
@@ -713,7 +703,7 @@ void ModelObject::translate(coordf_t x, coordf_t y, coordf_t z)
         m_bounding_box.translate(x, y, z);
 }
 
-void ModelObject::scale(const Pointf3 &versor)
+void ModelObject::scale(const Vec3d &versor)
 {
     for (ModelVolume *v : this->volumes)
     {
@@ -721,7 +711,7 @@ void ModelObject::scale(const Pointf3 &versor)
         v->m_convex_hull.scale(versor);
     }
     // reset origin translation since it doesn't make sense anymore
-    this->origin_translation = Pointf3(0,0,0);
+    this->origin_translation = Vec3d::Zero();
     this->invalidate_bounding_box();
 }
 
@@ -735,7 +725,7 @@ void ModelObject::rotate(float angle, const Axis &axis)
 
     center_around_origin();
 
-    this->origin_translation = Pointf3(0, 0, 0);
+    this->origin_translation = Vec3d::Zero();
     this->invalidate_bounding_box();
 }
 
@@ -750,8 +740,8 @@ void ModelObject::transform(const float* matrix3x4)
         v->m_convex_hull.transform(matrix3x4);
     }
 
-    origin_translation = Pointf3(0.0, 0.0, 0.0);
-    invalidate_bounding_box();
+    this->origin_translation = Vec3d::Zero();
+    this->invalidate_bounding_box();
 }
 
 void ModelObject::mirror(const Axis &axis)
@@ -762,7 +752,7 @@ void ModelObject::mirror(const Axis &axis)
         v->m_convex_hull.mirror(axis);
     }
 
-    this->origin_translation = Pointf3(0, 0, 0);
+    this->origin_translation = Vec3d::Zero();
     this->invalidate_bounding_box();
 }
 
@@ -872,14 +862,12 @@ void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_
         {
             for (ModelInstance* inst : this->instances)
             {
-                std::vector<float> world_mat(UNIT_MATRIX, std::end(UNIT_MATRIX));
-                Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
-                m.translate(Eigen::Vector3f((float)inst->offset.x, (float)inst->offset.y, 0.0f));
-                m.rotate(Eigen::AngleAxisf(inst->rotation, Eigen::Vector3f::UnitZ()));
+                Transform3d m = Transform3d::Identity();
+                m.translate(Vec3d(inst->offset(0), inst->offset(1), 0.0));
+                m.rotate(Eigen::AngleAxisd(inst->rotation, Vec3d::UnitZ()));
                 m.scale(inst->scaling_factor);
-                ::memcpy((void*)world_mat.data(), (const void*)m.data(), 16 * sizeof(float));
 
-                BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(world_mat);
+                BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(m);
 
                 if (print_volume.contains(bb))
                     inst->print_volume_state = ModelInstance::PVS_Inside;
@@ -901,16 +889,16 @@ void ModelObject::print_info() const
     TriangleMesh mesh = this->raw_mesh();
     mesh.check_topology();
     BoundingBoxf3 bb = mesh.bounding_box();
-    Sizef3 size = bb.size();
-    cout << "size_x = " << size.x << endl;
-    cout << "size_y = " << size.y << endl;
-    cout << "size_z = " << size.z << endl;
-    cout << "min_x = " << bb.min.x << endl;
-    cout << "min_y = " << bb.min.y << endl;
-    cout << "min_z = " << bb.min.z << endl;
-    cout << "max_x = " << bb.max.x << endl;
-    cout << "max_y = " << bb.max.y << endl;
-    cout << "max_z = " << bb.max.z << endl;
+    Vec3d size = bb.size();
+    cout << "size_x = " << size(0) << endl;
+    cout << "size_y = " << size(1) << endl;
+    cout << "size_z = " << size(2) << endl;
+    cout << "min_x = " << bb.min(0) << endl;
+    cout << "min_y = " << bb.min(1) << endl;
+    cout << "min_z = " << bb.min(2) << endl;
+    cout << "max_x = " << bb.max(0) << endl;
+    cout << "max_y = " << bb.max(1) << endl;
+    cout << "max_z = " << bb.max(2) << endl;
     cout << "number_of_facets = " << mesh.stl.stats.number_of_facets  << endl;
     cout << "manifold = "   << (mesh.is_manifold() ? "yes" : "no") << endl;
     
@@ -1011,7 +999,7 @@ void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) cons
     mesh->rotate_z(this->rotation);                 // rotate around mesh origin
     mesh->scale(this->scaling_factor);              // scale around mesh origin
     if (!dont_translate)
-        mesh->translate(this->offset.x, this->offset.y, 0);
+        mesh->translate(this->offset(0), this->offset(1), 0);
 }
 
 BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mesh, bool dont_translate) const
@@ -1023,30 +1011,20 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes
     for (int i = 0; i < mesh->stl.stats.number_of_facets; ++ i) {
         const stl_facet &facet = mesh->stl.facet_start[i];
         for (int j = 0; j < 3; ++ j) {
-            stl_vertex v = facet.vertex[j];
-            double xold = v.x;
-            double yold = v.y;
-            v.x = float(c * xold - s * yold);
-            v.y = float(s * xold + c * yold);
-            bbox.merge(Pointf3(v.x, v.y, v.z));
+            const stl_vertex &v = facet.vertex[j];
+			bbox.merge(Vec3d(c * v(0) - s * v(1), s * v(0) + c * v(1), v(2)));
         }
     }
     if (! empty(bbox)) {
         // Scale the bounding box uniformly.
         if (std::abs(this->scaling_factor - 1.) > EPSILON) {
-            bbox.min.x *= float(this->scaling_factor);
-            bbox.min.y *= float(this->scaling_factor);
-            bbox.min.z *= float(this->scaling_factor);
-            bbox.max.x *= float(this->scaling_factor);
-            bbox.max.y *= float(this->scaling_factor);
-            bbox.max.z *= float(this->scaling_factor);
+            bbox.min *= this->scaling_factor;
+			bbox.max *= this->scaling_factor;
         }
         // Translate the bounding box.
         if (! dont_translate) {
-            bbox.min.x += float(this->offset.x);
-            bbox.min.y += float(this->offset.y);
-            bbox.max.x += float(this->offset.x);
-            bbox.max.y += float(this->offset.y);
+            Eigen::Map<Vec2d>(bbox.min.data()) += this->offset;
+            Eigen::Map<Vec2d>(bbox.max.data()) += this->offset;
         }
     }
     return bbox;
@@ -1054,16 +1032,13 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes
 
 BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
 {
-    Eigen::Transform<float, 3, Eigen::Affine> matrix = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
+    Transform3d matrix = Transform3d::Identity();
     if (!dont_translate)
-        matrix.translate(Eigen::Vector3f((float)offset.x, (float)offset.y, 0.0f));
+        matrix.translate(Vec3d(offset(0), offset(1), 0.0));
 
-    matrix.rotate(Eigen::AngleAxisf(rotation, Eigen::Vector3f::UnitZ()));
+    matrix.rotate(Eigen::AngleAxisd(rotation, Vec3d::UnitZ()));
     matrix.scale(scaling_factor);
-
-    std::vector<float> m(16, 0.0f);
-    ::memcpy((void*)m.data(), (const void*)matrix.data(), 16 * sizeof(float));
-    return bbox.transformed(m);
+    return bbox.transformed(matrix);
 }
 
 void ModelInstance::transform_polygon(Polygon* polygon) const
diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp
index 23af9fb1c..468e6f833 100644
--- a/xs/src/libslic3r/Model.hpp
+++ b/xs/src/libslic3r/Model.hpp
@@ -84,7 +84,7 @@ public:
         center_around_origin() method. Callers might want to apply the same translation
         to new volumes before adding them to this object in order to preserve alignment
         when user expects that. */
-    Pointf3                 origin_translation;
+    Vec3d                   origin_translation;
     
     Model* get_model() const { return m_model; };
     
@@ -117,9 +117,9 @@ public:
     // A snug bounding box around the transformed non-modifier object volumes.
     BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
     void center_around_origin();
-    void translate(const Vectorf3 &vector) { this->translate(vector.x, vector.y, vector.z); }
+    void translate(const Vec3d &vector) { this->translate(vector(0), vector(1), vector(2)); }
     void translate(coordf_t x, coordf_t y, coordf_t z);
-    void scale(const Pointf3 &versor);
+    void scale(const Vec3d &versor);
     void rotate(float angle, const Axis &axis);
     void transform(const float* matrix3x4);
     void mirror(const Axis &axis);
@@ -135,7 +135,7 @@ public:
     void print_info() const;
     
 private:        
-    ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), m_bounding_box_valid(false) {}
+    ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {}
     ModelObject(Model *model, const ModelObject &other, bool copy_volumes = true);
     ModelObject& operator= (ModelObject other);
     void swap(ModelObject &other);
@@ -224,9 +224,10 @@ public:
 
     friend class ModelObject;
 
+//    Transform3d     transform;
     double rotation;            // Rotation around the Z axis, in radians around mesh center point
     double scaling_factor;
-    Pointf offset;              // in unscaled coordinates
+    Vec2d offset;              // in unscaled coordinates
     
     // flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
     EPrintVolumeState print_volume_state;
@@ -248,7 +249,7 @@ private:
     // Parent object, owning this instance.
     ModelObject* object;
 
-    ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object), print_volume_state(PVS_Inside) {}
+    ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), offset(Vec2d::Zero()), object(object), print_volume_state(PVS_Inside) {}
     ModelInstance(ModelObject *object, const ModelInstance &other) :
         rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object), print_volume_state(PVS_Inside) {}
 };
@@ -299,7 +300,7 @@ public:
     bool add_default_instances();
     // Returns approximate axis aligned bounding box of this model
     BoundingBoxf3 bounding_box() const;
-    void center_instances_around_point(const Pointf &point);
+    void center_instances_around_point(const Vec2d &point);
     void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
     TriangleMesh mesh() const;
     bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL);
diff --git a/xs/src/libslic3r/ModelArrange.hpp b/xs/src/libslic3r/ModelArrange.hpp
index f2d399ac6..db18e6731 100644
--- a/xs/src/libslic3r/ModelArrange.hpp
+++ b/xs/src/libslic3r/ModelArrange.hpp
@@ -44,11 +44,11 @@ std::string toString(const Model& model, bool holes = true) {
                 ss << "\t\t{\n";
 
                 for(auto v : expoly.contour.points) ss << "\t\t\t{"
-                                                    << v.x << ", "
-                                                    << v.y << "},\n";
+                                                    << v(0) << ", "
+                                                    << v(1) << "},\n";
                 {
                     auto v = expoly.contour.points.front();
-                    ss << "\t\t\t{" << v.x << ", " << v.y << "},\n";
+                    ss << "\t\t\t{" << v(0) << ", " << v(1) << "},\n";
                 }
                 ss << "\t\t},\n";
 
@@ -57,11 +57,11 @@ std::string toString(const Model& model, bool holes = true) {
                 if(holes) for(auto h : expoly.holes) {
                     ss << "\t\t\t{\n";
                     for(auto v : h.points) ss << "\t\t\t\t{"
-                                           << v.x << ", "
-                                           << v.y << "},\n";
+                                           << v(0) << ", "
+                                           << v(1) << "},\n";
                     {
                         auto v = h.points.front();
-                        ss << "\t\t\t\t{" << v.x << ", " << v.y << "},\n";
+                        ss << "\t\t\t\t{" << v(0) << ", " << v(1) << "},\n";
                     }
                     ss << "\t\t\t},\n";
                 }
@@ -427,8 +427,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
                     if(item.vertexCount() > 3) {
                         item.rotation(objinst->rotation);
                         item.translation( {
-                            ClipperLib::cInt(objinst->offset.x/SCALING_FACTOR),
-                            ClipperLib::cInt(objinst->offset.y/SCALING_FACTOR)
+                            ClipperLib::cInt(objinst->offset(0)/SCALING_FACTOR),
+                            ClipperLib::cInt(objinst->offset(1)/SCALING_FACTOR)
                         });
                         ret.emplace_back(objinst, item);
                     }
@@ -468,7 +468,7 @@ void applyResult(
         // appropriately
         auto off = item.translation();
         Radians rot = item.rotation();
-        Pointf foff(off.X*SCALING_FACTOR + batch_offset,
+        Vec2d foff(off.X*SCALING_FACTOR + batch_offset,
                     off.Y*SCALING_FACTOR);
 
         // write the tranformation data into the model instance
@@ -528,12 +528,12 @@ bool arrange(Model &model, coordf_t min_obj_distance,
     BoundingBox bbb(bed.points);
 
     auto binbb = Box({
-                         static_cast<libnest2d::Coord>(bbb.min.x),
-                         static_cast<libnest2d::Coord>(bbb.min.y)
+                         static_cast<libnest2d::Coord>(bbb.min(0)),
+                         static_cast<libnest2d::Coord>(bbb.min(1))
                      },
                      {
-                         static_cast<libnest2d::Coord>(bbb.max.x),
-                         static_cast<libnest2d::Coord>(bbb.max.y)
+                         static_cast<libnest2d::Coord>(bbb.max(0)),
+                         static_cast<libnest2d::Coord>(bbb.max(1))
                      });
 
     switch(bedhint) {
diff --git a/xs/src/libslic3r/MotionPlanner.cpp b/xs/src/libslic3r/MotionPlanner.cpp
index e8605d68c..ff3475ed8 100644
--- a/xs/src/libslic3r/MotionPlanner.cpp
+++ b/xs/src/libslic3r/MotionPlanner.cpp
@@ -58,7 +58,7 @@ Polyline MotionPlanner::shortest_path(const Point &from, const Point &to)
 {
     // If we have an empty configuration space, return a straight move.
     if (m_islands.empty())
-        return Line(from, to);
+        return Polyline(from, to);
     
     // Are both points in the same island?
     int island_idx_from = -1;
@@ -74,7 +74,7 @@ Polyline MotionPlanner::shortest_path(const Point &from, const Point &to)
             // Since both points are in the same island, is a direct move possible?
             // If so, we avoid generating the visibility environment.
             if (island.m_island.contains(Line(from, to)))
-                return Line(from, to);
+                return Polyline(from, to);
             // Both points are inside a single island, but the straight line crosses the island boundary.
             island_idx = idx;
             break;
@@ -90,7 +90,7 @@ Polyline MotionPlanner::shortest_path(const Point &from, const Point &to)
     if (env.m_env.expolygons.empty()) {
         // if this environment is empty (probably because it's too small), perform straight move
         // and avoid running the algorithms on empty dataset
-        return Line(from, to);
+        return Polyline(from, to);
     }
     
     // Now check whether points are inside the environment.
@@ -224,7 +224,7 @@ const MotionPlannerGraph& MotionPlanner::init_graph(int island_idx)
                 else
                     v1_idx = i_v1->second;
                 // Euclidean distance is used as weight for the graph edge
-                graph->add_edge(v0_idx, v1_idx, p0.distance_to(p1));
+                graph->add_edge(v0_idx, v1_idx, (p1 - p0).cast<double>().norm());
             }
         }
     }
@@ -238,7 +238,7 @@ static inline size_t nearest_waypoint_index(const Point &start_point, const Poin
     size_t idx = size_t(-1);
     double dmin = std::numeric_limits<double>::infinity();
     for (const Point &p : middle_points) {
-        double d = start_point.distance_to(p) + p.distance_to(end_point);
+        double d = (p - start_point).cast<double>().norm() + (end_point - p).cast<double>().norm();
         if (d < dmin) {
             idx  = &p - middle_points.data();
             dmin = d;
diff --git a/xs/src/libslic3r/MultiPoint.cpp b/xs/src/libslic3r/MultiPoint.cpp
index 2e65492cd..f44897a04 100644
--- a/xs/src/libslic3r/MultiPoint.cpp
+++ b/xs/src/libslic3r/MultiPoint.cpp
@@ -8,59 +8,52 @@ MultiPoint::operator Points() const
     return this->points;
 }
 
-void
-MultiPoint::scale(double factor)
+void MultiPoint::scale(double factor)
 {
-    for (Points::iterator it = points.begin(); it != points.end(); ++it) {
-        (*it).scale(factor);
-    }
+    for (Point &pt : points)
+        pt *= factor;
 }
 
-void
-MultiPoint::translate(double x, double y)
+void MultiPoint::translate(double x, double y)
 {
-    for (Points::iterator it = points.begin(); it != points.end(); ++it) {
-        (*it).translate(x, y);
-    }
+    Vector v(x, y);
+    for (Point &pt : points)
+        pt += v;
 }
 
-void
-MultiPoint::translate(const Point &vector)
+void MultiPoint::translate(const Point &v)
 {
-    this->translate(vector.x, vector.y);
+    for (Point &pt : points)
+        pt += v;
 }
 
 void MultiPoint::rotate(double cos_angle, double sin_angle)
 {
     for (Point &pt : this->points) {
-        double cur_x = double(pt.x);
-        double cur_y = double(pt.y);
-        pt.x = coord_t(round(cos_angle * cur_x - sin_angle * cur_y));
-        pt.y = coord_t(round(cos_angle * cur_y + sin_angle * cur_x));
+        double cur_x = double(pt(0));
+        double cur_y = double(pt(1));
+        pt(0) = coord_t(round(cos_angle * cur_x - sin_angle * cur_y));
+        pt(1) = coord_t(round(cos_angle * cur_y + sin_angle * cur_x));
     }
 }
 
-void
-MultiPoint::rotate(double angle, const Point &center)
+void MultiPoint::rotate(double angle, const Point &center)
 {
     double s = sin(angle);
     double c = cos(angle);
-    for (Points::iterator it = points.begin(); it != points.end(); ++it) {
-        double dx = double(it->x - center.x);
-        double dy = double(it->y - center.y);
-        it->x = (coord_t)round(double(center.x) + c * dx - s * dy);
-        it->y = (coord_t)round(double(center.y) + c * dy + s * dx);
+    for (Point &pt : points) {
+        Vec2crd v(pt - center);
+        pt(0) = (coord_t)round(double(center(0)) + c * v[0] - s * v[1]);
+        pt(1) = (coord_t)round(double(center(1)) + c * v[1] + s * v[0]);
     }
 }
 
-void
-MultiPoint::reverse()
+void MultiPoint::reverse()
 {
     std::reverse(this->points.begin(), this->points.end());
 }
 
-Point
-MultiPoint::first_point() const
+Point MultiPoint::first_point() const
 {
     return this->points.front();
 }
@@ -79,16 +72,16 @@ MultiPoint::length() const
 int
 MultiPoint::find_point(const Point &point) const
 {
-    for (Points::const_iterator it = this->points.begin(); it != this->points.end(); ++it) {
-        if (it->coincides_with(point)) return it - this->points.begin();
-    }
+    for (const Point &pt : this->points)
+        if (pt == point)
+            return &pt - &this->points.front();
     return -1;  // not found
 }
 
 bool
 MultiPoint::has_boundary_point(const Point &point) const
 {
-    double dist = point.distance_to(point.projection_onto(*this));
+    double dist = (point.projection_onto(*this) - point).cast<double>().norm();
     return dist < SCALED_EPSILON;
 }
 
@@ -102,7 +95,7 @@ bool
 MultiPoint::has_duplicate_points() const
 {
     for (size_t i = 1; i < points.size(); ++i)
-        if (points[i-1].coincides_with(points[i]))
+        if (points[i-1] == points[i])
             return true;
     return false;
 }
@@ -112,7 +105,7 @@ MultiPoint::remove_duplicate_points()
 {
     size_t j = 0;
     for (size_t i = 1; i < points.size(); ++i) {
-        if (points[j].coincides_with(points[i])) {
+        if (points[j] == points[i]) {
             // Just increase index i.
         } else {
             ++ j;
@@ -146,10 +139,10 @@ bool MultiPoint::first_intersection(const Line& line, Point* intersection) const
         if (l.intersection(line, &ip)) {
             if (! found) {
                 found = true;
-                dmin = ip.distance_to(line.a);
+                dmin = (line.a - ip).cast<double>().norm();
                 *intersection = ip;
             } else {
-                double d = ip.distance_to(line.a);
+                double d = (line.a - ip).cast<double>().norm();
                 if (d < dmin) {
                     dmin = d;
                     *intersection = ip;
@@ -160,19 +153,6 @@ bool MultiPoint::first_intersection(const Line& line, Point* intersection) const
     return found;
 }
 
-std::string
-MultiPoint::dump_perl() const
-{
-    std::ostringstream ret;
-    ret << "[";
-    for (Points::const_iterator p = this->points.begin(); p != this->points.end(); ++p) {
-        ret << p->dump_perl();
-        if (p != this->points.end()-1) ret << ",";
-    }
-    ret << "]";
-    return ret.str();
-}
-
 //FIXME This is very inefficient in term of memory use.
 // The recursive algorithm shall run in place, not allocating temporary data in each recursion.
 Points
@@ -185,7 +165,7 @@ MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
     Line full(points.front(), points.back());
     for (Points::const_iterator it = points.begin() + 1; it != points.end(); ++it) {
         // we use shortest distance, not perpendicular distance
-        double d = it->distance_to(full);
+        double d = full.distance_to(*it);
         if (d > dmax) {
             index = it - points.begin();
             dmax = d;
@@ -216,25 +196,22 @@ MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
 
 void MultiPoint3::translate(double x, double y)
 {
-    for (Point3& p : points)
-    {
-        p.translate(x, y);
+    for (Vec3crd &p : points) {
+        p(0) += x;
+        p(1) += y;
     }
 }
 
 void MultiPoint3::translate(const Point& vector)
 {
-    translate(vector.x, vector.y);
+    this->translate(vector(0), vector(1));
 }
 
 double MultiPoint3::length() const
 {
-    Lines3 lines = this->lines();
     double len = 0.0;
-    for (const Line3& line : lines)
-    {
+    for (const Line3& line : this->lines())
         len += line.length();
-    }
     return len;
 }
 
@@ -246,15 +223,11 @@ BoundingBox3 MultiPoint3::bounding_box() const
 bool MultiPoint3::remove_duplicate_points()
 {
     size_t j = 0;
-    for (size_t i = 1; i < points.size(); ++i)
-    {
-        if (points[j].coincides_with(points[i]))
-        {
+    for (size_t i = 1; i < points.size(); ++i) {
+        if (points[j] == points[i]) {
             // Just increase index i.
-        }
-        else
-        {
-            ++j;
+        } else {
+            ++ j;
             if (j < i)
                 points[j] = points[i];
         }
@@ -281,19 +254,19 @@ BoundingBox get_extents_rotated(const Points &points, double angle)
         double s = sin(angle);
         double c = cos(angle);
         Points::const_iterator it = points.begin();
-        double cur_x = (double)it->x;
-        double cur_y = (double)it->y;
-        bbox.min.x = bbox.max.x = (coord_t)round(c * cur_x - s * cur_y);
-        bbox.min.y = bbox.max.y = (coord_t)round(c * cur_y + s * cur_x);
+        double cur_x = (double)(*it)(0);
+        double cur_y = (double)(*it)(1);
+        bbox.min(0) = bbox.max(0) = (coord_t)round(c * cur_x - s * cur_y);
+        bbox.min(1) = bbox.max(1) = (coord_t)round(c * cur_y + s * cur_x);
         for (++it; it != points.end(); ++it) {
-            double cur_x = (double)it->x;
-            double cur_y = (double)it->y;
+            double cur_x = (double)(*it)(0);
+            double cur_y = (double)(*it)(1);
             coord_t x = (coord_t)round(c * cur_x - s * cur_y);
             coord_t y = (coord_t)round(c * cur_y + s * cur_x);
-            bbox.min.x = std::min(x, bbox.min.x);
-            bbox.min.y = std::min(y, bbox.min.y);
-            bbox.max.x = std::max(x, bbox.max.x);
-            bbox.max.y = std::max(y, bbox.max.y);
+            bbox.min(0) = std::min(x, bbox.min(0));
+            bbox.min(1) = std::min(y, bbox.min(1));
+            bbox.max(0) = std::max(x, bbox.max(0));
+            bbox.max(1) = std::max(y, bbox.max(1));
         }
         bbox.defined = true;
     }
diff --git a/xs/src/libslic3r/MultiPoint.hpp b/xs/src/libslic3r/MultiPoint.hpp
index 0970e9a67..1fef4083b 100644
--- a/xs/src/libslic3r/MultiPoint.hpp
+++ b/xs/src/libslic3r/MultiPoint.hpp
@@ -18,10 +18,11 @@ public:
     Points points;
     
     operator Points() const;
-    MultiPoint() {};
+    MultiPoint() {}
     MultiPoint(const MultiPoint &other) : points(other.points) {}
     MultiPoint(MultiPoint &&other) : points(std::move(other.points)) {}
-    explicit MultiPoint(const Points &_points): points(_points) {}
+    MultiPoint(std::initializer_list<Point> list) : points(list) {}
+    explicit MultiPoint(const Points &_points) : points(_points) {}
     MultiPoint& operator=(const MultiPoint &other) { points = other.points; return *this; }
     MultiPoint& operator=(MultiPoint &&other) { points = std::move(other.points); return *this; }
     void scale(double factor);
@@ -43,9 +44,9 @@ public:
         int idx = -1;
         if (! this->points.empty()) {
             idx = 0;
-            double dist_min = this->points.front().distance_to(point);
+            double dist_min = (point - this->points.front()).cast<double>().norm();
             for (int i = 1; i < int(this->points.size()); ++ i) {
-                double d = this->points[i].distance_to(point);
+                double d = (this->points[i] - point).cast<double>().norm();
                 if (d < dist_min) {
                     dist_min = d;
                     idx = i;
@@ -75,7 +76,6 @@ public:
 
     bool intersection(const Line& line, Point* intersection) const;
     bool first_intersection(const Line& line, Point* intersection) const;
-    std::string dump_perl() const;
     
     static Points _douglas_peucker(const Points &points, const double tolerance);
 };
@@ -85,7 +85,7 @@ class MultiPoint3
 public:
     Points3 points;
 
-    void append(const Point3& point) { this->points.push_back(point); }
+    void append(const Vec3crd& point) { this->points.push_back(point); }
 
     void translate(double x, double y);
     void translate(const Point& vector);
diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp
index 1d2e6248f..de8aeeb2a 100644
--- a/xs/src/libslic3r/PerimeterGenerator.cpp
+++ b/xs/src/libslic3r/PerimeterGenerator.cpp
@@ -243,7 +243,7 @@ void PerimeterGenerator::process()
                 perimeter_spacing / 2;
         // only apply infill overlap if we actually have one perimeter
         if (inset > 0)
-            inset -= scale_(this->config->get_abs_value("infill_overlap", unscale(inset + solid_infill_spacing / 2)));
+            inset -= scale_(this->config->get_abs_value("infill_overlap", unscale<double>(inset + solid_infill_spacing / 2)));
         // simplify infill contours according to resolution
         Polygons pp;
         for (ExPolygon &ex : last)
@@ -366,99 +366,103 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
     return entities;
 }
 
-ExtrusionEntityCollection PerimeterGenerator::_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const
+static inline ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, Flow &flow, const float tolerance)
 {
-    // this value determines granularity of adaptive width, as G-code does not allow
-    // variable extrusion within a single move; this value shall only affect the amount
-    // of segments, and any pruning shall be performed before we apply this tolerance
-    const double tolerance = scale_(0.05);
+    ExtrusionPaths paths;
+    ExtrusionPath path(role);
+    ThickLines lines = thick_polyline.thicklines();
     
-    ExtrusionEntityCollection coll;
-    for (const ThickPolyline &p : polylines) {
-        ExtrusionPaths paths;
-        ExtrusionPath path(role);
-        ThickLines lines = p.thicklines();
+    for (int i = 0; i < (int)lines.size(); ++i) {
+        const ThickLine& line = lines[i];
         
-        for (int i = 0; i < (int)lines.size(); ++i) {
-            const ThickLine& line = lines[i];
-            
-            const coordf_t line_len = line.length();
-            if (line_len < SCALED_EPSILON) continue;
-            
-            double thickness_delta = fabs(line.a_width - line.b_width);
-            if (thickness_delta > tolerance) {
-                const unsigned short segments = ceil(thickness_delta / tolerance);
-                const coordf_t seg_len = line_len / segments;
-                Points pp;
-                std::vector<coordf_t> width;
-                {
-                    pp.push_back(line.a);
-                    width.push_back(line.a_width);
-                    for (size_t j = 1; j < segments; ++j) {
-                        pp.push_back(line.point_at(j*seg_len));
-                        
-                        coordf_t w = line.a_width + (j*seg_len) * (line.b_width-line.a_width) / line_len;
-                        width.push_back(w);
-                        width.push_back(w);
-                    }
-                    pp.push_back(line.b);
-                    width.push_back(line.b_width);
+        const coordf_t line_len = line.length();
+        if (line_len < SCALED_EPSILON) continue;
+        
+        double thickness_delta = fabs(line.a_width - line.b_width);
+        if (thickness_delta > tolerance) {
+            const unsigned short segments = ceil(thickness_delta / tolerance);
+            const coordf_t seg_len = line_len / segments;
+            Points pp;
+            std::vector<coordf_t> width;
+            {
+                pp.push_back(line.a);
+                width.push_back(line.a_width);
+                for (size_t j = 1; j < segments; ++j) {
+                    pp.push_back((line.a.cast<double>() + (line.b - line.a).cast<double>().normalized() * (j * seg_len)).cast<coord_t>());
                     
-                    assert(pp.size() == segments + 1);
-                    assert(width.size() == segments*2);
+                    coordf_t w = line.a_width + (j*seg_len) * (line.b_width-line.a_width) / line_len;
+                    width.push_back(w);
+                    width.push_back(w);
                 }
+                pp.push_back(line.b);
+                width.push_back(line.b_width);
                 
-                // delete this line and insert new ones
-                lines.erase(lines.begin() + i);
-                for (size_t j = 0; j < segments; ++j) {
-                    ThickLine new_line(pp[j], pp[j+1]);
-                    new_line.a_width = width[2*j];
-                    new_line.b_width = width[2*j+1];
-                    lines.insert(lines.begin() + i + j, new_line);
-                }
-                
-                -- i;
-                continue;
+                assert(pp.size() == segments + 1);
+                assert(width.size() == segments*2);
             }
             
-            const double w = fmax(line.a_width, line.b_width);
-            if (path.polyline.points.empty()) {
-                path.polyline.append(line.a);
-                path.polyline.append(line.b);
-                // Convert from spacing to extrusion width based on the extrusion model
-                // of a square extrusion ended with semi circles.
-                flow.width = unscale(w) + flow.height * (1. - 0.25 * PI);
-                #ifdef SLIC3R_DEBUG
-                printf("  filling %f gap\n", flow.width);
-                #endif
-                path.mm3_per_mm  = flow.mm3_per_mm();
-                path.width       = flow.width;
-                path.height      = flow.height;
-            } else {
-                thickness_delta = fabs(scale_(flow.width) - w);
-                if (thickness_delta <= tolerance) {
-                    // the width difference between this line and the current flow width is 
-                    // within the accepted tolerance
-                    path.polyline.append(line.b);
-                } else {
-                    // we need to initialize a new line
-                    paths.emplace_back(std::move(path));
-                    path = ExtrusionPath(role);
-                    -- i;
-                }
+            // delete this line and insert new ones
+            lines.erase(lines.begin() + i);
+            for (size_t j = 0; j < segments; ++j) {
+                ThickLine new_line(pp[j], pp[j+1]);
+                new_line.a_width = width[2*j];
+                new_line.b_width = width[2*j+1];
+                lines.insert(lines.begin() + i + j, new_line);
             }
+            
+            -- i;
+            continue;
         }
-        if (path.polyline.is_valid())
-            paths.emplace_back(std::move(path));        
-        // Append paths to collection.
-        if (! paths.empty()) {
-            if (paths.front().first_point().coincides_with(paths.back().last_point()))
-                coll.append(ExtrusionLoop(paths));
-            else
-                coll.append(paths);
+        
+        const double w = fmax(line.a_width, line.b_width);
+        if (path.polyline.points.empty()) {
+            path.polyline.append(line.a);
+            path.polyline.append(line.b);
+            // Convert from spacing to extrusion width based on the extrusion model
+            // of a square extrusion ended with semi circles.
+            flow.width = unscale<float>(w) + flow.height * (1. - 0.25 * PI);
+            #ifdef SLIC3R_DEBUG
+            printf("  filling %f gap\n", flow.width);
+            #endif
+            path.mm3_per_mm  = flow.mm3_per_mm();
+            path.width       = flow.width;
+            path.height      = flow.height;
+        } else {
+            thickness_delta = fabs(scale_(flow.width) - w);
+            if (thickness_delta <= tolerance) {
+                // the width difference between this line and the current flow width is 
+                // within the accepted tolerance
+                path.polyline.append(line.b);
+            } else {
+                // we need to initialize a new line
+                paths.emplace_back(std::move(path));
+                path = ExtrusionPath(role);
+                -- i;
+            }
+        }
+    }
+    if (path.polyline.is_valid())
+        paths.emplace_back(std::move(path));
+    return paths;
+}
+
+ExtrusionEntityCollection PerimeterGenerator::_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const
+{
+    // This value determines granularity of adaptive width, as G-code does not allow
+    // variable extrusion within a single move; this value shall only affect the amount
+    // of segments, and any pruning shall be performed before we apply this tolerance.
+    ExtrusionEntityCollection coll;
+    const double tolerance = scale_(0.05);
+    for (const ThickPolyline &p : polylines) {
+        ExtrusionPaths paths = thick_polyline_to_extrusion_paths(p, role, flow, tolerance);
+        // Append paths to collection.
+        if (! paths.empty()) {
+            if (paths.front().first_point() == paths.back().last_point())
+                coll.append(ExtrusionLoop(std::move(paths)));
+            else
+                coll.append(std::move(paths));
         }
     }
-    
     return coll;
 }
 
diff --git a/xs/src/libslic3r/PlaceholderParser.cpp b/xs/src/libslic3r/PlaceholderParser.cpp
index 80740b20d..1cfd51141 100644
--- a/xs/src/libslic3r/PlaceholderParser.cpp
+++ b/xs/src/libslic3r/PlaceholderParser.cpp
@@ -693,7 +693,7 @@ namespace client
             case coInts:     output.set_i(static_cast<const ConfigOptionInts    *>(opt.opt)->values[idx]); break;
             case coStrings:  output.set_s(static_cast<const ConfigOptionStrings *>(opt.opt)->values[idx]); break;
             case coPercents: output.set_d(static_cast<const ConfigOptionPercents*>(opt.opt)->values[idx]); break;
-            case coPoints:   output.set_s(static_cast<const ConfigOptionPoints  *>(opt.opt)->values[idx].dump_perl()); break;
+            case coPoints:   output.set_s(to_string(static_cast<const ConfigOptionPoints  *>(opt.opt)->values[idx])); break;
             case coBools:    output.set_b(static_cast<const ConfigOptionBools   *>(opt.opt)->values[idx] != 0); break;
             default:
                 ctx->throw_exception("Unknown vector variable type", opt.it_range);
diff --git a/xs/src/libslic3r/Point.cpp b/xs/src/libslic3r/Point.cpp
index 2abcd26af..ec6c28fe8 100644
--- a/xs/src/libslic3r/Point.cpp
+++ b/xs/src/libslic3r/Point.cpp
@@ -3,84 +3,32 @@
 #include "MultiPoint.hpp"
 #include "Int128.hpp"
 #include <algorithm>
-#include <cmath>
 
 namespace Slic3r {
 
-Point::Point(double x, double y)
+void Point::rotate(double angle)
 {
-    this->x = lrint(x);
-    this->y = lrint(y);
+    double cur_x = (double)(*this)(0);
+    double cur_y = (double)(*this)(1);
+    double s     = ::sin(angle);
+    double c     = ::cos(angle);
+    (*this)(0) = (coord_t)round(c * cur_x - s * cur_y);
+    (*this)(1) = (coord_t)round(c * cur_y + s * cur_x);
 }
 
-std::string
-Point::wkt() const
+void Point::rotate(double angle, const Point &center)
 {
-    std::ostringstream ss;
-    ss << "POINT(" << this->x << " " << this->y << ")";
-    return ss.str();
+    double cur_x = (double)(*this)(0);
+    double cur_y = (double)(*this)(1);
+    double s     = ::sin(angle);
+    double c     = ::cos(angle);
+    double dx    = cur_x - (double)center(0);
+    double dy    = cur_y - (double)center(1);
+    (*this)(0) = (coord_t)round( (double)center(0) + c * dx - s * dy );
+    (*this)(1) = (coord_t)round( (double)center(1) + c * dy + s * dx );
 }
 
-std::string
-Point::dump_perl() const
-{
-    std::ostringstream ss;
-    ss << "[" << this->x << "," << this->y << "]";
-    return ss.str();
-}
-
-void
-Point::scale(double factor)
-{
-    this->x *= factor;
-    this->y *= factor;
-}
-
-void
-Point::translate(double x, double y)
-{
-    this->x += x;
-    this->y += y;
-}
-
-void
-Point::translate(const Vector &vector)
-{
-    this->translate(vector.x, vector.y);
-}
-
-void
-Point::rotate(double angle)
-{
-    double cur_x = (double)this->x;
-    double cur_y = (double)this->y;
-    double s     = sin(angle);
-    double c     = cos(angle);
-    this->x = (coord_t)round(c * cur_x - s * cur_y);
-    this->y = (coord_t)round(c * cur_y + s * cur_x);
-}
-
-void
-Point::rotate(double angle, const Point &center)
-{
-    double cur_x = (double)this->x;
-    double cur_y = (double)this->y;
-    double s     = sin(angle);
-    double c     = cos(angle);
-    double dx    = cur_x - (double)center.x;
-    double dy    = cur_y - (double)center.y;
-    this->x = (coord_t)round( (double)center.x + c * dx - s * dy );
-    this->y = (coord_t)round( (double)center.y + c * dy + s * dx );
-}
-
-bool
-Point::coincides_with_epsilon(const Point &point) const
-{
-    return std::abs(this->x - point.x) < SCALED_EPSILON && std::abs(this->y - point.y) < SCALED_EPSILON;
-}
-
-int
-Point::nearest_point_index(const Points &points) const
+int Point::nearest_point_index(const Points &points) const
 {
     PointConstPtrs p;
     p.reserve(points.size());
@@ -97,12 +45,12 @@ int Point::nearest_point_index(const PointConstPtrs &points) const
     for (PointConstPtrs::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 = sqr<double>(this->x - (*it)->x);
+        double d = sqr<double>((*this)(0) - (*it)->x());
         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 += sqr<double>(this->y - (*it)->y);
+        d += sqr<double>((*this)(1) - (*it)->y());
         if (distance != -1 && d > distance) continue;
         
         idx = it - points.begin();
@@ -114,8 +62,7 @@ int Point::nearest_point_index(const PointConstPtrs &points) const
     return idx;
 }
 
-int
-Point::nearest_point_index(const PointPtrs &points) const
+int Point::nearest_point_index(const PointPtrs &points) const
 {
     PointConstPtrs p;
     p.reserve(points.size());
@@ -124,8 +71,7 @@ Point::nearest_point_index(const PointPtrs &points) const
     return this->nearest_point_index(p);
 }
 
-bool
-Point::nearest_point(const Points &points, Point* point) const
+bool Point::nearest_point(const Points &points, Point* point) const
 {
     int idx = this->nearest_point_index(points);
     if (idx == -1) return false;
@@ -133,40 +79,6 @@ Point::nearest_point(const Points &points, Point* point) const
     return true;
 }
 
-/* distance to the closest point of line */
-double
-Point::distance_to(const Line &line) const
-{
-    const double dx = line.b.x - line.a.x;
-    const double dy = line.b.y - line.a.y;
-    
-    const double l2 = dx*dx + dy*dy;  // avoid a sqrt
-    if (l2 == 0.0) return this->distance_to(line.a);   // line.a == line.b case
-    
-    // Consider the line extending the segment, parameterized as line.a + t (line.b - line.a).
-    // We find projection of this point onto the line. 
-    // It falls where t = [(this-line.a) . (line.b-line.a)] / |line.b-line.a|^2
-    const double t = ((this->x - line.a.x) * dx + (this->y - line.a.y) * dy) / l2;
-    if (t < 0.0)      return this->distance_to(line.a);  // beyond the 'a' end of the segment
-    else if (t > 1.0) return this->distance_to(line.b);  // beyond the 'b' end of the segment
-    Point projection(
-        line.a.x + t * dx,
-        line.a.y + t * dy
-    );
-    return this->distance_to(projection);
-}
-
-double
-Point::perp_distance_to(const Line &line) const
-{
-    if (line.a.coincides_with(line.b)) return this->distance_to(line.a);
-    
-    double n = (double)(line.b.x - line.a.x) * (double)(line.a.y - this->y)
-        - (double)(line.a.x - this->x) * (double)(line.b.y - line.a.y);
-    
-    return std::abs(n) / line.length();
-}
-
 /* Three points are a counter-clockwise turn if ccw > 0, clockwise if
  * ccw < 0, and collinear if ccw = 0 because ccw is a determinant that
  * gives the signed area of the triangle formed by p1, p2 and this point.
@@ -174,51 +86,46 @@ Point::perp_distance_to(const Line &line) const
  * z-component of their 3D cross product.
  * We return double because it must be big enough to hold 2*max(|coordinate|)^2
  */
-double
-Point::ccw(const Point &p1, const Point &p2) const
+double Point::ccw(const Point &p1, const Point &p2) const
 {
-    return (double)(p2.x - p1.x)*(double)(this->y - p1.y) - (double)(p2.y - p1.y)*(double)(this->x - p1.x);
+    return (double)(p2(0) - p1(0))*(double)((*this)(1) - p1(1)) - (double)(p2(1) - p1(1))*(double)((*this)(0) - p1(0));
 }
 
-double
-Point::ccw(const Line &line) const
+double Point::ccw(const Line &line) const
 {
     return this->ccw(line.a, line.b);
 }
 
 // returns the CCW angle between this-p1 and this-p2
 // i.e. this assumes a CCW rotation from p1 to p2 around this
-double
-Point::ccw_angle(const Point &p1, const Point &p2) const
+double Point::ccw_angle(const Point &p1, const Point &p2) const
 {
-    double angle = atan2(p1.x - this->x, p1.y - this->y)
-                 - atan2(p2.x - this->x, p2.y - this->y);
+    double angle = atan2(p1(0) - (*this)(0), p1(1) - (*this)(1))
+                 - atan2(p2(0) - (*this)(0), p2(1) - (*this)(1));
     
     // we only want to return only positive angles
     return angle <= 0 ? angle + 2*PI : angle;
 }
 
-Point
-Point::projection_onto(const MultiPoint &poly) const
+Point Point::projection_onto(const MultiPoint &poly) const
 {
     Point running_projection = poly.first_point();
-    double running_min = this->distance_to(running_projection);
+    double running_min = (running_projection - *this).cast<double>().norm();
     
     Lines lines = poly.lines();
     for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
         Point point_temp = this->projection_onto(*line);
-        if (this->distance_to(point_temp) < running_min) {
+        if ((point_temp - *this).cast<double>().norm() < running_min) {
 	        running_projection = point_temp;
-	        running_min = this->distance_to(running_projection);
+	        running_min = (running_projection - *this).cast<double>().norm();
         }
     }
     return running_projection;
 }
 
-Point
-Point::projection_onto(const Line &line) const
+Point Point::projection_onto(const Line &line) const
 {
-    if (line.a.coincides_with(line.b)) return line.a;
+    if (line.a == line.b) return line.a;
     
     /*
         (Ported from VisiLibity by Karl J. Obermeyer)
@@ -229,165 +136,35 @@ Point::projection_onto(const Line &line) const
         If theta is outside the interval [0,1], then one of the Line_Segment's endpoints
         must be closest to calling Point.
     */
-    double lx = (double)(line.b.x - line.a.x);
-    double ly = (double)(line.b.y - line.a.y);
-    double theta = ( (double)(line.b.x - this->x)*lx + (double)(line.b.y- this->y)*ly ) 
+    double lx = (double)(line.b(0) - line.a(0));
+    double ly = (double)(line.b(1) - line.a(1));
+    double theta = ( (double)(line.b(0) - (*this)(0))*lx + (double)(line.b(1)- (*this)(1))*ly ) 
           / ( sqr<double>(lx) + sqr<double>(ly) );
     
     if (0.0 <= theta && theta <= 1.0)
-        return theta * line.a + (1.0-theta) * line.b;
+        return (theta * line.a.cast<coordf_t>() + (1.0-theta) * line.b.cast<coordf_t>()).cast<coord_t>();
     
     // Else pick closest endpoint.
-    if (this->distance_to(line.a) < this->distance_to(line.b)) {
-        return line.a;
-    } else {
-        return line.b;
-    }
+    return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b;
 }
 
-Point
-Point::negative() const
+std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf)
 {
-    return Point(-this->x, -this->y);
-}
-
-Vector
-Point::vector_to(const Point &point) const
-{
-    return Vector(point.x - this->x, point.y - this->y);
-}
-
-std::ostream&
-operator<<(std::ostream &stm, const Pointf &pointf)
-{
-    return stm << pointf.x << "," << pointf.y;
-}
-
-std::string
-Pointf::wkt() const
-{
-    std::ostringstream ss;
-    ss << "POINT(" << this->x << " " << this->y << ")";
-    return ss.str();
-}
-
-std::string
-Pointf::dump_perl() const
-{
-    std::ostringstream ss;
-    ss << "[" << this->x << "," << this->y << "]";
-    return ss.str();
-}
-
-void
-Pointf::scale(double factor)
-{
-    this->x *= factor;
-    this->y *= factor;
-}
-
-void
-Pointf::translate(double x, double y)
-{
-    this->x += x;
-    this->y += y;
-}
-
-void
-Pointf::translate(const Vectorf &vector)
-{
-    this->translate(vector.x, vector.y);
-}
-
-void
-Pointf::rotate(double angle)
-{
-    double cur_x = this->x;
-    double cur_y = this->y;
-    double s     = sin(angle);
-    double c     = cos(angle);
-    this->x = c * cur_x - s * cur_y;
-    this->y = c * cur_y + s * cur_x;
-}
-
-void
-Pointf::rotate(double angle, const Pointf &center)
-{
-    double cur_x = this->x;
-    double cur_y = this->y;
-    double s     = sin(angle);
-    double c     = cos(angle);
-    double dx    = cur_x - center.x;
-    double dy    = cur_y - center.y;
-    this->x = center.x + c * dx - s * dy;
-    this->y = center.y + c * dy + s * dx;
-}
-
-Pointf
-Pointf::negative() const
-{
-    return Pointf(-this->x, -this->y);
-}
-
-Vectorf
-Pointf::vector_to(const Pointf &point) const
-{
-    return Vectorf(point.x - this->x, point.y - this->y);
-}
-
-void
-Pointf3::scale(double factor)
-{
-    Pointf::scale(factor);
-    this->z *= factor;
-}
-
-void
-Pointf3::translate(const Vectorf3 &vector)
-{
-    this->translate(vector.x, vector.y, vector.z);
-}
-
-void
-Pointf3::translate(double x, double y, double z)
-{
-    Pointf::translate(x, y);
-    this->z += z;
-}
-
-double
-Pointf3::distance_to(const Pointf3 &point) const
-{
-    double dx = ((double)point.x - this->x);
-    double dy = ((double)point.y - this->y);
-    double dz = ((double)point.z - this->z);
-    return sqrt(dx*dx + dy*dy + dz*dz);
-}
-
-Pointf3
-Pointf3::negative() const
-{
-    return Pointf3(-this->x, -this->y, -this->z);
-}
-
-Vectorf3
-Pointf3::vector_to(const Pointf3 &point) const
-{
-    return Vectorf3(point.x - this->x, point.y - this->y, point.z - this->z);
+    return stm << pointf(0) << "," << pointf(1);
 }
 
 namespace int128 {
 
-int orient(const Point &p1, const Point &p2, const Point &p3)
+int orient(const Vec2crd &p1, const Vec2crd &p2, const Vec2crd &p3)
 {
     Slic3r::Vector v1(p2 - p1);
     Slic3r::Vector v2(p3 - p1);
-    return Int128::sign_determinant_2x2_filtered(v1.x, v1.y, v2.x, v2.y);
+    return Int128::sign_determinant_2x2_filtered(v1(0), v1(1), v2(0), v2(1));
 }
 
-int cross(const Point &v1, const Point &v2)
+int cross(const Vec2crd &v1, const Vec2crd &v2)
 {
-    return Int128::sign_determinant_2x2_filtered(v1.x, v1.y, v2.x, v2.y);
+    return Int128::sign_determinant_2x2_filtered(v1(0), v1(1), v2(0), v2(1));
 }
 
 }
diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp
index 8aee65a93..b969b9839 100644
--- a/xs/src/libslic3r/Point.hpp
+++ b/xs/src/libslic3r/Point.hpp
@@ -2,100 +2,128 @@
 #define slic3r_Point_hpp_
 
 #include "libslic3r.h"
+#include <cstddef>
 #include <vector>
-#include <math.h>
+#include <cmath>
 #include <string>
 #include <sstream>
 #include <unordered_map>
 
+#include <Eigen/Geometry> 
+
 namespace Slic3r {
 
 class Line;
-class Linef;
 class MultiPoint;
 class Point;
-class Point3;
-class Pointf;
-class Pointf3;
 typedef Point Vector;
-typedef Point3 Vector3;
-typedef Pointf Vectorf;
-typedef Pointf3 Vectorf3;
-typedef std::vector<Point> Points;
-typedef std::vector<Point*> PointPtrs;
-typedef std::vector<const Point*> PointConstPtrs;
-typedef std::vector<Point3> Points3;
-typedef std::vector<Pointf> Pointfs;
-typedef std::vector<Pointf3> Pointf3s;
 
-class Point
+// Eigen types, to replace the Slic3r's own types in the future.
+// Vector types with a fixed point coordinate base type.
+typedef Eigen::Matrix<coord_t,  2, 1, Eigen::DontAlign> Vec2crd;
+typedef Eigen::Matrix<coord_t,  3, 1, Eigen::DontAlign> Vec3crd;
+typedef Eigen::Matrix<int64_t,  2, 1, Eigen::DontAlign> Vec2i64;
+typedef Eigen::Matrix<int64_t,  3, 1, Eigen::DontAlign> Vec3i64;
+
+// Vector types with a double coordinate base type.
+typedef Eigen::Matrix<float,    2, 1, Eigen::DontAlign> Vec2f;
+typedef Eigen::Matrix<float,    3, 1, Eigen::DontAlign> Vec3f;
+typedef Eigen::Matrix<double,   2, 1, Eigen::DontAlign> Vec2d;
+typedef Eigen::Matrix<double,   3, 1, Eigen::DontAlign> Vec3d;
+
+typedef std::vector<Point>                              Points;
+typedef std::vector<Point*>                             PointPtrs;
+typedef std::vector<const Point*>                       PointConstPtrs;
+typedef std::vector<Vec3crd>                            Points3;
+typedef std::vector<Vec2d>                              Pointfs;
+typedef std::vector<Vec3d>                              Pointf3s;
+
+typedef Eigen::Transform<float,  2, Eigen::Affine, Eigen::DontAlign> Transform2f;
+typedef Eigen::Transform<double, 2, Eigen::Affine, Eigen::DontAlign> Transform2d;
+typedef Eigen::Transform<float,  3, Eigen::Affine, Eigen::DontAlign> Transform3f;
+typedef Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign> Transform3d;
+
+inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0) || (lhs(0) == rhs(0) && lhs(1) < rhs(1)); }
+
+inline int64_t cross2(const Vec2i64 &v1, const Vec2i64 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
+inline coord_t cross2(const Vec2crd &v1, const Vec2crd &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
+inline float   cross2(const Vec2f   &v1, const Vec2f   &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
+inline double  cross2(const Vec2d   &v1, const Vec2d   &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
+
+inline Vec2crd to_2d(const Vec3crd &pt3) { return Vec2crd(pt3(0), pt3(1)); }
+inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(1)); }
+inline Vec2f   to_2d(const Vec3f   &pt3) { return Vec2f  (pt3(0), pt3(1)); }
+inline Vec2d   to_2d(const Vec3d   &pt3) { return Vec2d  (pt3(0), pt3(1)); }
+
+inline Vec2d   unscale(coord_t x, coord_t y) { return Vec2d(unscale<double>(x), unscale<double>(y)); }
+inline Vec2d   unscale(const Vec2crd &pt) { return Vec2d(unscale<double>(pt(0)), unscale<double>(pt(1))); }
+inline Vec2d   unscale(const Vec2d   &pt) { return Vec2d(unscale<double>(pt(0)), unscale<double>(pt(1))); }
+inline Vec3d   unscale(coord_t x, coord_t y, coord_t z) { return Vec3d(unscale<double>(x), unscale<double>(y), unscale<double>(z)); }
+inline Vec3d   unscale(const Vec3crd &pt) { return Vec3d(unscale<double>(pt(0)), unscale<double>(pt(1)), unscale<double>(pt(2))); }
+inline Vec3d   unscale(const Vec3d   &pt) { return Vec3d(unscale<double>(pt(0)), unscale<double>(pt(1)), unscale<double>(pt(2))); }
+
+inline std::string to_string(const Vec2crd &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + "]"; }
+inline std::string to_string(const Vec2d   &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + "]"; }
+inline std::string to_string(const Vec3crd &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + ", " + std::to_string(pt(2)) + "]"; }
+inline std::string to_string(const Vec3d   &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + ", " + std::to_string(pt(2)) + "]"; }
+
+class Point : public Vec2crd
 {
 public:
     typedef coord_t coord_type;
-    coord_t x;
-    coord_t y;
-    Point(coord_t _x = 0, coord_t _y = 0): x(_x), y(_y) {};
-    Point(int64_t _x, int64_t _y): x(coord_t(_x)), y(coord_t(_y)) {};  // for Clipper
-    Point(double x, double y);
+
+    Point() : Vec2crd() { (*this)(0) = 0; (*this)(1) = 0; }
+    Point(coord_t x, coord_t y) { (*this)(0) = x; (*this)(1) = y; }
+    Point(int64_t x, int64_t y) { (*this)(0) = coord_t(x); (*this)(1) = coord_t(y); } // for Clipper
+    Point(double x, double y) { (*this)(0) = coord_t(lrint(x)); (*this)(1) = coord_t(lrint(y)); }
+    Point(const Point &rhs) { *this = rhs; }
+    // This constructor allows you to construct Point from Eigen expressions
+    template<typename OtherDerived>
+    Point(const Eigen::MatrixBase<OtherDerived> &other) : Vec2crd(other) {}
     static Point new_scale(coordf_t x, coordf_t y) { return Point(coord_t(scale_(x)), coord_t(scale_(y))); }
 
-    bool operator==(const Point& rhs) const { return this->x == rhs.x && this->y == rhs.y; }
-    bool operator!=(const Point& rhs) const { return ! (*this == rhs); }
-    bool operator<(const Point& rhs) const { return this->x < rhs.x || (this->x == rhs.x && this->y < rhs.y); }
+    // This method allows you to assign Eigen expressions to MyVectorType
+    template<typename OtherDerived>
+    Point& operator=(const Eigen::MatrixBase<OtherDerived> &other)
+    {
+        this->Vec2crd::operator=(other);
+        return *this;
+    }
 
-    Point& operator+=(const Point& rhs) { this->x += rhs.x; this->y += rhs.y; return *this; }
-    Point& operator-=(const Point& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; }
-    Point& operator*=(const coord_t& rhs) { this->x *= rhs; this->y *= rhs;   return *this; }
+    bool operator< (const Point& rhs) const { return (*this)(0) < rhs(0) || ((*this)(0) == rhs(0) && (*this)(1) < rhs(1)); }
 
-    std::string wkt() const;
-    std::string dump_perl() const;
-    void scale(double factor);
-    void translate(double x, double y);
-    void translate(const Vector &vector);
-    void rotate(double angle);
-    void rotate(double angle, const Point &center);
-    Point rotated(double angle) const { Point res(*this); res.rotate(angle); return res; }
-    Point rotated(double angle, const Point &center) const { Point res(*this); res.rotate(angle, center); return res; }
-    bool coincides_with(const Point &point) const { return this->x == point.x && this->y == point.y; }
-    bool coincides_with_epsilon(const Point &point) const;
-    int nearest_point_index(const Points &points) const;
-    int nearest_point_index(const PointConstPtrs &points) const;
-    int nearest_point_index(const PointPtrs &points) const;
-    bool nearest_point(const Points &points, Point* point) const;
-    double distance_to(const Point &point) const { return sqrt(distance_to_sq(point)); }
-    double distance_to_sq(const Point &point) const { double dx = double(point.x - this->x); double dy = double(point.y - this->y); return dx*dx + dy*dy; }
-    double distance_to(const Line &line) const;
-    double perp_distance_to(const Line &line) const;
+    Point& operator+=(const Point& rhs) { (*this)(0) += rhs(0); (*this)(1) += rhs(1); return *this; }
+    Point& operator-=(const Point& rhs) { (*this)(0) -= rhs(0); (*this)(1) -= rhs(1); return *this; }
+    Point& operator*=(const double &rhs) { (*this)(0) *= rhs; (*this)(1) *= rhs;   return *this; }
+
+    void   rotate(double angle);
+    void   rotate(double angle, const Point &center);
+    Point  rotated(double angle) const { Point res(*this); res.rotate(angle); return res; }
+    Point  rotated(double angle, const Point &center) const { Point res(*this); res.rotate(angle, center); return res; }
+    int    nearest_point_index(const Points &points) const;
+    int    nearest_point_index(const PointConstPtrs &points) const;
+    int    nearest_point_index(const PointPtrs &points) const;
+    bool   nearest_point(const Points &points, Point* point) const;
     double ccw(const Point &p1, const Point &p2) const;
     double ccw(const Line &line) const;
     double ccw_angle(const Point &p1, const Point &p2) const;
-    Point projection_onto(const MultiPoint &poly) const;
-    Point projection_onto(const Line &line) const;
-    Point negative() const;
-    Vector vector_to(const Point &point) const;
+    Point  projection_onto(const MultiPoint &poly) const;
+    Point  projection_onto(const Line &line) const;
 };
 
-inline Point operator+(const Point& point1, const Point& point2) { return Point(point1.x + point2.x, point1.y + point2.y); }
-inline Point operator-(const Point& point1, const Point& point2) { return Point(point1.x - point2.x, point1.y - point2.y); }
-inline Point operator*(double scalar, const Point& point2) { return Point(scalar * point2.x, scalar * point2.y); }
-inline int64_t cross(const Point &v1, const Point &v2) { return int64_t(v1.x) * int64_t(v2.y) - int64_t(v1.y) * int64_t(v2.x); }
-inline int64_t dot(const Point &v1, const Point &v2) { return int64_t(v1.x) * int64_t(v2.x) + int64_t(v1.y) * int64_t(v2.y); }
-
 namespace int128 {
-
-// Exact orientation predicate,
-// returns +1: CCW, 0: collinear, -1: CW.
-int orient(const Point &p1, const Point &p2, const Point &p3);
-
-// Exact orientation predicate,
-// returns +1: CCW, 0: collinear, -1: CW.
-int cross(const Point &v1, const Slic3r::Point &v2);
+    // Exact orientation predicate,
+    // returns +1: CCW, 0: collinear, -1: CW.
+    int orient(const Vec2crd &p1, const Vec2crd &p2, const Vec2crd &p3);
+    // Exact orientation predicate,
+    // returns +1: CCW, 0: collinear, -1: CW.
+    int cross(const Vec2crd &v1, const Vec2crd &v2);
 }
 
 // To be used by std::unordered_map, std::unordered_multimap and friends.
 struct PointHash {
-    size_t operator()(const Point &pt) const {
-        return std::hash<coord_t>()(pt.x) ^ std::hash<coord_t>()(pt.y);
+    size_t operator()(const Vec2crd &pt) const {
+        return std::hash<coord_t>()(pt(0)) ^ std::hash<coord_t>()(pt(1));
     }
 };
 
@@ -139,36 +167,36 @@ public:
     }
 
     void insert(const ValueType &value) {
-        const Point *pt = m_point_accessor(value);
+        const Vec2crd *pt = m_point_accessor(value);
         if (pt != nullptr)
-            m_map.emplace(std::make_pair(Point(pt->x>>m_grid_log2, pt->y>>m_grid_log2), value));
+            m_map.emplace(std::make_pair(Vec2crd(pt->x()>>m_grid_log2, pt->y()>>m_grid_log2), value));
     }
 
     void insert(ValueType &&value) {
-        const Point *pt = m_point_accessor(value);
+        const Vec2crd *pt = m_point_accessor(value);
         if (pt != nullptr)
-            m_map.emplace(std::make_pair(Point(pt->x>>m_grid_log2, pt->y>>m_grid_log2), std::move(value)));
+            m_map.emplace(std::make_pair(Vec2crd(pt->x()>>m_grid_log2, pt->y()>>m_grid_log2), std::move(value)));
     }
 
     // Return a pair of <ValueType*, distance_squared>
-    std::pair<const ValueType*, double> find(const Point &pt) {
+    std::pair<const ValueType*, double> find(const Vec2crd &pt) {
         // Iterate over 4 closest grid cells around pt,
         // find the closest start point inside these cells to pt.
         const ValueType *value_min = nullptr;
         double           dist_min = std::numeric_limits<double>::max();
         // Round pt to a closest grid_cell corner.
-        Point            grid_corner((pt.x+(m_grid_resolution>>1))>>m_grid_log2, (pt.y+(m_grid_resolution>>1))>>m_grid_log2);
+        Vec2crd            grid_corner((pt(0)+(m_grid_resolution>>1))>>m_grid_log2, (pt(1)+(m_grid_resolution>>1))>>m_grid_log2);
         // For four neighbors of grid_corner:
         for (coord_t neighbor_y = -1; neighbor_y < 1; ++ neighbor_y) {
             for (coord_t neighbor_x = -1; neighbor_x < 1; ++ neighbor_x) {
                 // Range of fragment starts around grid_corner, close to pt.
-                auto range = m_map.equal_range(Point(grid_corner.x + neighbor_x, grid_corner.y + neighbor_y));
+                auto range = m_map.equal_range(Vec2crd(grid_corner(0) + neighbor_x, grid_corner(1) + neighbor_y));
                 // Find the map entry closest to pt.
                 for (auto it = range.first; it != range.second; ++it) {
                     const ValueType &value = it->second;
-                    const Point *pt2 = m_point_accessor(value);
+                    const Vec2crd *pt2 = m_point_accessor(value);
                     if (pt2 != nullptr) {
-                        const double d2 = pt.distance_to_sq(*pt2);
+                        const double d2 = (pt - *pt2).squaredNorm();
                         if (d2 < dist_min) {
                             dist_min = d2;
                             value_min = &value;
@@ -183,7 +211,7 @@ public:
     }
 
 private:
-    typedef typename std::unordered_multimap<Point, ValueType, PointHash> map_type;
+    typedef typename std::unordered_multimap<Vec2crd, ValueType, PointHash> map_type;
     PointAccessor m_point_accessor;
     map_type m_map;
     coord_t  m_search_radius;
@@ -191,113 +219,7 @@ private:
     coord_t  m_grid_log2;
 };
 
-class Point3 : public Point
-{
-public:
-    coord_t z;
-    explicit Point3(coord_t _x = 0, coord_t _y = 0, coord_t _z = 0): Point(_x, _y), z(_z) {};
-    static Point3 new_scale(coordf_t x, coordf_t y, coordf_t z) { return Point3(coord_t(scale_(x)), coord_t(scale_(y)), coord_t(scale_(z))); }
-    bool operator==(const Point3 &rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; }
-    bool operator!=(const Point3 &rhs) const { return ! (*this == rhs); }
-    bool coincides_with(const Point3& rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; }
-private:
-    // Hide the following inherited methods:
-    bool operator==(const Point &rhs) const;
-    bool operator!=(const Point &rhs) const;
-};
-
-std::ostream& operator<<(std::ostream &stm, const Pointf &pointf);
-
-class Pointf
-{
-public:
-    typedef coordf_t coord_type;
-    coordf_t x;
-    coordf_t y;
-    explicit Pointf(coordf_t _x = 0, coordf_t _y = 0): x(_x), y(_y) {};
-    static Pointf new_unscale(coord_t x, coord_t y) {
-        return Pointf(unscale(x), unscale(y));
-    };
-    static Pointf new_unscale(const Point &p) {
-        return Pointf(unscale(p.x), unscale(p.y));
-    };
-    std::string wkt() const;
-    std::string dump_perl() const;
-    void scale(double factor);
-    void translate(double x, double y);
-    void translate(const Vectorf &vector);
-    void rotate(double angle);
-    void rotate(double angle, const Pointf &center);
-    Pointf negative() const;
-    Vectorf vector_to(const Pointf &point) const;
-    
-    Pointf& operator+=(const Pointf& rhs) { this->x += rhs.x; this->y += rhs.y; return *this; }
-    Pointf& operator-=(const Pointf& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; }
-    Pointf& operator*=(const coordf_t& rhs) { this->x *= rhs; this->y *= rhs;   return *this; }
-
-    bool operator==(const Pointf &rhs) const { return this->x == rhs.x && this->y == rhs.y; }
-    bool operator!=(const Pointf &rhs) const { return ! (*this == rhs); }
-    bool operator< (const Pointf& rhs) const { return this->x < rhs.x || (this->x == rhs.x && this->y < rhs.y); }
-};
-
-inline Pointf operator+(const Pointf& point1, const Pointf& point2) { return Pointf(point1.x + point2.x, point1.y + point2.y); }
-inline Pointf operator-(const Pointf& point1, const Pointf& point2) { return Pointf(point1.x - point2.x, point1.y - point2.y); }
-inline Pointf operator*(double scalar, const Pointf& point2) { return Pointf(scalar * point2.x, scalar * point2.y); }
-inline Pointf operator*(const Pointf& point2, double scalar) { return Pointf(scalar * point2.x, scalar * point2.y); }
-inline coordf_t cross(const Pointf &v1, const Pointf &v2) { return v1.x * v2.y - v1.y * v2.x; }
-inline coordf_t dot(const Pointf &v1, const Pointf &v2) { return v1.x * v2.x + v1.y * v2.y; }
-inline coordf_t dot(const Pointf &v) { return v.x * v.x + v.y * v.y; }
-inline double length(const Vectorf &v) { return sqrt(dot(v)); }
-inline double l2(const Vectorf &v) { return dot(v); }
-inline Vectorf normalize(const Vectorf& v)
-{
-    coordf_t len = ::sqrt(sqr(v.x) + sqr(v.y));
-    return (len != 0.0) ? 1.0 / len * v : Vectorf(0.0, 0.0);
-}
-
-class Pointf3 : public Pointf
-{
-public:
-    coordf_t z;
-    explicit Pointf3(coordf_t _x = 0, coordf_t _y = 0, coordf_t _z = 0): Pointf(_x, _y), z(_z) {};
-    static Pointf3 new_unscale(coord_t x, coord_t y, coord_t z) {
-        return Pointf3(unscale(x), unscale(y), unscale(z));
-    };
-    static Pointf3 new_unscale(const Point3& p) { return Pointf3(unscale(p.x), unscale(p.y), unscale(p.z)); }
-    void scale(double factor);
-    void translate(const Vectorf3 &vector);
-    void translate(double x, double y, double z);
-    double distance_to(const Pointf3 &point) const;
-    Pointf3 negative() const;
-    Vectorf3 vector_to(const Pointf3 &point) const;
-
-    bool operator==(const Pointf3 &rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; }
-    bool operator!=(const Pointf3 &rhs) const { return ! (*this == rhs); }
-
-private:
-    // Hide the following inherited methods:
-    bool operator==(const Pointf &rhs) const;
-    bool operator!=(const Pointf &rhs) const;
-};
-
-inline Pointf3 operator+(const Pointf3& p1, const Pointf3& p2) { return Pointf3(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z); }
-inline Pointf3 operator-(const Pointf3& p1, const Pointf3& p2) { return Pointf3(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z); }
-inline Pointf3 operator-(const Pointf3& p) { return Pointf3(-p.x, -p.y, -p.z); }
-inline Pointf3 operator*(double scalar, const Pointf3& p) { return Pointf3(scalar * p.x, scalar * p.y, scalar * p.z); }
-inline Pointf3 operator*(const Pointf3& p, double scalar) { return Pointf3(scalar * p.x, scalar * p.y, scalar * p.z); }
-inline Pointf3 cross(const Pointf3& v1, const Pointf3& v2) { return Pointf3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x); }
-inline coordf_t dot(const Pointf3& v1, const Pointf3& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; }
-inline double length(const Vectorf3 &v) { return ::sqrt(sqr(v.x) + sqr(v.y) + sqr(v.z)); }
-inline Pointf3 normalize(const Pointf3& v)
-{
-    coordf_t len = ::sqrt(sqr(v.x) + sqr(v.y) + sqr(v.z));
-    return (len != 0.0) ? 1.0 / len * v : Pointf3(0.0, 0.0, 0.0);
-}
-
-template<typename TO> inline TO convert_to(const Point &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y)); }
-template<typename TO> inline TO convert_to(const Pointf &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y)); }
-template<typename TO> inline TO convert_to(const Point3 &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y), typename TO::coord_type(src.z)); }
-template<typename TO> inline TO convert_to(const Pointf3 &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y), typename TO::coord_type(src.z)); }
+std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf);
 
 } // namespace Slic3r
 
@@ -313,7 +235,7 @@ namespace boost { namespace polygon {
         typedef coord_t coordinate_type;
     
         static inline coordinate_type get(const Slic3r::Point& point, orientation_2d orient) {
-            return (orient == HORIZONTAL) ? point.x : point.y;
+            return (orient == HORIZONTAL) ? (coordinate_type)point(0) : (coordinate_type)point(1);
         }
     };
     
@@ -322,14 +244,14 @@ namespace boost { namespace polygon {
         typedef coord_t coordinate_type;
         static inline void set(Slic3r::Point& point, orientation_2d orient, coord_t value) {
             if (orient == HORIZONTAL)
-                point.x = value;
+                point(0) = value;
             else
-                point.y = value;
+                point(1) = value;
         }
         static inline Slic3r::Point construct(coord_t x_value, coord_t y_value) {
             Slic3r::Point retval;
-            retval.x = x_value;
-            retval.y = y_value; 
+            retval(0) = x_value;
+            retval(1) = y_value; 
             return retval;
         }
     };
diff --git a/xs/src/libslic3r/Polygon.cpp b/xs/src/libslic3r/Polygon.cpp
index b5fd7e64f..14248d84f 100644
--- a/xs/src/libslic3r/Polygon.cpp
+++ b/xs/src/libslic3r/Polygon.cpp
@@ -44,11 +44,9 @@ Polyline
 Polygon::split_at_vertex(const Point &point) const
 {
     // find index of point
-    for (Points::const_iterator it = this->points.begin(); it != this->points.end(); ++it) {
-        if (it->coincides_with(point)) {
-            return this->split_at_index(it - this->points.begin());
-        }
-    }
+    for (const Point &pt : this->points)
+        if (pt == point)
+            return this->split_at_index(&pt - &this->points.front());
     CONFESS("Point not found");
     return Polyline();
 }
@@ -88,7 +86,7 @@ int64_t Polygon::area2x() const
 
     int64_t a = 0;
     for (size_t i = 0, j = n - 1; i < n; ++i)
-        a += int64_t(poly[j].x + poly[i].x) * int64_t(poly[j].y - poly[i].y);
+        a += int64_t(poly[j](0) + poly[i](0)) * int64_t(poly[j](1) - poly[i](1));
         j = i;
     }
     return -a * 0.5;
@@ -103,7 +101,7 @@ double Polygon::area() const
 
     double a = 0.;
     for (size_t i = 0, j = n - 1; i < n; ++i) {
-        a += ((double)points[j].x + (double)points[i].x) * ((double)points[i].y - (double)points[j].y);
+        a += ((double)points[j](0) + (double)points[i](0)) * ((double)points[i](1) - (double)points[j](1));
         j = i;
     }
     return 0.5 * a;
@@ -157,17 +155,17 @@ Polygon::contains(const Point &point) const
     Points::const_iterator i = this->points.begin();
     Points::const_iterator j = this->points.end() - 1;
     for (; i != this->points.end(); j = i++) {
-        //FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point.y well.
-        // Does the ray with y == point.y intersect this line segment?
+        //FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point(1) well.
+        // Does the ray with y == point(1) intersect this line segment?
 #if 1
-        if ( ((i->y > point.y) != (j->y > point.y))
-            && ((double)point.x < (double)(j->x - i->x) * (double)(point.y - i->y) / (double)(j->y - i->y) + (double)i->x) )
+        if ( (((*i)(1) > point(1)) != ((*j)(1) > point(1)))
+            && ((double)point(0) < (double)((*j)(0) - (*i)(0)) * (double)(point(1) - (*i)(1)) / (double)((*j)(1) - (*i)(1)) + (double)(*i)(0)) )
             result = !result;
 #else
-        if ((i->y > point.y) != (j->y > point.y)) {
+        if (((*i)(1) > point(1)) != ((*j)(1) > point(1))) {
             // Orientation predicated relative to i-th point.
-            double orient = (double)(point.x - i->x) * (double)(j->y - i->y) - (double)(point.y - i->y) * (double)(j->x - i->x);
-            if ((i->y > j->y) ? (orient > 0.) : (orient < 0.))
+            double orient = (double)(point(0) - (*i)(0)) * (double)((*j)(1) - (*i)(1)) - (double)(point(1) - (*i)(1)) * (double)((*j)(0) - (*i)(0));
+            if (((*i)(1) > (*j)(1)) ? (orient > 0.) : (orient < 0.))
                 result = !result;
         }
 #endif
@@ -225,26 +223,13 @@ Polygon::centroid() const
     
     Polyline polyline = this->split_at_first_point();
     for (Points::const_iterator point = polyline.points.begin(); point != polyline.points.end() - 1; ++point) {
-        x_temp += (double)( point->x + (point+1)->x ) * ( (double)point->x*(point+1)->y - (double)(point+1)->x*point->y );
-        y_temp += (double)( point->y + (point+1)->y ) * ( (double)point->x*(point+1)->y - (double)(point+1)->x*point->y );
+        x_temp += (double)( point->x() + (point+1)->x() ) * ( (double)point->x()*(point+1)->y() - (double)(point+1)->x()*point->y() );
+        y_temp += (double)( point->y() + (point+1)->y() ) * ( (double)point->x()*(point+1)->y() - (double)(point+1)->x()*point->y() );
     }
     
     return Point(x_temp/(6*area_temp), y_temp/(6*area_temp));
 }
 
-std::string
-Polygon::wkt() const
-{
-    std::ostringstream wkt;
-    wkt << "POLYGON((";
-    for (Points::const_iterator p = this->points.begin(); p != this->points.end(); ++p) {
-        wkt << p->x << " " << p->y;
-        if (p != this->points.end()-1) wkt << ",";
-    }
-    wkt << "))";
-    return wkt.str();
-}
-
 // find all concave vertices (i.e. having an internal angle greater than the supplied angle)
 // (external = right side, thus we consider ccw orientation)
 Points
@@ -302,24 +287,24 @@ Point Polygon::point_projection(const Point &point) const
         for (size_t i = 0; i < this->points.size(); ++ i) {
             const Point &pt0 = this->points[i];
             const Point &pt1 = this->points[(i + 1 == this->points.size()) ? 0 : i + 1];
-            double d = pt0.distance_to(point);
+            double d = (point - pt0).cast<double>().norm();
             if (d < dmin) {
                 dmin = d;
                 proj = pt0;
             }
-            d = pt1.distance_to(point);
+            d = (point - pt1).cast<double>().norm();
             if (d < dmin) {
                 dmin = d;
                 proj = pt1;
             }
-            Pointf v1(coordf_t(pt1.x - pt0.x), coordf_t(pt1.y - pt0.y));
-            coordf_t div = dot(v1);
+            Vec2d v1(coordf_t(pt1(0) - pt0(0)), coordf_t(pt1(1) - pt0(1)));
+            coordf_t div = v1.squaredNorm();
             if (div > 0.) {
-                Pointf v2(coordf_t(point.x - pt0.x), coordf_t(point.y - pt0.y));
-                coordf_t t = dot(v1, v2) / div;
+                Vec2d v2(coordf_t(point(0) - pt0(0)), coordf_t(point(1) - pt0(1)));
+                coordf_t t = v1.dot(v2) / div;
                 if (t > 0. && t < 1.) {
-                    Point foot(coord_t(floor(coordf_t(pt0.x) + t * v1.x + 0.5)), coord_t(floor(coordf_t(pt0.y) + t * v1.y + 0.5)));
-                    d = foot.distance_to(point);
+                    Point foot(coord_t(floor(coordf_t(pt0(0)) + t * v1(0) + 0.5)), coord_t(floor(coordf_t(pt0(1)) + t * v1(1) + 0.5)));
+                    d = (point - foot).cast<double>().norm();
                     if (d < dmin) {
                         dmin = d;
                         proj = foot;
@@ -376,12 +361,12 @@ static inline bool is_stick(const Point &p1, const Point &p2, const Point &p3)
 {
     Point v1 = p2 - p1;
     Point v2 = p3 - p2;
-    int64_t dir = int64_t(v1.x) * int64_t(v2.x) + int64_t(v1.y) * int64_t(v2.y);
+    int64_t dir = int64_t(v1(0)) * int64_t(v2(0)) + int64_t(v1(1)) * int64_t(v2(1));
     if (dir > 0)
         // p3 does not turn back to p1. Do not remove p2.
         return false;
-    double l2_1 = double(v1.x) * double(v1.x) + double(v1.y) * double(v1.y);
-    double l2_2 = double(v2.x) * double(v2.x) + double(v2.y) * double(v2.y);
+    double l2_1 = double(v1(0)) * double(v1(0)) + double(v1(1)) * double(v1(1));
+    double l2_2 = double(v2(0)) * double(v2(0)) + double(v2(1)) * double(v2(1));
     if (dir == 0)
         // p1, p2, p3 may make a perpendicular corner, or there is a zero edge length.
         // Remove p2 if it is coincident with p1 or p2.
@@ -389,7 +374,7 @@ static inline bool is_stick(const Point &p1, const Point &p2, const Point &p3)
     // p3 turns back to p1 after p2. Are p1, p2, p3 collinear?
     // Calculate distance from p3 to a segment (p1, p2) or from p1 to a segment(p2, p3),
     // whichever segment is longer
-    double cross = double(v1.x) * double(v2.y) - double(v2.x) * double(v1.y);
+    double cross = double(v1(0)) * double(v2(1)) - double(v2(0)) * double(v1(1));
     double dist2 = cross * cross / std::max(l2_1, l2_2);
     return dist2 < EPSILON * EPSILON;
 }
diff --git a/xs/src/libslic3r/Polygon.hpp b/xs/src/libslic3r/Polygon.hpp
index 1a02d78b7..54909352c 100644
--- a/xs/src/libslic3r/Polygon.hpp
+++ b/xs/src/libslic3r/Polygon.hpp
@@ -24,11 +24,12 @@ public:
     explicit Polygon(const Points &points): MultiPoint(points) {}
     Polygon(const Polygon &other) : MultiPoint(other.points) {}
     Polygon(Polygon &&other) : MultiPoint(std::move(other.points)) {}
-	static Polygon new_scale(std::vector<Pointf> points) { 
-		Points int_points;
-		for (auto pt : points)
-			int_points.push_back(Point::new_scale(pt.x, pt.y));
-		return Polygon(int_points);
+	static Polygon new_scale(const std::vector<Vec2d> &points) { 
+        Polygon pgn;
+        pgn.points.reserve(points.size());
+        for (const Vec2d &pt : points)
+            pgn.points.emplace_back(Point::new_scale(pt(0), pt(1)));
+		return pgn;
 	}
     Polygon& operator=(const Polygon &other) { points = other.points; return *this; }
     Polygon& operator=(Polygon &&other) { points = std::move(other.points); return *this; }
@@ -54,7 +55,6 @@ public:
     void simplify(double tolerance, Polygons &polygons) const;
     void triangulate_convex(Polygons* polygons) const;
     Point centroid() const;
-    std::string wkt() const;
     Points concave_points(double angle = PI) const;
     Points convex_points(double angle = PI) const;
     // Projection of a point onto the polygon.
diff --git a/xs/src/libslic3r/Polyline.cpp b/xs/src/libslic3r/Polyline.cpp
index 3432506c6..b2e50bca3 100644
--- a/xs/src/libslic3r/Polyline.cpp
+++ b/xs/src/libslic3r/Polyline.cpp
@@ -33,7 +33,7 @@ Polyline::leftmost_point() const
 {
     Point p = this->points.front();
     for (Points::const_iterator it = this->points.begin() + 1; it != this->points.end(); ++it) {
-        if (it->x < p.x) p = *it;
+        if ((*it)(0) < p(0)) p = *it;
     }
     return p;
 }
@@ -52,92 +52,82 @@ Polyline::lines() const
 }
 
 // removes the given distance from the end of the polyline
-void
-Polyline::clip_end(double distance)
+void Polyline::clip_end(double distance)
 {
     while (distance > 0) {
-        Point last_point = this->last_point();
+        Vec2d  last_point = this->last_point().cast<double>();
         this->points.pop_back();
-        if (this->points.empty()) break;
-        
-        double last_segment_length = last_point.distance_to(this->last_point());
-        if (last_segment_length <= distance) {
-            distance -= last_segment_length;
-            continue;
+        if (this->points.empty())
+            break;
+        Vec2d  v    = this->last_point().cast<double>() - last_point;
+        double lsqr = v.squaredNorm();
+        if (lsqr > distance * distance) {
+            this->points.emplace_back((last_point + v * (distance / sqrt(lsqr))).cast<coord_t>());
+            return;
         }
-        
-        Line segment(last_point, this->last_point());
-        this->points.push_back(segment.point_at(distance));
-        distance = 0;
+        distance -= sqrt(lsqr);
     }
 }
 
 // removes the given distance from the start of the polyline
-void
-Polyline::clip_start(double distance)
+void Polyline::clip_start(double distance)
 {
     this->reverse();
     this->clip_end(distance);
-    if (this->points.size() >= 2) this->reverse();
+    if (this->points.size() >= 2)
+        this->reverse();
 }
 
-void
-Polyline::extend_end(double distance)
+void Polyline::extend_end(double distance)
 {
     // relocate last point by extending the last segment by the specified length
-    Line line(
-        this->points.back(),
-        *(this->points.end() - 2)
-    );
-    this->points.back() = line.point_at(-distance);
+    Vec2d v = (this->points.back() - *(this->points.end() - 2)).cast<double>().normalized();
+    this->points.back() += (v * distance).cast<coord_t>();
 }
 
-void
-Polyline::extend_start(double distance)
+void Polyline::extend_start(double distance)
 {
     // relocate first point by extending the first segment by the specified length
-    this->points.front() = Line(this->points.front(), this->points[1]).point_at(-distance);
+    Vec2d v = (this->points.front() - this->points[1]).cast<double>().normalized();
+    this->points.front() += (v * distance).cast<coord_t>();
 }
 
 /* this method returns a collection of points picked on the polygon contour
    so that they are evenly spaced according to the input distance */
-Points
-Polyline::equally_spaced_points(double distance) const
+Points Polyline::equally_spaced_points(double distance) const
 {
     Points points;
-    points.push_back(this->first_point());
+    points.emplace_back(this->first_point());
     double len = 0;
     
     for (Points::const_iterator it = this->points.begin() + 1; it != this->points.end(); ++it) {
-        double segment_length = it->distance_to(*(it-1));
+        Vec2d  p1 = (it-1)->cast<double>();
+        Vec2d  v  = it->cast<double>() - p1;
+        double segment_length = v.norm();
         len += segment_length;
-        if (len < distance) continue;
-        
+        if (len < distance)
+            continue;
         if (len == distance) {
-            points.push_back(*it);
+            points.emplace_back(*it);
             len = 0;
             continue;
         }
-        
         double take = segment_length - (len - distance);  // how much we take of this segment
-        Line segment(*(it-1), *it);
-        points.push_back(segment.point_at(take));
-        --it;
-        len = -take;
+        points.emplace_back((p1 + v * (take / v.norm())).cast<coord_t>());
+        -- it;
+        len = - take;
     }
     return points;
 }
 
-void
-Polyline::simplify(double tolerance)
+void Polyline::simplify(double tolerance)
 {
     this->points = MultiPoint::_douglas_peucker(this->points, tolerance);
 }
 
 /* This method simplifies all *lines* contained in the supplied area */
 template <class T>
-void
-Polyline::simplify_by_visibility(const T &area)
+void Polyline::simplify_by_visibility(const T &area)
 {
     Points &pp = this->points;
     
@@ -157,30 +147,29 @@ Polyline::simplify_by_visibility(const T &area)
 template void Polyline::simplify_by_visibility<ExPolygon>(const ExPolygon &area);
 template void Polyline::simplify_by_visibility<ExPolygonCollection>(const ExPolygonCollection &area);
 
-void
-Polyline::split_at(const Point &point, Polyline* p1, Polyline* p2) const
+void Polyline::split_at(const Point &point, Polyline* p1, Polyline* p2) const
 {
     if (this->points.empty()) return;
     
     // find the line to split at
     size_t line_idx = 0;
     Point p = this->first_point();
-    double min = point.distance_to(p);
+    double min = (p - point).cast<double>().norm();
     Lines lines = this->lines();
     for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
         Point p_tmp = point.projection_onto(*line);
-        if (point.distance_to(p_tmp) < min) {
+        if ((p_tmp - point).cast<double>().norm() < min) {
 	        p = p_tmp;
-	        min = point.distance_to(p);
+	        min = (p - point).cast<double>().norm();
 	        line_idx = line - lines.begin();
         }
     }
     
     // create first half
     p1->points.clear();
-    for (Lines::const_iterator line = lines.begin(); line != lines.begin() + line_idx + 1; ++line) {
-        if (!line->a.coincides_with(p)) p1->points.push_back(line->a);
-    }
+    for (Lines::const_iterator line = lines.begin(); line != lines.begin() + line_idx + 1; ++line)
+        if (line->a != p) 
+            p1->points.push_back(line->a);
     // we add point instead of p because they might differ because of numerical issues
     // and caller might want to rely on point belonging to result polylines
     p1->points.push_back(point);
@@ -193,8 +182,7 @@ Polyline::split_at(const Point &point, Polyline* p1, Polyline* p2) const
     }
 }
 
-bool
-Polyline::is_straight() const
+bool Polyline::is_straight() const
 {
     /*  Check that each segment's direction is equal to the line connecting
         first point and last point. (Checking each line against the previous
@@ -208,19 +196,6 @@ Polyline::is_straight() const
     return true;
 }
 
-std::string
-Polyline::wkt() const
-{
-    std::ostringstream wkt;
-    wkt << "LINESTRING((";
-    for (Points::const_iterator p = this->points.begin(); p != this->points.end(); ++p) {
-        wkt << p->x << " " << p->y;
-        if (p != this->points.end()-1) wkt << ",";
-    }
-    wkt << "))";
-    return wkt.str();
-}
-
 BoundingBox get_extents(const Polyline &polyline)
 {
     return polyline.bounding_box();
@@ -254,30 +229,17 @@ bool remove_degenerate(Polylines &polylines)
     return modified;
 }
 
-ThickLines
-ThickPolyline::thicklines() const
+ThickLines ThickPolyline::thicklines() const
 {
     ThickLines lines;
     if (this->points.size() >= 2) {
         lines.reserve(this->points.size() - 1);
-        for (size_t i = 0; i < this->points.size()-1; ++i) {
-            ThickLine line(this->points[i], this->points[i+1]);
-            line.a_width = this->width[2*i];
-            line.b_width = this->width[2*i+1];
-            lines.push_back(line);
-        }
+        for (size_t i = 0; i + 1 < this->points.size(); ++ i)
+            lines.emplace_back(this->points[i], this->points[i + 1], this->width[2 * i], this->width[2 * i + 1]);
     }
     return lines;
 }
 
-void
-ThickPolyline::reverse()
-{
-    Polyline::reverse();
-    std::reverse(this->width.begin(), this->width.end());
-    std::swap(this->endpoints.first, this->endpoints.second);
-}
-
 Lines3 Polyline3::lines() const
 {
     Lines3 lines;
diff --git a/xs/src/libslic3r/Polyline.hpp b/xs/src/libslic3r/Polyline.hpp
index b64743d84..0c934e074 100644
--- a/xs/src/libslic3r/Polyline.hpp
+++ b/xs/src/libslic3r/Polyline.hpp
@@ -19,14 +19,15 @@ public:
     Polyline() {};
     Polyline(const Polyline &other) : MultiPoint(other.points) {}
     Polyline(Polyline &&other) : MultiPoint(std::move(other.points)) {}
+    Polyline(std::initializer_list<Point> list) : MultiPoint(list) {}
+    explicit Polyline(const Point &p1, const Point &p2) { points.reserve(2); points.emplace_back(p1); points.emplace_back(p2); }
     Polyline& operator=(const Polyline &other) { points = other.points; return *this; }
     Polyline& operator=(Polyline &&other) { points = std::move(other.points); return *this; }
-	static Polyline new_scale(std::vector<Pointf> points) {
+	static Polyline new_scale(const std::vector<Vec2d> &points) {
 		Polyline pl;
-		Points int_points;
-		for (auto pt : points)
-			int_points.push_back(Point::new_scale(pt.x, pt.y));
-		pl.append(int_points);
+		pl.points.reserve(points.size());
+		for (const Vec2d &pt : points)
+			pl.points.emplace_back(Point::new_scale(pt(0), pt(1)));
 		return pl;
     }
     
@@ -71,7 +72,6 @@ public:
     template <class T> void simplify_by_visibility(const T &area);
     void split_at(const Point &point, Polyline* p1, Polyline* p2) const;
     bool is_straight() const;
-    std::string wkt() const;
 };
 
 extern BoundingBox get_extents(const Polyline &polyline);
@@ -129,12 +129,17 @@ inline void polylines_append(Polylines &dst, Polylines &&src)
 bool remove_degenerate(Polylines &polylines);
 
 class ThickPolyline : public Polyline {
-    public:
-    std::vector<coordf_t> width;
-    std::pair<bool,bool> endpoints;
-    ThickPolyline() : endpoints(std::make_pair(false, false)) {};
+public:
+    ThickPolyline() : endpoints(std::make_pair(false, false)) {}
     ThickLines thicklines() const;
-    void reverse();
+    void reverse() {
+        Polyline::reverse();
+        std::reverse(this->width.begin(), this->width.end());
+        std::swap(this->endpoints.first, this->endpoints.second);
+    }
+
+    std::vector<coordf_t> width;
+    std::pair<bool,bool>  endpoints;
 };
 
 class Polyline3 : public MultiPoint3
diff --git a/xs/src/libslic3r/PolylineCollection.cpp b/xs/src/libslic3r/PolylineCollection.cpp
index ca9c64d23..3f65ea699 100644
--- a/xs/src/libslic3r/PolylineCollection.cpp
+++ b/xs/src/libslic3r/PolylineCollection.cpp
@@ -15,9 +15,9 @@ inline int nearest_point_index(const std::vector<Chaining> &pairs, const Point &
     T dmin = std::numeric_limits<T>::max();
     int idx = 0;
     for (std::vector<Chaining>::const_iterator it = pairs.begin(); it != pairs.end(); ++it) {
-        T d = sqr(T(start_near.x - it->first.x));
+        T d = sqr(T(start_near(0) - it->first(0)));
         if (d <= dmin) {
-            d += sqr(T(start_near.y - it->first.y));
+            d += sqr(T(start_near(1) - it->first(1)));
             if (d < dmin) {
                 idx = (it - pairs.begin()) * 2;
                 dmin = d;
@@ -26,9 +26,9 @@ inline int nearest_point_index(const std::vector<Chaining> &pairs, const Point &
             }
         }
         if (! no_reverse) {
-            d = sqr(T(start_near.x - it->last.x));
+            d = sqr(T(start_near(0) - it->last(0)));
             if (d <= dmin) {
-                d += sqr(T(start_near.y - it->last.y));
+                d += sqr(T(start_near(1) - it->last(1)));
                 if (d < dmin) {
                     idx = (it - pairs.begin()) * 2 + 1;
                     dmin = d;
@@ -82,7 +82,7 @@ Point PolylineCollection::leftmost_point(const Polylines &polylines)
     Point p = it->leftmost_point();
     for (++ it; it != polylines.end(); ++it) {
         Point p2 = it->leftmost_point();
-        if (p2.x < p.x) 
+        if (p2(0) < p(0))
             p = p2;
     }
     return p;
diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp
index 7d2906bcc..230201cc1 100644
--- a/xs/src/libslic3r/Print.cpp
+++ b/xs/src/libslic3r/Print.cpp
@@ -536,9 +536,9 @@ bool Print::has_skirt() const
 std::string Print::validate() const
 {
     BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.bed_shape.values));
-    BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height));
+	BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(config.max_print_height)));
     // Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
-    print_volume.min.z = -1e10;
+    print_volume.min(2) = -1e10;
     unsigned int printable_count = 0;
     for (PrintObject *po : this->objects) {
         po->model_object()->check_instances_print_volume_state(print_volume);
@@ -583,7 +583,7 @@ std::string Print::validate() const
         {
             std::vector<coord_t> object_height;
             for (const PrintObject *object : this->objects)
-                object_height.insert(object_height.end(), object->copies().size(), object->size.z);
+                object_height.insert(object_height.end(), object->copies().size(), object->size(2));
             std::sort(object_height.begin(), object_height.end());
             // Ignore the tallest *copy* (this is why we repeat height for all of them):
             // it will be printed as last one so its height doesn't matter.
@@ -724,7 +724,7 @@ BoundingBox Print::bounding_box() const
     for (const PrintObject *object : this->objects)
         for (Point copy : object->_shifted_copies) {
             bb.merge(copy);
-            copy.translate(object->size);
+            copy += to_2d(object->size);
             bb.merge(copy);
         }
     return bb;
@@ -900,7 +900,7 @@ void Print::_make_skirt()
         for (const Point &shift : object->_shifted_copies) {
             Points copy_points = object_points;
             for (Point &pt : copy_points)
-                pt.translate(shift);
+                pt += shift;
             append(points, copy_points);
         }
     }
@@ -967,7 +967,7 @@ void Print::_make_skirt()
         this->skirt.append(eloop);
         if (this->config.min_skirt_length.value > 0) {
             // The skirt length is limited. Sum the total amount of filament length extruded, in mm.
-            extruded_length[extruder_idx] += unscale(loop.length()) * extruders_e_per_mm[extruder_idx];
+            extruded_length[extruder_idx] += unscale<double>(loop.length()) * extruders_e_per_mm[extruder_idx];
             if (extruded_length[extruder_idx] < this->config.min_skirt_length.value) {
                 // Not extruded enough yet with the current extruder. Add another loop.
                 if (i == 1)
@@ -1052,7 +1052,7 @@ void Print::_make_wipe_tower()
     m_wipe_tower_depth = 0.f;
 
     // Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
-    std::vector<float> wiping_matrix((this->config.wiping_volumes_matrix.values).begin(),(this->config.wiping_volumes_matrix.values).end());
+    std::vector<float> wiping_matrix(cast<float>(this->config.wiping_volumes_matrix.values));
     // Extract purging volumes for each extruder pair:
     std::vector<std::vector<float>> wipe_volumes;
     const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON);
diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp
index e3430ad0e..82fedbc7b 100644
--- a/xs/src/libslic3r/Print.hpp
+++ b/xs/src/libslic3r/Print.hpp
@@ -118,7 +118,7 @@ public:
     // so that next call to make_perimeters() performs a union() before computing loops
     bool typed_slices;
 
-    Point3 size;           // XYZ in scaled coordinates
+    Vec3crd size;           // XYZ in scaled coordinates
 
     // scaled coordinates to add to copies (to compensate for the alignment
     // operated when creating the object but still preserving a coherent API
@@ -138,13 +138,13 @@ public:
     const ModelObject*  model_object() const    { return this->_model_object; }
 
     const Points& copies() const { return this->_copies; }
-    bool add_copy(const Pointf &point);
+    bool add_copy(const Vec2d &point);
     bool delete_last_copy();
     bool delete_all_copies() { return this->set_copies(Points()); }
     bool set_copies(const Points &points);
     bool reload_model_instances();
     // since the object is aligned to origin, bounding box coincides with size
-    BoundingBox bounding_box() const { return BoundingBox(Point(0,0), this->size); }
+    BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); }
 
     // adds region_id, too, if necessary
     void add_region_volume(unsigned int region_id, int volume_id) {
diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp
index bf5f734ac..400530151 100644
--- a/xs/src/libslic3r/PrintConfig.cpp
+++ b/xs/src/libslic3r/PrintConfig.cpp
@@ -35,7 +35,7 @@ PrintConfigDef::PrintConfigDef()
 
     def = this->add("bed_shape", coPoints);
 	def->label = L("Bed shape");
-    def->default_value = new ConfigOptionPoints { Pointf(0,0), Pointf(200,0), Pointf(200,200), Pointf(0,200) };
+    def->default_value = new ConfigOptionPoints { Vec2d(0,0), Vec2d(200,0), Vec2d(200,200), Vec2d(0,200) };
     
     def = this->add("bed_temperature", coInts);
     def->label = L("Other layers");
@@ -392,7 +392,7 @@ PrintConfigDef::PrintConfigDef()
                    "from the XY coordinate).");
     def->sidetext = L("mm");
     def->cli = "extruder-offset=s@";
-    def->default_value = new ConfigOptionPoints { Pointf(0,0) };
+    def->default_value = new ConfigOptionPoints { Vec2d(0,0) };
 
     def = this->add("extrusion_axis", coString);
     def->label = L("Extrusion axis");
@@ -2117,7 +2117,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
         ConfigOptionPoint p;
         p.deserialize(value);
         std::ostringstream oss;
-        oss << "0x0," << p.value.x << "x0," << p.value.x << "x" << p.value.y << ",0x" << p.value.y;
+        oss << "0x0," << p.value(0) << "x0," << p.value(0) << "x" << p.value(1) << ",0x" << p.value(1);
         value = oss.str();
     } else if ((opt_key == "perimeter_acceleration" && value == "25")
         || (opt_key == "infill_acceleration" && value == "50")) {
diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp
index 7150ead59..d03b99416 100644
--- a/xs/src/libslic3r/PrintObject.cpp
+++ b/xs/src/libslic3r/PrintObject.cpp
@@ -38,6 +38,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
     typed_slices(false),
     _print(print),
     _model_object(model_object),
+    size(Vec3crd::Zero()),
     layer_height_profile_valid(false)
 {
     // Compute the translation to be applied to our meshes so that we work with smaller coordinates
@@ -48,10 +49,9 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
         // don't assume it's already aligned and we don't alter the original position in model.
         // We store the XY translation so that we can place copies correctly in the output G-code
         // (copies are expressed in G-code coordinates and this translation is not publicly exposed).
-        this->_copies_shift = Point::new_scale(modobj_bbox.min.x, modobj_bbox.min.y);
+        this->_copies_shift = Point::new_scale(modobj_bbox.min(0), modobj_bbox.min(1));
         // Scale the object size and store it
-        Pointf3 size = modobj_bbox.size();
-        this->size = Point3::new_scale(size.x, size.y, size.z);
+        this->size = (modobj_bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
     }
     
     this->reload_model_instances();
@@ -59,10 +59,10 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
     this->layer_height_profile = model_object->layer_height_profile;
 }
 
-bool PrintObject::add_copy(const Pointf &point)
+bool PrintObject::add_copy(const Vec2d &point)
 {
     Points points = this->_copies;
-    points.push_back(Point::new_scale(point.x, point.y));
+    points.push_back(Point::new_scale(point(0), point(1)));
     return this->set_copies(points);
 }
 
@@ -86,11 +86,8 @@ bool PrintObject::set_copies(const Points &points)
     std::vector<Points::size_type> ordered_copies;
     Slic3r::Geometry::chained_path(points, ordered_copies);
     
-    for (size_t point_idx : ordered_copies) {
-        Point copy = points[point_idx];
-        copy.translate(this->_copies_shift);
-        this->_shifted_copies.push_back(copy);
-    }
+    for (size_t point_idx : ordered_copies)
+        this->_shifted_copies.push_back(points[point_idx] + this->_copies_shift);
     
     bool invalidated = this->_print->invalidate_step(psSkirt);
     invalidated |= this->_print->invalidate_step(psBrim);
@@ -106,7 +103,7 @@ bool PrintObject::reload_model_instances()
     for (const ModelInstance *mi : this->_model_object->instances)
     {
         if (mi->is_printable())
-            copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y));
+            copies.emplace_back(Point::new_scale(mi->offset(0), mi->offset(1)));
     }
     return this->set_copies(copies);
 }
@@ -1124,7 +1121,7 @@ SlicingParameters PrintObject::slicing_parameters() const
 {
     return SlicingParameters::create_from_config(
         this->print()->config, this->config, 
-        unscale(this->size.z), this->print()->object_extruders());
+        unscale<double>(this->size(2)), this->print()->object_extruders());
 }
 
 bool PrintObject::update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const
@@ -1338,7 +1335,7 @@ std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::
                 // consider the first one
                 this->model_object()->instances.front()->transform_mesh(&mesh, true);
                 // align mesh to Z = 0 (it should be already aligned actually) and apply XY shift
-                mesh.translate(- float(unscale(this->_copies_shift.x)), - float(unscale(this->_copies_shift.y)), -float(this->model_object()->bounding_box().min.z));
+                mesh.translate(- unscale<float>(this->_copies_shift(0)), - unscale<float>(this->_copies_shift(1)), - float(this->model_object()->bounding_box().min(2)));
                 // perform actual slicing
                 TriangleMeshSlicer mslicer(&mesh);
                 mslicer.slice(z, &layers);
diff --git a/xs/src/libslic3r/SVG.cpp b/xs/src/libslic3r/SVG.cpp
index c94db8e74..03f55802e 100644
--- a/xs/src/libslic3r/SVG.cpp
+++ b/xs/src/libslic3r/SVG.cpp
@@ -3,7 +3,7 @@
 
 #include <boost/nowide/cstdio.hpp>
 
-#define COORD(x) ((float)unscale((x))*10)
+#define COORD(x) (unscale<float>((x))*10)
 
 namespace Slic3r {
 
@@ -32,8 +32,8 @@ bool SVG::open(const char* afilename, const BoundingBox &bbox, const coord_t bbo
     this->f        = boost::nowide::fopen(afilename, "w");
     if (f == NULL)
         return false;
-    float w = COORD(bbox.max.x - bbox.min.x + 2 * bbox_offset);
-    float h = COORD(bbox.max.y - bbox.min.y + 2 * bbox_offset);
+    float w = COORD(bbox.max(0) - bbox.min(0) + 2 * bbox_offset);
+    float h = COORD(bbox.max(1) - bbox.min(1) + 2 * bbox_offset);
     fprintf(this->f,
         "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
         "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
@@ -50,7 +50,7 @@ SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width)
 {
     fprintf(this->f,
         "   <line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke: %s; stroke-width: %f\"",
-        COORD(line.a.x - origin.x), COORD(line.a.y - origin.y), COORD(line.b.x - origin.x), COORD(line.b.y - origin.y), stroke.c_str(), (stroke_width == 0) ? 1.f : COORD(stroke_width));
+        COORD(line.a(0) - origin(0)), COORD(line.a(1) - origin(1)), COORD(line.b(0) - origin(0)), COORD(line.b(1) - origin(1)), stroke.c_str(), (stroke_width == 0) ? 1.f : COORD(stroke_width));
     if (this->arrows)
         fprintf(this->f, " marker-end=\"url(#endArrow)\"");
     fprintf(this->f, "/>\n");
@@ -58,21 +58,21 @@ SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width)
 
 void SVG::draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coordf_t stroke_width)
 {
-    Pointf dir(line.b.x-line.a.x, line.b.y-line.a.y);
-    Pointf perp(-dir.y, dir.x);
-    coordf_t len = sqrt(perp.x*perp.x + perp.y*perp.y);
+    Vec2d dir(line.b(0)-line.a(0), line.b(1)-line.a(1));
+    Vec2d perp(-dir(1), dir(0));
+    coordf_t len = sqrt(perp(0)*perp(0) + perp(1)*perp(1));
     coordf_t da  = coordf_t(0.5)*line.a_width/len;
     coordf_t db  = coordf_t(0.5)*line.b_width/len;
     fprintf(this->f,
         "   <polygon points=\"%f,%f %f,%f %f,%f %f,%f\" style=\"fill:%s; stroke: %s; stroke-width: %f\"/>\n",
-        COORD(line.a.x-da*perp.x-origin.x),
-        COORD(line.a.y-da*perp.y-origin.y),
-        COORD(line.b.x-db*perp.x-origin.x),
-        COORD(line.b.y-db*perp.y-origin.y),
-        COORD(line.b.x+db*perp.x-origin.x),
-        COORD(line.b.y+db*perp.y-origin.y),
-        COORD(line.a.x+da*perp.x-origin.x),
-        COORD(line.a.y+da*perp.y-origin.y),
+        COORD(line.a(0)-da*perp(0)-origin(0)),
+        COORD(line.a(1)-da*perp(1)-origin(1)),
+        COORD(line.b(0)-db*perp(0)-origin(0)),
+        COORD(line.b(1)-db*perp(1)-origin(1)),
+        COORD(line.b(0)+db*perp(0)-origin(0)),
+        COORD(line.b(1)+db*perp(1)-origin(1)),
+        COORD(line.a(0)+da*perp(0)-origin(0)),
+        COORD(line.a(1)+da*perp(1)-origin(1)),
         fill.c_str(), stroke.c_str(),
         (stroke_width == 0) ? 1.f : COORD(stroke_width));
 }
@@ -220,7 +220,7 @@ SVG::draw(const Point &point, std::string fill, coord_t iradius)
 {
     float radius = (iradius == 0) ? 3.f : COORD(iradius);
     std::ostringstream svg;
-    svg << "   <circle cx=\"" << COORD(point.x - origin.x) << "\" cy=\"" << COORD(point.y - origin.y)
+    svg << "   <circle cx=\"" << COORD(point(0) - origin(0)) << "\" cy=\"" << COORD(point(1) - origin(1))
         << "\" r=\"" << radius << "\" "
         << "style=\"stroke: none; fill: " << fill << "\" />";
     
@@ -287,8 +287,8 @@ SVG::get_path_d(const MultiPoint &mp, bool closed) const
     std::ostringstream d;
     d << "M ";
     for (Points::const_iterator p = mp.points.begin(); p != mp.points.end(); ++p) {
-        d << COORD(p->x - origin.x) << " ";
-        d << COORD(p->y - origin.y) << " ";
+        d << COORD((*p)(0) - origin(0)) << " ";
+        d << COORD((*p)(1) - origin(1)) << " ";
     }
     if (closed) d << "z";
     return d.str();
@@ -300,8 +300,8 @@ SVG::get_path_d(const ClipperLib::Path &path, double scale, bool closed) const
     std::ostringstream d;
     d << "M ";
     for (ClipperLib::Path::const_iterator p = path.begin(); p != path.end(); ++p) {
-        d << COORD(scale * p->X - origin.x) << " ";
-        d << COORD(scale * p->Y - origin.y) << " ";
+        d << COORD(scale * p->X - origin(0)) << " ";
+        d << COORD(scale * p->Y - origin(1)) << " ";
     }
     if (closed) d << "z";
     return d.str();
@@ -311,8 +311,8 @@ void SVG::draw_text(const Point &pt, const char *text, const char *color)
 {
     fprintf(this->f,
         "<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"20px\" fill=\"%s\">%s</text>",
-        COORD(pt.x-origin.x),
-        COORD(pt.y-origin.y),
+        COORD(pt(0)-origin(0)),
+        COORD(pt(1)-origin(1)),
         color, text);
 }
 
@@ -320,13 +320,13 @@ void SVG::draw_legend(const Point &pt, const char *text, const char *color)
 {
     fprintf(this->f,
         "<circle cx=\"%f\" cy=\"%f\" r=\"10\" fill=\"%s\"/>",
-        COORD(pt.x-origin.x),
-        COORD(pt.y-origin.y),
+        COORD(pt(0)-origin(0)),
+        COORD(pt(1)-origin(1)),
         color);
     fprintf(this->f,
         "<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"10px\" fill=\"%s\">%s</text>",
-        COORD(pt.x-origin.x) + 20.f,
-        COORD(pt.y-origin.y),
+        COORD(pt(0)-origin(0)) + 20.f,
+        COORD(pt(1)-origin(1)),
         "black", text);
 }
 
diff --git a/xs/src/libslic3r/Slicing.cpp b/xs/src/libslic3r/Slicing.cpp
index e9295d1e3..1bc38502b 100644
--- a/xs/src/libslic3r/Slicing.cpp
+++ b/xs/src/libslic3r/Slicing.cpp
@@ -561,15 +561,15 @@ int generate_layer_height_texture(
 	void *data, int rows, int cols, bool level_of_detail_2nd_level)
 {
 // https://github.com/aschn/gnuplot-colorbrewer
-    std::vector<Point3> palette_raw;
-    palette_raw.push_back(Point3(0x01A, 0x098, 0x050));
-    palette_raw.push_back(Point3(0x066, 0x0BD, 0x063));
-    palette_raw.push_back(Point3(0x0A6, 0x0D9, 0x06A));
-    palette_raw.push_back(Point3(0x0D9, 0x0F1, 0x0EB));
-    palette_raw.push_back(Point3(0x0FE, 0x0E6, 0x0EB));
-    palette_raw.push_back(Point3(0x0FD, 0x0AE, 0x061));
-    palette_raw.push_back(Point3(0x0F4, 0x06D, 0x043));
-    palette_raw.push_back(Point3(0x0D7, 0x030, 0x027));
+    std::vector<Vec3crd> palette_raw;
+    palette_raw.push_back(Vec3crd(0x01A, 0x098, 0x050));
+    palette_raw.push_back(Vec3crd(0x066, 0x0BD, 0x063));
+    palette_raw.push_back(Vec3crd(0x0A6, 0x0D9, 0x06A));
+    palette_raw.push_back(Vec3crd(0x0D9, 0x0F1, 0x0EB));
+    palette_raw.push_back(Vec3crd(0x0FE, 0x0E6, 0x0EB));
+    palette_raw.push_back(Vec3crd(0x0FD, 0x0AE, 0x061));
+    palette_raw.push_back(Vec3crd(0x0F4, 0x06D, 0x043));
+    palette_raw.push_back(Vec3crd(0x0D7, 0x030, 0x027));
 
     // Clear the main texture and the 2nd LOD level.
 //	memset(data, 0, rows * cols * (level_of_detail_2nd_level ? 5 : 4));
@@ -600,25 +600,25 @@ int generate_layer_height_texture(
             int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf)));
             int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1);
 			coordf_t t = idxf - coordf_t(idx1);
-            const Point3 &color1 = palette_raw[idx1];
-            const Point3 &color2 = palette_raw[idx2];
+            const Vec3crd &color1 = palette_raw[idx1];
+            const Vec3crd &color2 = palette_raw[idx2];
             coordf_t z = cell_to_z * coordf_t(cell);
 			assert(z >= lo && z <= hi);
             // Intensity profile to visualize the layers.
             coordf_t intensity = cos(M_PI * 0.7 * (mid - z) / h);
             // Color mapping from layer height to RGB.
-            Pointf3 color(
-                intensity * lerp(coordf_t(color1.x), coordf_t(color2.x), t), 
-                intensity * lerp(coordf_t(color1.y), coordf_t(color2.y), t),
-                intensity * lerp(coordf_t(color1.z), coordf_t(color2.z), t));
+            Vec3d color(
+                intensity * lerp(coordf_t(color1(0)), coordf_t(color2(0)), t), 
+                intensity * lerp(coordf_t(color1(1)), coordf_t(color2(1)), t),
+                intensity * lerp(coordf_t(color1(2)), coordf_t(color2(2)), t));
             int row = cell / (cols - 1);
             int col = cell - row * (cols - 1);
 			assert(row >= 0 && row < rows);
 			assert(col >= 0 && col < cols);
             unsigned char *ptr = (unsigned char*)data + (row * cols + col) * 4;
-            ptr[0] = (unsigned char)clamp<int>(0, 255, int(floor(color.x + 0.5)));
-            ptr[1] = (unsigned char)clamp<int>(0, 255, int(floor(color.y + 0.5)));
-            ptr[2] = (unsigned char)clamp<int>(0, 255, int(floor(color.z + 0.5)));
+            ptr[0] = (unsigned char)clamp<int>(0, 255, int(floor(color(0) + 0.5)));
+            ptr[1] = (unsigned char)clamp<int>(0, 255, int(floor(color(1) + 0.5)));
+            ptr[2] = (unsigned char)clamp<int>(0, 255, int(floor(color(2) + 0.5)));
             ptr[3] = 255;
             if (col == 0 && row > 0) {
                 // Duplicate the first value in a row as a last value of the preceding row.
@@ -636,21 +636,21 @@ int generate_layer_height_texture(
                 int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf)));
                 int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1);
     			coordf_t t = idxf - coordf_t(idx1);
-                const Point3 &color1 = palette_raw[idx1];
-                const Point3 &color2 = palette_raw[idx2];
+                const Vec3crd &color1 = palette_raw[idx1];
+                const Vec3crd &color2 = palette_raw[idx2];
                 // Color mapping from layer height to RGB.
-                Pointf3 color(
-                    lerp(coordf_t(color1.x), coordf_t(color2.x), t), 
-                    lerp(coordf_t(color1.y), coordf_t(color2.y), t),
-                    lerp(coordf_t(color1.z), coordf_t(color2.z), t));
+                Vec3d color(
+                    lerp(coordf_t(color1(0)), coordf_t(color2(0)), t), 
+                    lerp(coordf_t(color1(1)), coordf_t(color2(1)), t),
+                    lerp(coordf_t(color1(2)), coordf_t(color2(2)), t));
                 int row = cell / (cols1 - 1);
                 int col = cell - row * (cols1 - 1);
     			assert(row >= 0 && row < rows/2);
     			assert(col >= 0 && col < cols/2);
                 unsigned char *ptr = data1 + (row * cols1 + col) * 4;
-                ptr[0] = (unsigned char)clamp<int>(0, 255, int(floor(color.x + 0.5)));
-                ptr[1] = (unsigned char)clamp<int>(0, 255, int(floor(color.y + 0.5)));
-                ptr[2] = (unsigned char)clamp<int>(0, 255, int(floor(color.z + 0.5)));
+                ptr[0] = (unsigned char)clamp<int>(0, 255, int(floor(color(0) + 0.5)));
+                ptr[1] = (unsigned char)clamp<int>(0, 255, int(floor(color(1) + 0.5)));
+                ptr[2] = (unsigned char)clamp<int>(0, 255, int(floor(color(2) + 0.5)));
                 ptr[3] = 255;
                 if (col == 0 && row > 0) {
                     // Duplicate the first value in a row as a last value of the preceding row.
diff --git a/xs/src/libslic3r/SlicingAdaptive.cpp b/xs/src/libslic3r/SlicingAdaptive.cpp
index ff0da7636..2ef4aec8c 100644
--- a/xs/src/libslic3r/SlicingAdaptive.cpp
+++ b/xs/src/libslic3r/SlicingAdaptive.cpp
@@ -15,8 +15,8 @@ void SlicingAdaptive::clear()
 std::pair<float, float> face_z_span(const stl_facet *f)
 {
 	return std::pair<float, float>(
-		std::min(std::min(f->vertex[0].z, f->vertex[1].z), f->vertex[2].z),
-		std::max(std::max(f->vertex[0].z, f->vertex[1].z), f->vertex[2].z));
+		std::min(std::min(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)),
+		std::max(std::max(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)));
 }
 
 void SlicingAdaptive::prepare()
@@ -40,7 +40,7 @@ void SlicingAdaptive::prepare()
 	// 3) Generate Z components of the facet normals.
 	m_face_normal_z.assign(m_faces.size(), 0.f);
     for (size_t iface = 0; iface < m_faces.size(); ++ iface)
-    	m_face_normal_z[iface] = m_faces[iface]->normal.z;
+    	m_face_normal_z[iface] = m_faces[iface]->normal(2);
 }
 
 float SlicingAdaptive::cusp_height(float z, float cusp_value, int &current_facet)
diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp
index 0cecf0014..4b7e78976 100644
--- a/xs/src/libslic3r/SupportMaterial.cpp
+++ b/xs/src/libslic3r/SupportMaterial.cpp
@@ -67,9 +67,9 @@ Point export_support_surface_type_legend_to_svg_box_size()
 void export_support_surface_type_legend_to_svg(SVG &svg, const Point &pos)
 {
     // 1st row
-    coord_t pos_x0 = pos.x + scale_(1.);
+    coord_t pos_x0 = pos(0) + scale_(1.);
     coord_t pos_x = pos_x0;
-    coord_t pos_y = pos.y + scale_(1.5);
+    coord_t pos_y = pos(1) + scale_(1.5);
     coord_t step_x = scale_(10.);
     svg.draw_legend(Point(pos_x, pos_y), "top contact"    , support_surface_type_to_color_name(PrintObjectSupportMaterial::sltTopContact));
     pos_x += step_x;
@@ -82,7 +82,7 @@ void export_support_surface_type_legend_to_svg(SVG &svg, const Point &pos)
     svg.draw_legend(Point(pos_x, pos_y), "bottom contact" , support_surface_type_to_color_name(PrintObjectSupportMaterial::sltBottomContact));
     // 2nd row
     pos_x = pos_x0;
-    pos_y = pos.y+scale_(2.8);
+    pos_y = pos(1)+scale_(2.8);
     svg.draw_legend(Point(pos_x, pos_y), "raft interface" , support_surface_type_to_color_name(PrintObjectSupportMaterial::sltRaftInterface));
     pos_x += step_x;
     svg.draw_legend(Point(pos_x, pos_y), "raft base"      , support_surface_type_to_color_name(PrintObjectSupportMaterial::sltRaftBase));
@@ -98,8 +98,8 @@ void export_print_z_polygons_to_svg(const char *path, PrintObjectSupportMaterial
     for (int i = 0; i < n_layers; ++ i)
         bbox.merge(get_extents(layers[i]->polygons));
     Point legend_size = export_support_surface_type_legend_to_svg_box_size();
-    Point legend_pos(bbox.min.x, bbox.max.y);
-    bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
+    Point legend_pos(bbox.min(0), bbox.max(1));
+    bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
     SVG svg(path, bbox);
     const float transparency = 0.5f;
     for (int i = 0; i < n_layers; ++ i)
@@ -120,8 +120,8 @@ void export_print_z_polygons_and_extrusions_to_svg(
     for (int i = 0; i < n_layers; ++ i)
         bbox.merge(get_extents(layers[i]->polygons));
     Point legend_size = export_support_surface_type_legend_to_svg_box_size();
-    Point legend_pos(bbox.min.x, bbox.max.y);
-    bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
+    Point legend_pos(bbox.min(0), bbox.max(1));
+    bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
     SVG svg(path, bbox);
     const float transparency = 0.5f;
     for (int i = 0; i < n_layers; ++ i)
@@ -506,8 +506,8 @@ public:
 
         for (ExPolygon &island : islands) {
             BoundingBox bbox = get_extents(island.contour);
-            auto it_lower = std::lower_bound(m_island_samples.begin(), m_island_samples.end(), bbox.min - Point(1, 1));
-            auto it_upper = std::upper_bound(m_island_samples.begin(), m_island_samples.end(), bbox.max + Point(1, 1));
+            auto it_lower = std::lower_bound(m_island_samples.begin(), m_island_samples.end(), Point(bbox.min - Point(1, 1)));
+            auto it_upper = std::upper_bound(m_island_samples.begin(), m_island_samples.end(), Point(bbox.max + Point(1, 1)));
             samples_inside.clear();
             for (auto it = it_lower; it != it_upper; ++ it)
                 if (bbox.contains(*it))
@@ -519,12 +519,12 @@ public:
                     Points::const_iterator i = contour.points.begin();
                     Points::const_iterator j = contour.points.end() - 1;
                     for (; i != contour.points.end(); j = i ++) {
-                        //FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point.y well.
-                        // Does the ray with y == point.y intersect this line segment?
+                        //FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point(1) well.
+                        // Does the ray with y == point(1) intersect this line segment?
                         for (auto &sample_inside : samples_inside) {
-                            if ((i->y > sample_inside.first.y) != (j->y > sample_inside.first.y)) {
-                                double x1 = (double)sample_inside.first.x;
-                                double x2 = (double)i->x + (double)(j->x - i->x) * (double)(sample_inside.first.y - i->y) / (double)(j->y - i->y);
+                            if (((*i)(1) > sample_inside.first(1)) != ((*j)(1) > sample_inside.first(1))) {
+                                double x1 = (double)sample_inside.first(0);
+                                double x2 = (double)(*i)(0) + (double)((*j)(0) - (*i)(0)) * (double)(sample_inside.first(1) - (*i)(1)) / (double)((*j)(1) - (*i)(1));
                                 if (x1 < x2)
                                     sample_inside.second = !sample_inside.second;
                             }
@@ -585,11 +585,11 @@ private:
         const Point &p3 = (pt_min == &expoly.contour.points.back()) ? expoly.contour.points.front() : *(pt_min + 1);
 
         Vector v  = (p3 - p2) + (p1 - p2);
-        double l2 = double(v.x)*double(v.x)+double(v.y)*double(v.y);
+        double l2 = double(v(0))*double(v(0))+double(v(1))*double(v(1));
         if (l2 == 0.)
             return p2;
         double coef = 20. / sqrt(l2);
-        return Point(p2.x + coef * v.x, p2.y + coef * v.y);
+        return Point(p2(0) + coef * v(0), p2(1) + coef * v(1));
     }
 
     static Points island_samples(const ExPolygons &expolygons)
@@ -789,7 +789,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
                                     
                                     // workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline()
                                     for (Polyline &polyline : overhang_perimeters)
-                                        polyline.points[0].x += 1;
+                                        polyline.points[0](0) += 1;
                                     // Trim the perimeters of this layer by the lower layer to get the unsupported pieces of perimeters.
                                     overhang_perimeters = diff_pl(overhang_perimeters, lower_grown_slices);
                                     
@@ -2057,11 +2057,11 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
                         const Point &p1 = *(it-1);
                         const Point &p2 = *it;
                         // Intersection of a ray (p1, p2) with a circle placed at center_last, with radius of circle_distance.
-                        const Pointf v_seg(coordf_t(p2.x) - coordf_t(p1.x), coordf_t(p2.y) - coordf_t(p1.y));
-                        const Pointf v_cntr(coordf_t(p1.x - center_last.x), coordf_t(p1.y - center_last.y));
-                        coordf_t a = dot(v_seg);
-                        coordf_t b = 2. * dot(v_seg, v_cntr);
-                        coordf_t c = dot(v_cntr) - circle_distance * circle_distance;
+                        const Vec2d v_seg(coordf_t(p2(0)) - coordf_t(p1(0)), coordf_t(p2(1)) - coordf_t(p1(1)));
+                        const Vec2d v_cntr(coordf_t(p1(0) - center_last(0)), coordf_t(p1(1) - center_last(1)));
+                        coordf_t a = v_seg.squaredNorm();
+                        coordf_t b = 2. * v_seg.dot(v_cntr);
+                        coordf_t c = v_cntr.squaredNorm() - circle_distance * circle_distance;
                         coordf_t disc = b * b - 4. * a * c;
                         if (disc > 0.) {
                             // The circle intersects a ray. Avoid the parts of the segment inside the circle.
@@ -2081,7 +2081,7 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
                             }
                             seg_current_pt = &p1;
                             seg_current_t  = t;
-                            center_last    = Point(p1.x + coord_t(v_seg.x * t), p1.y + coord_t(v_seg.y * t));
+                            center_last    = Point(p1(0) + coord_t(v_seg(0) * t), p1(1) + coord_t(v_seg(1) * t));
                             // It has been verified that the new point is far enough from center_last.
                             // Ensure, that it is far enough from all the centers.
                             std::pair<const Point*, coordf_t> circle_closest = circle_centers_lookup.find(center_last);
@@ -2100,9 +2100,9 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
                         circle_centers.push_back(center_last);
                     }
                     external_loops.push_back(std::move(contour));
-                    for (Points::const_iterator it_center = circle_centers.begin(); it_center != circle_centers.end(); ++ it_center) {
+                    for (const Point &center : circle_centers) {
                         circles.push_back(circle);
-                        circles.back().translate(*it_center);
+                        circles.back().translate(center);
                     }
                 }
             }
@@ -2359,7 +2359,7 @@ void modulate_extrusion_by_overlapping_layers(
                 (fragment_end.is_start ? &polyline.points.front() : &polyline.points.back());
         }
     private:
-        ExtrusionPathFragmentEndPointAccessor& operator=(const ExtrusionPathFragmentEndPointAccessor&);
+        ExtrusionPathFragmentEndPointAccessor& operator=(const ExtrusionPathFragmentEndPointAccessor&) = delete;
         const std::vector<ExtrusionPathFragment> &m_path_fragments;
     };
     const coord_t search_radius = 7;
@@ -2392,7 +2392,7 @@ void modulate_extrusion_by_overlapping_layers(
             if (end_and_dist2.first == nullptr) {
                 // New fragment connecting to pt_current was not found.
                 // Verify that the last point found is close to the original end point of the unfragmented path.
-                //const double d2 = pt_end.distance_to_sq(pt_current);
+                //const double d2 = (pt_end - pt_current).squaredNorm();
                 //assert(d2 < coordf_t(search_radius * search_radius));
                 // End of the path.
                 break;
@@ -2887,9 +2887,9 @@ void PrintObjectSupportMaterial::clip_by_pillars(
         BoundingBox bbox;
         for (LayersPtr::const_iterator it = top_contacts.begin(); it != top_contacts.end(); ++ it)
             bbox.merge(get_extents((*it)->polygons));
-        grid.reserve(size_t(ceil(bb.size().x / pillar_spacing)) * size_t(ceil(bb.size().y / pillar_spacing)));
-        for (coord_t x = bb.min.x; x <= bb.max.x - pillar_size; x += pillar_spacing) {
-            for (coord_t y = bb.min.y; y <= bb.max.y - pillar_size; y += pillar_spacing) {
+        grid.reserve(size_t(ceil(bb.size()(0) / pillar_spacing)) * size_t(ceil(bb.size()(1) / pillar_spacing)));
+        for (coord_t x = bb.min(0); x <= bb.max(0) - pillar_size; x += pillar_spacing) {
+            for (coord_t y = bb.min(1); y <= bb.max(1) - pillar_size; y += pillar_spacing) {
                 grid.push_back(pillar);
                 for (size_t i = 0; i < pillar.points.size(); ++ i)
                     grid.back().points[i].translate(Point(x, y));
diff --git a/xs/src/libslic3r/Surface.cpp b/xs/src/libslic3r/Surface.cpp
index 384540d87..0e9eca7fd 100644
--- a/xs/src/libslic3r/Surface.cpp
+++ b/xs/src/libslic3r/Surface.cpp
@@ -106,9 +106,9 @@ Point export_surface_type_legend_to_svg_box_size()
 void export_surface_type_legend_to_svg(SVG &svg, const Point &pos)
 {
     // 1st row
-    coord_t pos_x0 = pos.x + scale_(1.);
+    coord_t pos_x0 = pos(0) + scale_(1.);
     coord_t pos_x = pos_x0;
-    coord_t pos_y = pos.y + scale_(1.5);
+    coord_t pos_y = pos(1) + scale_(1.5);
     coord_t step_x = scale_(10.);
     svg.draw_legend(Point(pos_x, pos_y), "perimeter"      , surface_type_to_color_name(stPerimeter));
     pos_x += step_x;
@@ -121,7 +121,7 @@ void export_surface_type_legend_to_svg(SVG &svg, const Point &pos)
     svg.draw_legend(Point(pos_x, pos_y), "invalid"        , surface_type_to_color_name(SurfaceType(-1)));
     // 2nd row
     pos_x = pos_x0;
-    pos_y = pos.y+scale_(2.8);
+    pos_y = pos(1)+scale_(2.8);
     svg.draw_legend(Point(pos_x, pos_y), "internal"       , surface_type_to_color_name(stInternal));
     pos_x += step_x;
     svg.draw_legend(Point(pos_x, pos_y), "internal solid" , surface_type_to_color_name(stInternalSolid));
diff --git a/xs/src/libslic3r/SurfaceCollection.cpp b/xs/src/libslic3r/SurfaceCollection.cpp
index 42ddf9574..6db599306 100644
--- a/xs/src/libslic3r/SurfaceCollection.cpp
+++ b/xs/src/libslic3r/SurfaceCollection.cpp
@@ -170,8 +170,8 @@ void SurfaceCollection::export_to_svg(const char *path, bool show_labels)
     for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface)
         bbox.merge(get_extents(surface->expolygon));
     Point legend_size = export_surface_type_legend_to_svg_box_size();
-    Point legend_pos(bbox.min.x, bbox.max.y);
-    bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y));
+    Point legend_pos(bbox.min(0), bbox.max(1));
+    bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
 
     SVG svg(path, bbox);
     const float transparency = 0.5f;
diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp
index fc72a45aa..d559afe52 100644
--- a/xs/src/libslic3r/TriangleMesh.cpp
+++ b/xs/src/libslic3r/TriangleMesh.cpp
@@ -35,13 +35,7 @@
 
 namespace Slic3r {
 
-TriangleMesh::TriangleMesh()
-    : repaired(false)
-{
-    stl_initialize(&this->stl);
-}
-
-TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Point3>& facets )
+TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets )
     : repaired(false)
 {
     stl_initialize(&this->stl);
@@ -56,51 +50,22 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Point3>& fa
 
     for (int i = 0; i < stl.stats.number_of_facets; i++) {
         stl_facet facet;
-
-        const Pointf3& ref_f1 = points[facets[i].x];
-        facet.vertex[0].x = ref_f1.x;
-        facet.vertex[0].y = ref_f1.y;
-        facet.vertex[0].z = ref_f1.z;
-
-        const Pointf3& ref_f2 = points[facets[i].y];
-        facet.vertex[1].x = ref_f2.x;
-        facet.vertex[1].y = ref_f2.y;
-        facet.vertex[1].z = ref_f2.z;
-
-        const Pointf3& ref_f3 = points[facets[i].z];
-        facet.vertex[2].x = ref_f3.x;
-        facet.vertex[2].y = ref_f3.y;
-        facet.vertex[2].z = ref_f3.z;
-        
+        facet.vertex[0] = points[facets[i](0)].cast<float>();
+        facet.vertex[1] = points[facets[i](1)].cast<float>();
+        facet.vertex[2] = points[facets[i](2)].cast<float>();
         facet.extra[0] = 0;
         facet.extra[1] = 0;
 
-        float normal[3];
+        stl_normal normal;
         stl_calculate_normal(normal, &facet);
         stl_normalize_vector(normal);
-        facet.normal.x = normal[0];
-        facet.normal.y = normal[1];
-        facet.normal.z = normal[2];
+        facet.normal = normal;
 
         stl.facet_start[i] = facet;
     }
     stl_get_size(&stl);
 }
 
-TriangleMesh::TriangleMesh(const TriangleMesh &other) :
-    repaired(false)
-{
-    stl_initialize(&this->stl);
-    *this = other;
-}
-
-TriangleMesh::TriangleMesh(TriangleMesh &&other) : 
-    repaired(false)
-{
-    stl_initialize(&this->stl);
-    this->swap(other);
-}
-
 TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
 {
     stl_close(&this->stl);
@@ -128,42 +93,8 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
     return *this;
 }
 
-TriangleMesh& TriangleMesh::operator=(TriangleMesh &&other)
+void TriangleMesh::repair()
 {
-    this->swap(other);
-    return *this;
-}
-
-void
-TriangleMesh::swap(TriangleMesh &other)
-{
-    std::swap(this->stl,      other.stl);
-    std::swap(this->repaired, other.repaired);
-}
-
-TriangleMesh::~TriangleMesh() {
-    stl_close(&this->stl);
-}
-
-void
-TriangleMesh::ReadSTLFile(const char* input_file) {
-    stl_open(&stl, input_file);
-}
-
-void
-TriangleMesh::write_ascii(const char* output_file)
-{
-    stl_write_ascii(&this->stl, output_file, "");
-}
-
-void
-TriangleMesh::write_binary(const char* output_file)
-{
-    stl_write_binary(&this->stl, output_file, "");
-}
-
-void
-TriangleMesh::repair() {
     if (this->repaired) return;
     
     // admesh fails when repairing empty meshes
@@ -260,13 +191,7 @@ void TriangleMesh::check_topology()
     }
 }
 
-bool TriangleMesh::is_manifold() const
-{
-    return this->stl.stats.connected_facets_3_edge == this->stl.stats.number_of_facets;
-}
-
-void
-TriangleMesh::reset_repair_stats() {
+void TriangleMesh::reset_repair_stats() {
     this->stl.stats.degenerate_facets   = 0;
     this->stl.stats.edges_fixed         = 0;
     this->stl.stats.facets_removed      = 0;
@@ -276,8 +201,7 @@ TriangleMesh::reset_repair_stats() {
     this->stl.stats.normals_fixed       = 0;
 }
 
-bool
-TriangleMesh::needed_repair() const
+bool TriangleMesh::needed_repair() const
 {
     return this->stl.stats.degenerate_facets    > 0
         || this->stl.stats.edges_fixed          > 0
@@ -287,14 +211,8 @@ TriangleMesh::needed_repair() const
         || this->stl.stats.backwards_edges      > 0;
 }
 
-size_t
-TriangleMesh::facets_count() const
+void TriangleMesh::WriteOBJFile(char* output_file)
 {
-    return this->stl.stats.number_of_facets;
-}
-
-void
-TriangleMesh::WriteOBJFile(char* output_file) {
     stl_generate_shared_vertices(&stl);
     stl_write_obj(&stl, output_file);
 }
@@ -305,13 +223,9 @@ void TriangleMesh::scale(float factor)
     stl_invalidate_shared_vertices(&this->stl);
 }
 
-void TriangleMesh::scale(const Pointf3 &versor)
+void TriangleMesh::scale(const Vec3d &versor)
 {
-    float fversor[3];
-    fversor[0] = versor.x;
-    fversor[1] = versor.y;
-    fversor[2] = versor.z;
-    stl_scale_versor(&this->stl, fversor);
+    stl_scale_versor(&this->stl, versor.cast<float>());
     stl_invalidate_shared_vertices(&this->stl);
 }
 
@@ -341,21 +255,6 @@ void TriangleMesh::rotate(float angle, const Axis &axis)
     stl_invalidate_shared_vertices(&this->stl);
 }
 
-void TriangleMesh::rotate_x(float angle)
-{
-    this->rotate(angle, X);
-}
-
-void TriangleMesh::rotate_y(float angle)
-{
-    this->rotate(angle, Y);
-}
-
-void TriangleMesh::rotate_z(float angle)
-{
-    this->rotate(angle, Z);
-}
-
 void TriangleMesh::mirror(const Axis &axis)
 {
     if (axis == X) {
@@ -368,21 +267,6 @@ void TriangleMesh::mirror(const Axis &axis)
     stl_invalidate_shared_vertices(&this->stl);
 }
 
-void TriangleMesh::mirror_x()
-{
-    this->mirror(X);
-}
-
-void TriangleMesh::mirror_y()
-{
-    this->mirror(Y);
-}
-
-void TriangleMesh::mirror_z()
-{
-    this->mirror(Z);
-}
-
 void TriangleMesh::transform(const float* matrix3x4)
 {
     if (matrix3x4 == nullptr)
@@ -395,19 +279,19 @@ void TriangleMesh::transform(const float* matrix3x4)
 void TriangleMesh::align_to_origin()
 {
     this->translate(
-        -(this->stl.stats.min.x),
-        -(this->stl.stats.min.y),
-        -(this->stl.stats.min.z)
-    );
+        - this->stl.stats.min(0),
+        - this->stl.stats.min(1),
+        - this->stl.stats.min(2));
 }
 
 void TriangleMesh::rotate(double angle, Point* center)
 {
     if (angle == 0.)
         return;
-    this->translate(float(-center->x), float(-center->y), 0);
+    Vec2f c = center->cast<float>();
+    this->translate(-c(0), -c(1), 0);
     stl_rotate_z(&(this->stl), (float)angle);
-    this->translate(float(+center->x), float(+center->y), 0);
+    this->translate(c(0), c(1), 0);
 }
 
 bool TriangleMesh::has_multiple_patches() const
@@ -480,14 +364,14 @@ size_t TriangleMesh::number_of_patches() const
     return num_bodies;
 }
 
-TriangleMeshPtrs
-TriangleMesh::split() const
+TriangleMeshPtrs TriangleMesh::split() const
 {
-    TriangleMeshPtrs meshes;
-    std::set<int> seen_facets;
+    TriangleMeshPtrs            meshes;
+    std::vector<unsigned char>  facet_visited(this->stl.stats.number_of_facets, false);
     
     // we need neighbors
-    if (!this->repaired) CONFESS("split() requires repair()");
+    if (!this->repaired)
+        CONFESS("split() requires repair()");
     
     // loop while we have remaining facets
     for (;;) {
@@ -495,46 +379,45 @@ TriangleMesh::split() const
         std::queue<int> facet_queue;
         std::deque<int> facets;
         for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; facet_idx++) {
-            if (seen_facets.find(facet_idx) == seen_facets.end()) {
+            if (! facet_visited[facet_idx]) {
                 // if facet was not seen put it into queue and start searching
                 facet_queue.push(facet_idx);
                 break;
             }
         }
-        if (facet_queue.empty()) break;
-        
-        while (!facet_queue.empty()) {
+        if (facet_queue.empty())
+            break;
+
+        while (! facet_queue.empty()) {
             int facet_idx = facet_queue.front();
             facet_queue.pop();
-            if (seen_facets.find(facet_idx) != seen_facets.end()) continue;
-            facets.push_back(facet_idx);
-            for (int j = 0; j <= 2; j++) {
-                facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]);
+            if (! facet_visited[facet_idx]) {
+                facets.emplace_back(facet_idx);
+                for (int j = 0; j < 3; ++ j)
+                    facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]);
+                facet_visited[facet_idx] = true;
             }
-            seen_facets.insert(facet_idx);
         }
-        
+
         TriangleMesh* mesh = new TriangleMesh;
-        meshes.push_back(mesh);
+        meshes.emplace_back(mesh);
         mesh->stl.stats.type = inmemory;
         mesh->stl.stats.number_of_facets = facets.size();
         mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets;
         stl_clear_error(&mesh->stl);
         stl_allocate(&mesh->stl);
         
-        int first = 1;
-        for (std::deque<int>::const_iterator facet = facets.begin(); facet != facets.end(); ++facet) {
+        bool first = true;
+        for (std::deque<int>::const_iterator facet = facets.begin(); facet != facets.end(); ++ facet) {
             mesh->stl.facet_start[facet - facets.begin()] = this->stl.facet_start[*facet];
             stl_facet_stats(&mesh->stl, this->stl.facet_start[*facet], first);
-            first = 0;
         }
     }
     
     return meshes;
 }
 
-void
-TriangleMesh::merge(const TriangleMesh &mesh)
+void TriangleMesh::merge(const TriangleMesh &mesh)
 {
     // reset stats and metadata
     int number_of_facets = this->stl.stats.number_of_facets;
@@ -565,11 +448,11 @@ ExPolygons TriangleMesh::horizontal_projection() const
         stl_facet* facet = &this->stl.facet_start[i];
         Polygon p;
         p.points.resize(3);
-        p.points[0] = Point::new_scale(facet->vertex[0].x, facet->vertex[0].y);
-        p.points[1] = Point::new_scale(facet->vertex[1].x, facet->vertex[1].y);
-        p.points[2] = Point::new_scale(facet->vertex[2].x, facet->vertex[2].y);
+        p.points[0] = Point::new_scale(facet->vertex[0](0), facet->vertex[0](1));
+        p.points[1] = Point::new_scale(facet->vertex[1](0), facet->vertex[1](1));
+        p.points[2] = Point::new_scale(facet->vertex[2](0), facet->vertex[2](1));
         p.make_counter_clockwise();  // do this after scaling, as winding order might change while doing that
-        pp.push_back(p);
+        pp.emplace_back(p);
     }
     
     // the offset factor was tuned using groovemount.stl
@@ -582,27 +465,22 @@ Polygon TriangleMesh::convex_hull()
     Points pp;
     pp.reserve(this->stl.stats.shared_vertices);
     for (int i = 0; i < this->stl.stats.shared_vertices; ++ i) {
-        stl_vertex* v = &this->stl.v_shared[i];
-        pp.emplace_back(Point::new_scale(v->x, v->y));
+        const stl_vertex &v = this->stl.v_shared[i];
+        pp.emplace_back(Point::new_scale(v(0), v(1)));
     }
     return Slic3r::Geometry::convex_hull(pp);
 }
 
-BoundingBoxf3
-TriangleMesh::bounding_box() const
+BoundingBoxf3 TriangleMesh::bounding_box() const
 {
     BoundingBoxf3 bb;
     bb.defined = true;
-    bb.min.x = this->stl.stats.min.x;
-    bb.min.y = this->stl.stats.min.y;
-    bb.min.z = this->stl.stats.min.z;
-    bb.max.x = this->stl.stats.max.x;
-    bb.max.y = this->stl.stats.max.y;
-    bb.max.z = this->stl.stats.max.z;
+    bb.min = this->stl.stats.min.cast<double>();
+    bb.max = this->stl.stats.max.cast<double>();
     return bb;
 }
 
-BoundingBoxf3 TriangleMesh::transformed_bounding_box(const std::vector<float>& matrix) const
+BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& t) const
 {
     bool has_shared = (stl.v_shared != nullptr);
     if (!has_shared)
@@ -613,16 +491,16 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const std::vector<float>& m
     if (vertices_count == 0)
         return BoundingBoxf3();
 
-    Eigen::MatrixXf src_vertices(3, vertices_count);
+    Eigen::MatrixXd src_vertices(3, vertices_count);
 
     if (stl.stats.shared_vertices > 0)
     {
         stl_vertex* vertex_ptr = stl.v_shared;
         for (int i = 0; i < stl.stats.shared_vertices; ++i)
         {
-            src_vertices(0, i) = vertex_ptr->x;
-            src_vertices(1, i) = vertex_ptr->y;
-            src_vertices(2, i) = vertex_ptr->z;
+            src_vertices(0, i) = (double)(*vertex_ptr)(0);
+            src_vertices(1, i) = (double)(*vertex_ptr)(1);
+            src_vertices(2, i) = (double)(*vertex_ptr)(2);
             vertex_ptr += 1;
         }
     }
@@ -634,9 +512,9 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const std::vector<float>& m
         {
             for (int i = 0; i < 3; ++i)
             {
-                src_vertices(0, v_id) = facet_ptr->vertex[i].x;
-                src_vertices(1, v_id) = facet_ptr->vertex[i].y;
-                src_vertices(2, v_id) = facet_ptr->vertex[i].z;
+                src_vertices(0, v_id) = (double)facet_ptr->vertex[i](0);
+                src_vertices(1, v_id) = (double)facet_ptr->vertex[i](1);
+                src_vertices(2, v_id) = (double)facet_ptr->vertex[i](2);
             }
             facet_ptr += 1;
             ++v_id;
@@ -646,30 +524,22 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const std::vector<float>& m
     if (!has_shared && (stl.stats.shared_vertices > 0))
         stl_invalidate_shared_vertices(&stl);
 
-    Eigen::Transform<float, 3, Eigen::Affine> m;
-    ::memcpy((void*)m.data(), (const void*)matrix.data(), 16 * sizeof(float));
+    Eigen::MatrixXd dst_vertices(3, vertices_count);
+    dst_vertices = t * src_vertices.colwise().homogeneous();
 
-    Eigen::MatrixXf dst_vertices(3, vertices_count);
-    dst_vertices = m * src_vertices.colwise().homogeneous();
-
-    float min_x = dst_vertices(0, 0);
-    float max_x = dst_vertices(0, 0);
-    float min_y = dst_vertices(1, 0);
-    float max_y = dst_vertices(1, 0);
-    float min_z = dst_vertices(2, 0);
-    float max_z = dst_vertices(2, 0);
+    Vec3d v_min(dst_vertices(0, 0), dst_vertices(1, 0), dst_vertices(2, 0));
+    Vec3d v_max = v_min;
 
     for (int i = 1; i < vertices_count; ++i)
     {
-        min_x = std::min(min_x, dst_vertices(0, i));
-        max_x = std::max(max_x, dst_vertices(0, i));
-        min_y = std::min(min_y, dst_vertices(1, i));
-        max_y = std::max(max_y, dst_vertices(1, i));
-        min_z = std::min(min_z, dst_vertices(2, i));
-        max_z = std::max(max_z, dst_vertices(2, i));
+        for (int j = 0; j < 3; ++j)
+        {
+            v_min(j) = std::min(v_min(j), dst_vertices(j, i));
+            v_max(j) = std::max(v_max(j), dst_vertices(j, i));
+        }
     }
 
-    return BoundingBoxf3(Pointf3((coordf_t)min_x, (coordf_t)min_y, (coordf_t)min_z), Pointf3((coordf_t)max_x, (coordf_t)max_y, (coordf_t)max_z));
+    return BoundingBoxf3(v_min, v_max);
 }
 
 TriangleMesh TriangleMesh::convex_hull_3d() const
@@ -688,7 +558,7 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
         for (int i = 0; i < 3; ++i)
         {
             const stl_vertex& v = facet_ptr->vertex[i];
-            src_vertices.emplace_back(v.x, v.y, v.z);
+            src_vertices.emplace_back(v(0), v(1), v(2));
         }
 
         facet_ptr += 1;
@@ -708,8 +578,8 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
     }
 
     // Let's collect results:
-    Pointf3s det_vertices;
-    std::vector<Point3> facets;
+    Pointf3s dst_vertices;
+    std::vector<Vec3crd> facets;
     auto facet_list = qhull.facetList().toStdVector();
     for (const orgQhull::QhullFacet& facet : facet_list)
     {   // iterate through facets
@@ -719,19 +589,18 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
 
             orgQhull::QhullPoint p = vertices[i].point();
             const float* coords = p.coordinates();
-            det_vertices.emplace_back(coords[0], coords[1], coords[2]);
+            dst_vertices.emplace_back(coords[0], coords[1], coords[2]);
         }
-        unsigned int size = (unsigned int)det_vertices.size();
+        unsigned int size = (unsigned int)dst_vertices.size();
         facets.emplace_back(size - 3, size - 2, size - 1);
     }
 
-    TriangleMesh output_mesh(det_vertices, facets);
+    TriangleMesh output_mesh(dst_vertices, facets);
     output_mesh.repair();
     return output_mesh;
 }
 
-void
-TriangleMesh::require_shared_vertices()
+void TriangleMesh::require_shared_vertices()
 {
     BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - start";
     if (!this->repaired) 
@@ -751,11 +620,8 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) :
     facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
     v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices);
     // Scale the copied vertices.
-    for (int i = 0; i < this->mesh->stl.stats.shared_vertices; ++ i) {
-        this->v_scaled_shared[i].x /= float(SCALING_FACTOR);
-        this->v_scaled_shared[i].y /= float(SCALING_FACTOR);
-        this->v_scaled_shared[i].z /= float(SCALING_FACTOR);
-    }
+    for (int i = 0; i < this->mesh->stl.stats.shared_vertices; ++ i)
+        this->v_scaled_shared[i] *= float(1. / SCALING_FACTOR);
 
     // Create a mapping from triangle edge into face.
     struct EdgeToFace {
@@ -829,8 +695,7 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) :
     }
 }
 
-void
-TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
+void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
 {
     BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice";
 
@@ -911,14 +776,14 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin
     const stl_facet &facet = this->mesh->stl.facet_start[facet_idx];
     
     // find facet extents
-    const float min_z = fminf(facet.vertex[0].z, fminf(facet.vertex[1].z, facet.vertex[2].z));
-    const float max_z = fmaxf(facet.vertex[0].z, fmaxf(facet.vertex[1].z, facet.vertex[2].z));
+    const float min_z = fminf(facet.vertex[0](2), fminf(facet.vertex[1](2), facet.vertex[2](2)));
+    const float max_z = fmaxf(facet.vertex[0](2), fmaxf(facet.vertex[1](2), facet.vertex[2](2)));
     
     #ifdef SLIC3R_DEBUG
     printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx,
-        facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0].z,
-        facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1].z,
-        facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2].z);
+        facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0](2),
+        facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1](2),
+        facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2](2));
     printf("z: min = %.2f, max = %.2f\n", min_z, max_z);
     #endif
     
@@ -938,24 +803,24 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin
             if (il.edge_type == feHorizontal) {
                 // Insert all three edges of the face.
                 const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
-                const bool reverse  = this->mesh->stl.facet_start[facet_idx].normal.z < 0;
+                const bool reverse  = this->mesh->stl.facet_start[facet_idx].normal(2) < 0;
                 for (int j = 0; j < 3; ++ j) {
                     int               a_id     = vertices[j % 3];
                     int               b_id     = vertices[(j+1) % 3];
                     if (reverse)
                         std::swap(a_id, b_id);
-                    const stl_vertex *a = &this->v_scaled_shared[a_id];
-                    const stl_vertex *b = &this->v_scaled_shared[b_id];
-                    il.a.x    = a->x;
-                    il.a.y    = a->y;
-                    il.b.x    = b->x;
-                    il.b.y    = b->y;
+                    const stl_vertex &a = this->v_scaled_shared[a_id];
+                    const stl_vertex &b = this->v_scaled_shared[b_id];
+                    il.a(0)    = a(0);
+                    il.a(1)    = a(1);
+                    il.b(0)    = b(0);
+                    il.b(1)    = b(1);
                     il.a_id   = a_id;
                     il.b_id   = b_id;
-                    (*lines)[layer_idx].push_back(il);
+                    (*lines)[layer_idx].emplace_back(il);
                 }
             } else
-                (*lines)[layer_idx].push_back(il);
+                (*lines)[layer_idx].emplace_back(il);
         }
     }
 }
@@ -995,66 +860,63 @@ bool TriangleMeshSlicer::slice_facet(
     // Reorder vertices so that the first one is the one with lowest Z.
     // This is needed to get all intersection lines in a consistent order
     // (external on the right of the line)
-    int i = (facet.vertex[1].z == min_z) ? 1 : ((facet.vertex[2].z == min_z) ? 2 : 0);
+    int i = (facet.vertex[1](2) == min_z) ? 1 : ((facet.vertex[2](2) == min_z) ? 2 : 0);
     for (int j = i; j - i < 3; ++ j) {  // loop through facet edges
         int               edge_id  = this->facets_edges[facet_idx * 3 + (j % 3)];
         const int        *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
         int               a_id     = vertices[j % 3];
         int               b_id     = vertices[(j+1) % 3];
-        const stl_vertex *a = &this->v_scaled_shared[a_id];
-        const stl_vertex *b = &this->v_scaled_shared[b_id];
+        const stl_vertex &a = this->v_scaled_shared[a_id];
+        const stl_vertex &b = this->v_scaled_shared[b_id];
         
         // Is edge or face aligned with the cutting plane?
-        if (a->z == slice_z && b->z == slice_z) {
+        if (a(2) == slice_z && b(2) == slice_z) {
             // Edge is horizontal and belongs to the current layer.
             const stl_vertex &v0 = this->v_scaled_shared[vertices[0]];
             const stl_vertex &v1 = this->v_scaled_shared[vertices[1]];
             const stl_vertex &v2 = this->v_scaled_shared[vertices[2]];
+            bool              swap = false;
             if (min_z == max_z) {
                 // All three vertices are aligned with slice_z.
                 line_out->edge_type = feHorizontal;
-                if (this->mesh->stl.facet_start[facet_idx].normal.z < 0) {
+                if (this->mesh->stl.facet_start[facet_idx].normal(2) < 0) {
                     // If normal points downwards this is a bottom horizontal facet so we reverse its point order.
-                    std::swap(a, b);
-                    std::swap(a_id, b_id);
+                    swap = true;
                 }
-            } else if (v0.z < slice_z || v1.z < slice_z || v2.z < slice_z) {
+            } else if (v0(2) < slice_z || v1(2) < slice_z || v2(2) < slice_z) {
                 // Two vertices are aligned with the cutting plane, the third vertex is below the cutting plane.
                 line_out->edge_type = feTop;
-                std::swap(a, b);
-                std::swap(a_id, b_id);
+                swap = true;
             } else {
                 // Two vertices are aligned with the cutting plane, the third vertex is above the cutting plane.
                 line_out->edge_type = feBottom;
             }
-            line_out->a.x    = a->x;
-            line_out->a.y    = a->y;
-            line_out->b.x    = b->x;
-            line_out->b.y    = b->y;
-            line_out->a_id   = a_id;
-            line_out->b_id   = b_id;
+            line_out->a = to_2d(swap ? b : a).cast<coord_t>();
+            line_out->b = to_2d(swap ? a : b).cast<coord_t>();
+            line_out->a_id = swap ? b_id : a_id;
+            line_out->b_id = swap ? a_id : b_id;
             return true;
         }
 
-        if (a->z == slice_z) {
+        if (a(2) == slice_z) {
             // Only point a alings with the cutting plane.
             points_on_layer[num_points_on_layer ++] = num_points;
             IntersectionPoint &point = points[num_points ++];
-            point.x         = a->x;
-            point.y         = a->y;
+            point(0)       = a(0);
+            point(1)       = a(1);
             point.point_id  = a_id;
-        } else if (b->z == slice_z) {
+        } else if (b(2) == slice_z) {
             // Only point b alings with the cutting plane.
             points_on_layer[num_points_on_layer ++] = num_points;
             IntersectionPoint &point = points[num_points ++];
-            point.x         = b->x;
-            point.y         = b->y;
+            point(0)       = b(0);
+            point(1)       = b(1);
             point.point_id  = b_id;
-        } else if ((a->z < slice_z && b->z > slice_z) || (b->z < slice_z && a->z > slice_z)) {
+        } else if ((a(2) < slice_z && b(2) > slice_z) || (b(2) < slice_z && a(2) > slice_z)) {
             // A general case. The face edge intersects the cutting plane. Calculate the intersection point.
             IntersectionPoint &point = points[num_points ++];
-            point.x         = b->x + (a->x - b->x) * (slice_z - b->z) / (a->z - b->z);
-            point.y         = b->y + (a->y - b->y) * (slice_z - b->z) / (a->z - b->z);
+            point(0)       = b(0) + (a(0) - b(0)) * (slice_z - b(2)) / (a(2) - b(2));
+            point(1)       = b(1) + (a(1) - b(1)) * (slice_z - b(2)) / (a(2) - b(2));
             point.edge_id   = edge_id;
         }
     }
@@ -1335,7 +1197,7 @@ void TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygo
                         // Orient the patched up polygons CCW. This heuristic may close some holes and cavities.
                         double area = 0.;
                         for (size_t i = 0, j = opl.points.size() - 1; i < opl.points.size(); j = i ++)
-                            area += double(opl.points[j].x + opl.points[i].x) * double(opl.points[i].y - opl.points[j].y);
+                            area += double(opl.points[j](0) + opl.points[i](0)) * double(opl.points[i](1) - opl.points[j](1));
                         if (area < 0)
                             std::reverse(opl.points.begin(), opl.points.end());
                         loops->emplace_back(std::move(opl.points));
@@ -1362,9 +1224,9 @@ void TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &l
         if (loop->area() >= 0.) {
             ExPolygon ex;
             ex.contour = *loop;
-            slices->push_back(ex);
+            slices->emplace_back(ex);
         } else {
-            holes.push_back(*loop);
+            holes.emplace_back(*loop);
         }
     }
 
@@ -1455,8 +1317,8 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic
     //std::vector<double> area;
     //std::vector<size_t> sorted_area;  // vector of indices
     //for (Polygons::const_iterator loop = loops.begin(); loop != loops.end(); ++ loop) {
-    //    area.push_back(loop->area());
-    //    sorted_area.push_back(loop - loops.begin());
+    //    area.emplace_back(loop->area());
+    //    sorted_area.emplace_back(loop - loops.begin());
     //}
     //
     //// outer first
@@ -1471,7 +1333,7 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic
     //       would do the same, thus repeating the calculation */
     //    Polygons::const_iterator loop = loops.begin() + *loop_idx;
     //    if (area[*loop_idx] > +EPSILON)
-    //        p_slices.push_back(*loop);
+    //        p_slices.emplace_back(*loop);
     //    else if (area[*loop_idx] < -EPSILON)
     //        //FIXME This is arbitrary and possibly very slow.
     //        // If the hole is inside a polygon, then there is no need to diff.
@@ -1521,20 +1383,20 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
         stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
         
         // find facet extents
-        float min_z = std::min(facet->vertex[0].z, std::min(facet->vertex[1].z, facet->vertex[2].z));
-        float max_z = std::max(facet->vertex[0].z, std::max(facet->vertex[1].z, facet->vertex[2].z));
+        float min_z = std::min(facet->vertex[0](2), std::min(facet->vertex[1](2), facet->vertex[2](2)));
+        float max_z = std::max(facet->vertex[0](2), std::max(facet->vertex[1](2), facet->vertex[2](2)));
         
         // intersect facet with cutting plane
         IntersectionLine line;
         if (this->slice_facet(scaled_z, *facet, facet_idx, min_z, max_z, &line)) {
             // Save intersection lines for generating correct triangulations.
             if (line.edge_type == feTop) {
-                lower_lines.push_back(line);
+                lower_lines.emplace_back(line);
             } else if (line.edge_type == feBottom) {
-                upper_lines.push_back(line);
+                upper_lines.emplace_back(line);
             } else if (line.edge_type != feHorizontal) {
-                lower_lines.push_back(line);
-                upper_lines.push_back(line);
+                lower_lines.emplace_back(line);
+                upper_lines.emplace_back(line);
             }
         }
         
@@ -1549,47 +1411,47 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
 
             // look for the vertex on whose side of the slicing plane there are no other vertices
             int isolated_vertex;
-            if ( (facet->vertex[0].z > z) == (facet->vertex[1].z > z) ) {
+            if ( (facet->vertex[0](2) > z) == (facet->vertex[1](2) > z) ) {
                 isolated_vertex = 2;
-            } else if ( (facet->vertex[1].z > z) == (facet->vertex[2].z > z) ) {
+            } else if ( (facet->vertex[1](2) > z) == (facet->vertex[2](2) > z) ) {
                 isolated_vertex = 0;
             } else {
                 isolated_vertex = 1;
             }
             
             // get vertices starting from the isolated one
-            stl_vertex* v0 = &facet->vertex[isolated_vertex];
-            stl_vertex* v1 = &facet->vertex[(isolated_vertex+1) % 3];
-            stl_vertex* v2 = &facet->vertex[(isolated_vertex+2) % 3];
+            const stl_vertex &v0 = facet->vertex[isolated_vertex];
+            const stl_vertex &v1 = facet->vertex[(isolated_vertex+1) % 3];
+            const stl_vertex &v2 = facet->vertex[(isolated_vertex+2) % 3];
             
             // intersect v0-v1 and v2-v0 with cutting plane and make new vertices
             stl_vertex v0v1, v2v0;
-            v0v1.x = v1->x + (v0->x - v1->x) * (z - v1->z) / (v0->z - v1->z);
-            v0v1.y = v1->y + (v0->y - v1->y) * (z - v1->z) / (v0->z - v1->z);
-            v0v1.z = z;
-            v2v0.x = v2->x + (v0->x - v2->x) * (z - v2->z) / (v0->z - v2->z);
-            v2v0.y = v2->y + (v0->y - v2->y) * (z - v2->z) / (v0->z - v2->z);
-            v2v0.z = z;
+            v0v1(0) = v1(0) + (v0(0) - v1(0)) * (z - v1(2)) / (v0(2) - v1(2));
+            v0v1(1) = v1(1) + (v0(1) - v1(1)) * (z - v1(2)) / (v0(2) - v1(2));
+            v0v1(2) = z;
+            v2v0(0) = v2(0) + (v0(0) - v2(0)) * (z - v2(2)) / (v0(2) - v2(2));
+            v2v0(1) = v2(1) + (v0(1) - v2(1)) * (z - v2(2)) / (v0(2) - v2(2));
+            v2v0(2) = z;
             
             // build the triangular facet
             stl_facet triangle;
             triangle.normal = facet->normal;
-            triangle.vertex[0] = *v0;
+            triangle.vertex[0] = v0;
             triangle.vertex[1] = v0v1;
             triangle.vertex[2] = v2v0;
             
             // build the facets forming a quadrilateral on the other side
             stl_facet quadrilateral[2];
             quadrilateral[0].normal = facet->normal;
-            quadrilateral[0].vertex[0] = *v1;
-            quadrilateral[0].vertex[1] = *v2;
+            quadrilateral[0].vertex[0] = v1;
+            quadrilateral[0].vertex[1] = v2;
             quadrilateral[0].vertex[2] = v0v1;
             quadrilateral[1].normal = facet->normal;
-            quadrilateral[1].vertex[0] = *v2;
+            quadrilateral[1].vertex[0] = v2;
             quadrilateral[1].vertex[1] = v2v0;
             quadrilateral[1].vertex[2] = v0v1;
             
-            if (v0->z > z) {
+            if (v0(2) > z) {
                 if (upper != NULL) stl_add_facet(&upper->stl, &triangle);
                 if (lower != NULL) {
                     stl_add_facet(&lower->stl, &quadrilateral[0]);
@@ -1621,13 +1483,11 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
             Polygon p = *polygon;
             p.reverse();
             stl_facet facet;
-            facet.normal.x = 0;
-            facet.normal.y = 0;
-            facet.normal.z = -1;
+            facet.normal = stl_normal(0, 0, -1.f);
             for (size_t i = 0; i <= 2; ++i) {
-                facet.vertex[i].x = unscale(p.points[i].x);
-                facet.vertex[i].y = unscale(p.points[i].y);
-                facet.vertex[i].z = z;
+                facet.vertex[i](0) = unscale<float>(p.points[i](0));
+                facet.vertex[i](1) = unscale<float>(p.points[i](1));
+                facet.vertex[i](2) = z;
             }
             stl_add_facet(&upper->stl, &facet);
         }
@@ -1647,13 +1507,11 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
         // convert triangles to facets and append them to mesh
         for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) {
             stl_facet facet;
-            facet.normal.x = 0;
-            facet.normal.y = 0;
-            facet.normal.z = 1;
+            facet.normal = stl_normal(0, 0, 1.f);
             for (size_t i = 0; i <= 2; ++i) {
-                facet.vertex[i].x = unscale(polygon->points[i].x);
-                facet.vertex[i].y = unscale(polygon->points[i].y);
-                facet.vertex[i].z = z;
+                facet.vertex[i](0) = unscale<float>(polygon->points[i](0));
+                facet.vertex[i](1) = unscale<float>(polygon->points[i](1));
+                facet.vertex[i](2) = z;
             }
             stl_add_facet(&lower->stl, &facet);
         }
@@ -1666,19 +1524,19 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
 
 // Generate the vertex list for a cube solid of arbitrary size in X/Y/Z.
 TriangleMesh make_cube(double x, double y, double z) {
-    Pointf3 pv[8] = { 
-        Pointf3(x, y, 0), Pointf3(x, 0, 0), Pointf3(0, 0, 0), 
-        Pointf3(0, y, 0), Pointf3(x, y, z), Pointf3(0, y, z), 
-        Pointf3(0, 0, z), Pointf3(x, 0, z) 
+    Vec3d pv[8] = { 
+        Vec3d(x, y, 0), Vec3d(x, 0, 0), Vec3d(0, 0, 0), 
+        Vec3d(0, y, 0), Vec3d(x, y, z), Vec3d(0, y, z), 
+        Vec3d(0, 0, z), Vec3d(x, 0, z) 
     };
-    Point3 fv[12] = { 
-        Point3(0, 1, 2), Point3(0, 2, 3), Point3(4, 5, 6), 
-        Point3(4, 6, 7), Point3(0, 4, 7), Point3(0, 7, 1), 
-        Point3(1, 7, 6), Point3(1, 6, 2), Point3(2, 6, 5), 
-        Point3(2, 5, 3), Point3(4, 0, 3), Point3(4, 3, 5) 
+    Vec3crd fv[12] = { 
+        Vec3crd(0, 1, 2), Vec3crd(0, 2, 3), Vec3crd(4, 5, 6), 
+        Vec3crd(4, 6, 7), Vec3crd(0, 4, 7), Vec3crd(0, 7, 1), 
+        Vec3crd(1, 7, 6), Vec3crd(1, 6, 2), Vec3crd(2, 6, 5), 
+        Vec3crd(2, 5, 3), Vec3crd(4, 0, 3), Vec3crd(4, 3, 5) 
     };
 
-    std::vector<Point3> facets(&fv[0], &fv[0]+12);
+    std::vector<Vec3crd> facets(&fv[0], &fv[0]+12);
     Pointf3s vertices(&pv[0], &pv[0]+8);
 
     TriangleMesh mesh(vertices ,facets);
@@ -1690,11 +1548,11 @@ TriangleMesh make_cube(double x, double y, double z) {
 // Default is 360 sides, angle fa is in radians.
 TriangleMesh make_cylinder(double r, double h, double fa) {
     Pointf3s vertices;
-    std::vector<Point3> facets;
+    std::vector<Vec3crd> facets;
 
     // 2 special vertices, top and bottom center, rest are relative to this
-    vertices.push_back(Pointf3(0.0, 0.0, 0.0));
-    vertices.push_back(Pointf3(0.0, 0.0, h));
+    vertices.emplace_back(Vec3d(0.0, 0.0, 0.0));
+    vertices.emplace_back(Vec3d(0.0, 0.0, h));
 
     // adjust via rounding to get an even multiple for any provided angle.
     double angle = (2*PI / floor(2*PI / fa));
@@ -1704,26 +1562,23 @@ TriangleMesh make_cylinder(double r, double h, double fa) {
     // top and bottom.
     // Special case: Last line shares 2 vertices with the first line.
     unsigned id = vertices.size() - 1;
-    vertices.push_back(Pointf3(sin(0) * r , cos(0) * r, 0));
-    vertices.push_back(Pointf3(sin(0) * r , cos(0) * r, h));
+    vertices.emplace_back(Vec3d(sin(0) * r , cos(0) * r, 0));
+    vertices.emplace_back(Vec3d(sin(0) * r , cos(0) * r, h));
     for (double i = 0; i < 2*PI; i+=angle) {
-        Pointf3 b(0, r, 0);
-        Pointf3 t(0, r, h);
-        b.rotate(i, Pointf3(0,0,0)); 
-        t.rotate(i, Pointf3(0,0,h));
-        vertices.push_back(b);
-        vertices.push_back(t);
+        Vec2d p = Eigen::Rotation2Dd(i) * Eigen::Vector2d(0, r);
+        vertices.emplace_back(Vec3d(p(0), p(1), 0.));
+        vertices.emplace_back(Vec3d(p(0), p(1), h));
         id = vertices.size() - 1;
-        facets.push_back(Point3( 0, id - 1, id - 3)); // top
-        facets.push_back(Point3(id,      1, id - 2)); // bottom
-        facets.push_back(Point3(id, id - 2, id - 3)); // upper-right of side
-        facets.push_back(Point3(id, id - 3, id - 1)); // bottom-left of side
+        facets.emplace_back(Vec3crd( 0, id - 1, id - 3)); // top
+        facets.emplace_back(Vec3crd(id,      1, id - 2)); // bottom
+        facets.emplace_back(Vec3crd(id, id - 2, id - 3)); // upper-right of side
+        facets.emplace_back(Vec3crd(id, id - 3, id - 1)); // bottom-left of side
     }
     // Connect the last set of vertices with the first.
-    facets.push_back(Point3( 2, 0, id - 1));
-    facets.push_back(Point3( 1, 3,     id));
-    facets.push_back(Point3(id, 3,      2));
-    facets.push_back(Point3(id, 2, id - 1));
+    facets.emplace_back(Vec3crd( 2, 0, id - 1));
+    facets.emplace_back(Vec3crd( 1, 3,     id));
+    facets.emplace_back(Vec3crd(id, 3,      2));
+    facets.emplace_back(Vec3crd(id, 2, id - 1));
     
     TriangleMesh mesh(vertices, facets);
     return mesh;
@@ -1734,7 +1589,7 @@ TriangleMesh make_cylinder(double r, double h, double fa) {
 // Default angle is 1 degree.
 TriangleMesh make_sphere(double rho, double fa) {
     Pointf3s vertices;
-    std::vector<Point3> facets;
+    std::vector<Vec3crd> facets;
 
     // Algorithm: 
     // Add points one-by-one to the sphere grid and form facets using relative coordinates.
@@ -1746,29 +1601,24 @@ TriangleMesh make_sphere(double rho, double fa) {
     // Ring to be scaled to generate the steps of the sphere
     std::vector<double> ring;
     for (double i = 0; i < 2*PI; i+=angle) {
-        ring.push_back(i);
+        ring.emplace_back(i);
     }
     const size_t steps = ring.size(); 
     const double increment = (double)(1.0 / (double)steps);
 
     // special case: first ring connects to 0,0,0
     // insert and form facets.
-    vertices.push_back(Pointf3(0.0, 0.0, -rho));
+    vertices.emplace_back(Vec3d(0.0, 0.0, -rho));
     size_t id = vertices.size();
     for (size_t i = 0; i < ring.size(); i++) {
         // Fixed scaling 
         const double z = -rho + increment*rho*2.0;
         // radius of the circle for this step.
         const double r = sqrt(abs(rho*rho - z*z));
-        Pointf3 b(0, r, z);
-        b.rotate(ring[i], Pointf3(0,0,z)); 
-        vertices.push_back(b);
-        if (i == 0) {
-            facets.push_back(Point3(1, 0, ring.size()));
-        } else {
-            facets.push_back(Point3(id, 0, id - 1));
-        }
-        id++;
+        Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
+        vertices.emplace_back(Vec3d(b(0), b(1), z));
+        facets.emplace_back((i == 0) ? Vec3crd(1, 0, ring.size()) : Vec3crd(id, 0, id - 1));
+        ++ id;
     }
 
     // General case: insert and form facets for each step, joining it to the ring below it.
@@ -1777,16 +1627,15 @@ TriangleMesh make_sphere(double rho, double fa) {
         const double r = sqrt(abs(rho*rho - z*z));
 
         for (size_t i = 0; i < ring.size(); i++) {
-            Pointf3 b(0, r, z);
-            b.rotate(ring[i], Pointf3(0,0,z)); 
-            vertices.push_back(b);
+            Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
+            vertices.emplace_back(Vec3d(b(0), b(1), z));
             if (i == 0) {
                 // wrap around
-                facets.push_back(Point3(id + ring.size() - 1 , id, id - 1)); 
-                facets.push_back(Point3(id, id - ring.size(),  id - 1)); 
+                facets.emplace_back(Vec3crd(id + ring.size() - 1 , id, id - 1)); 
+                facets.emplace_back(Vec3crd(id, id - ring.size(),  id - 1)); 
             } else {
-                facets.push_back(Point3(id , id - ring.size(), (id - 1) - ring.size())); 
-                facets.push_back(Point3(id, id - 1 - ring.size() ,  id - 1)); 
+                facets.emplace_back(Vec3crd(id , id - ring.size(), (id - 1) - ring.size())); 
+                facets.emplace_back(Vec3crd(id, id - 1 - ring.size() ,  id - 1)); 
             }
             id++;
         } 
@@ -1795,13 +1644,13 @@ TriangleMesh make_sphere(double rho, double fa) {
 
     // special case: last ring connects to 0,0,rho*2.0
     // only form facets.
-    vertices.push_back(Pointf3(0.0, 0.0, rho));
+    vertices.emplace_back(Vec3d(0.0, 0.0, rho));
     for (size_t i = 0; i < ring.size(); i++) {
         if (i == 0) {
             // third vertex is on the other side of the ring.
-            facets.push_back(Point3(id, id - ring.size(),  id - 1));
+            facets.emplace_back(Vec3crd(id, id - ring.size(),  id - 1));
         } else {
-            facets.push_back(Point3(id, id - ring.size() + i,  id - ring.size() + (i - 1)));
+            facets.emplace_back(Vec3crd(id, id - ring.size() + i,  id - ring.size() + (i - 1)));
         }
     }
     id++;
diff --git a/xs/src/libslic3r/TriangleMesh.hpp b/xs/src/libslic3r/TriangleMesh.hpp
index 6ab52efe2..e4d377a9d 100644
--- a/xs/src/libslic3r/TriangleMesh.hpp
+++ b/xs/src/libslic3r/TriangleMesh.hpp
@@ -20,33 +20,33 @@ typedef std::vector<TriangleMesh*> TriangleMeshPtrs;
 class TriangleMesh
 {
 public:
-    TriangleMesh();
-    TriangleMesh(const Pointf3s &points, const std::vector<Point3> &facets);
-    TriangleMesh(const TriangleMesh &other);
-    TriangleMesh(TriangleMesh &&other);
+    TriangleMesh() : repaired(false) { stl_initialize(&this->stl); }
+    TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets);
+    TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_initialize(&this->stl); *this = other; }
+    TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_initialize(&this->stl); this->swap(other); }
+    ~TriangleMesh() { stl_close(&this->stl); }
     TriangleMesh& operator=(const TriangleMesh &other);
-    TriangleMesh& operator=(TriangleMesh &&other);
-    void swap(TriangleMesh &other);
-    ~TriangleMesh();
-    void ReadSTLFile(const char* input_file);
-    void write_ascii(const char* output_file);
-    void write_binary(const char* output_file);
+    TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; }
+    void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); }
+    void ReadSTLFile(const char* input_file) { stl_open(&stl, input_file); }
+    void write_ascii(const char* output_file) { stl_write_ascii(&this->stl, output_file, ""); }
+    void write_binary(const char* output_file) { stl_write_binary(&this->stl, output_file, ""); }
     void repair();
     float volume();
     void check_topology();
-    bool is_manifold() const;
+    bool is_manifold() const { return this->stl.stats.connected_facets_3_edge == this->stl.stats.number_of_facets; }
     void WriteOBJFile(char* output_file);
     void scale(float factor);
-    void scale(const Pointf3 &versor);
+    void scale(const Vec3d &versor);
     void translate(float x, float y, float z);
     void rotate(float angle, const Axis &axis);
-    void rotate_x(float angle);
-    void rotate_y(float angle);
-    void rotate_z(float angle);
+    void rotate_x(float angle) { this->rotate(angle, X); }
+    void rotate_y(float angle) { this->rotate(angle, Y); }
+    void rotate_z(float angle) { this->rotate(angle, Z); }
     void mirror(const Axis &axis);
-    void mirror_x();
-    void mirror_y();
-    void mirror_z();
+    void mirror_x() { this->mirror(X); }
+    void mirror_y() { this->mirror(Y); }
+    void mirror_z() { this->mirror(Z); }
     void transform(const float* matrix3x4);
     void align_to_origin();
     void rotate(double angle, Point* center);
@@ -55,13 +55,13 @@ public:
     ExPolygons horizontal_projection() const;
     Polygon convex_hull();
     BoundingBoxf3 bounding_box() const;
-    // Returns the bbox of this TriangleMesh transformed by the given matrix
-    BoundingBoxf3 transformed_bounding_box(const std::vector<float>& matrix) const;
+    // Returns the bbox of this TriangleMesh transformed by the given transformation
+    BoundingBoxf3 transformed_bounding_box(const Transform3d& t) const;
     // Returns the convex hull of this TriangleMesh
     TriangleMesh convex_hull_3d() const;
     void reset_repair_stats();
     bool needed_repair() const;
-    size_t facets_count() const;
+    size_t facets_count() const { return this->stl.stats.number_of_facets; }
 
     // Returns true, if there are two and more connected patches in the mesh.
     // Returns false, if one or zero connected patch is in the mesh.
diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h
index 34f61cb12..6fea64cd1 100644
--- a/xs/src/libslic3r/libslic3r.h
+++ b/xs/src/libslic3r/libslic3r.h
@@ -45,7 +45,6 @@ typedef double  coordf_t;
 //FIXME Better to use an inline function with an explicit return type.
 //inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); }
 #define scale_(val) ((val) / SCALING_FACTOR)
-#define unscale(val) ((val) * SCALING_FACTOR)
 #define SCALED_EPSILON scale_(EPSILON)
 /* Implementation of CONFESS("foo"): */
 #ifdef _MSC_VER
@@ -102,6 +101,9 @@ inline std::string debug_out_path(const char *name, ...)
 
 namespace Slic3r {
 
+template<typename T, typename Q>
+inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); }
+
 enum Axis { X=0, Y, Z, E, F, NUM_AXES };
 
 template <class T>
@@ -130,6 +132,17 @@ inline void append(std::vector<T>& dest, std::vector<T>&& src)
     src.shrink_to_fit();
 }
 
+// Casting an std::vector<> from one type to another type without warnings about a loss of accuracy.
+template<typename T_TO, typename T_FROM>
+std::vector<T_TO> cast(const std::vector<T_FROM> &src) 
+{
+    std::vector<T_TO> dst;
+    dst.reserve(src.size());
+    for (const T_FROM &a : src)
+        dst.emplace_back((T_TO)a);
+    return dst;
+}
+
 template <typename T>
 inline void remove_nulls(std::vector<T*> &vec)
 {
diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp
index d6bd0e94c..5e0918755 100644
--- a/xs/src/perlglue.cpp
+++ b/xs/src/perlglue.cpp
@@ -41,9 +41,8 @@ REGISTER_CLASS(BoundingBoxf, "Geometry::BoundingBoxf");
 REGISTER_CLASS(BoundingBoxf3, "Geometry::BoundingBoxf3");
 REGISTER_CLASS(BridgeDetector, "BridgeDetector");
 REGISTER_CLASS(Point, "Point");
-REGISTER_CLASS(Point3, "Point3");
-REGISTER_CLASS(Pointf, "Pointf");
-REGISTER_CLASS(Pointf3, "Pointf3");
+__REGISTER_CLASS(Vec2d, "Pointf");
+__REGISTER_CLASS(Vec3d, "Pointf3");
 REGISTER_CLASS(DynamicPrintConfig, "Config");
 REGISTER_CLASS(StaticPrintConfig, "Config::Static");
 REGISTER_CLASS(PrintObjectConfig, "Config::PrintObject");
@@ -133,7 +132,7 @@ SV* ConfigOption_to_SV(const ConfigOption &opt, const ConfigOptionDef &def)
         auto optv = static_cast<const ConfigOptionPoints*>(&opt);
         AV* av = newAV();
         av_fill(av, optv->values.size()-1);
-        for (const Pointf &v : optv->values)
+        for (const Vec2d &v : optv->values)
             av_store(av, &v - optv->values.data(), perl_to_SV_clone_ref(v));
         return newRV_noinc((SV*)av);
     }
@@ -263,14 +262,14 @@ bool ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* v
         return from_SV_check(value, &static_cast<ConfigOptionPoint*>(opt)->value);
     case coPoints:
     {
-        std::vector<Pointf> &values = static_cast<ConfigOptionPoints*>(opt)->values;
+        std::vector<Vec2d> &values = static_cast<ConfigOptionPoints*>(opt)->values;
         AV* av = (AV*)SvRV(value);
         const size_t len = av_len(av)+1;
         values.clear();
         values.reserve(len);
         for (size_t i = 0; i < len; i++) {
             SV** elem = av_fetch(av, i, 0);
-            Pointf point;
+            Vec2d point(Vec2d::Zero());
             if (elem == NULL || !from_SV_check(*elem, &point)) return false;
             values.emplace_back(point);
         }
@@ -485,8 +484,8 @@ SV* to_SV_pureperl(const Point* THIS)
 {
     AV* av = newAV();
     av_fill(av, 1);
-    av_store(av, 0, newSViv(THIS->x));
-    av_store(av, 1, newSViv(THIS->y));
+    av_store(av, 0, newSViv((*THIS)(0)));
+    av_store(av, 1, newSViv((*THIS)(1)));
     return newRV_noinc((SV*)av);
 }
 
@@ -495,8 +494,7 @@ void from_SV(SV* point_sv, Point* point)
     AV* point_av = (AV*)SvRV(point_sv);
     // get a double from Perl and round it, otherwise
     // it would get truncated
-    point->x = lrint(SvNV(*av_fetch(point_av, 0, 0)));
-    point->y = lrint(SvNV(*av_fetch(point_av, 1, 0)));
+    (*point) = Point(SvNV(*av_fetch(point_av, 0, 0)), SvNV(*av_fetch(point_av, 1, 0)));
 }
 
 void from_SV_check(SV* point_sv, Point* point)
@@ -510,33 +508,32 @@ void from_SV_check(SV* point_sv, Point* point)
     }
 }
 
-SV* to_SV_pureperl(const Pointf* point)
+SV* to_SV_pureperl(const Vec2d* point)
 {
     AV* av = newAV();
     av_fill(av, 1);
-    av_store(av, 0, newSVnv(point->x));
-    av_store(av, 1, newSVnv(point->y));
+    av_store(av, 0, newSVnv((*point)(0)));
+    av_store(av, 1, newSVnv((*point)(1)));
     return newRV_noinc((SV*)av);
 }
 
-bool from_SV(SV* point_sv, Pointf* point)
+bool from_SV(SV* point_sv, Vec2d* point)
 {
     AV* point_av = (AV*)SvRV(point_sv);
     SV* sv_x = *av_fetch(point_av, 0, 0);
     SV* sv_y = *av_fetch(point_av, 1, 0);
     if (!looks_like_number(sv_x) || !looks_like_number(sv_y)) return false;
     
-    point->x = SvNV(sv_x);
-    point->y = SvNV(sv_y);
+    *point = Vec2d(SvNV(sv_x), SvNV(sv_y));
     return true;
 }
 
-bool from_SV_check(SV* point_sv, Pointf* point)
+bool from_SV_check(SV* point_sv, Vec2d* point)
 {
     if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) {
         if (!sv_isa(point_sv, perl_class_name(point)) && !sv_isa(point_sv, perl_class_name_ref(point)))
             CONFESS("Not a valid %s object (got %s)", perl_class_name(point), HvNAME(SvSTASH(SvRV(point_sv))));
-        *point = *(Pointf*)SvIV((SV*)SvRV( point_sv ));
+        *point = *(Vec2d*)SvIV((SV*)SvRV( point_sv ));
         return true;
     } else {
         return from_SV(point_sv, point);
diff --git a/xs/src/poly2tri/common/utils.h b/xs/src/poly2tri/common/utils.h
index ffb713f58..4bcb76361 100644
--- a/xs/src/poly2tri/common/utils.h
+++ b/xs/src/poly2tri/common/utils.h
@@ -33,7 +33,9 @@
 #define UTILS_H
 
 // Otherwise #defines like M_PI are undeclared under Visual Studio
-#define _USE_MATH_DEFINES
+#ifndef _USE_MATH_DEFINES
+  #define _USE_MATH_DEFINES
+#endif /* _USE_MATH_DEFINES */
 
 #include <exception>
 #include <math.h>
diff --git a/xs/src/slic3r/AppController.cpp b/xs/src/slic3r/AppController.cpp
index 58858f5fc..a3ab0155c 100644
--- a/xs/src/slic3r/AppController.cpp
+++ b/xs/src/slic3r/AppController.cpp
@@ -319,7 +319,7 @@ void AppController::arrange_model()
         auto& bedpoints = print_ctl()->config().bed_shape.values;
         Polyline bed; bed.points.reserve(bedpoints.size());
         for(auto& v : bedpoints)
-            bed.append(Point::new_scale(v.x, v.y));
+            bed.append(Point::new_scale(v(0), v(1)));
 
         if(pind) pind->update(0, _(L("Arranging objects...")));
 
diff --git a/xs/src/slic3r/GUI/2DBed.cpp b/xs/src/slic3r/GUI/2DBed.cpp
index 6d788cf34..e19f839cd 100644
--- a/xs/src/slic3r/GUI/2DBed.cpp
+++ b/xs/src/slic3r/GUI/2DBed.cpp
@@ -32,17 +32,17 @@ void Bed_2D::repaint()
 	cw--;
 	ch--;
 
-	auto cbb = BoundingBoxf(Pointf(0, 0),Pointf(cw, ch));
+	auto cbb = BoundingBoxf(Vec2d(0, 0),Vec2d(cw, ch));
 	// leave space for origin point
-	cbb.min.translate(4, 0);
-	cbb.max.translate(-4, -4);
+	cbb.min(0) += 4;
+	cbb.max -= Vec2d(4., 4.);
 
 	// leave space for origin label
-	cbb.max.translate(0, -13);
+	cbb.max(1) -= 13;
 
 	// read new size
-	cw = cbb.size().x;
-	ch = cbb.size().y;
+	cw = cbb.size()(0);
+	ch = cbb.size()(1);
 
 	auto ccenter = cbb.center();
 
@@ -50,20 +50,20 @@ void Bed_2D::repaint()
 	auto bed_shape = m_bed_shape;
 	auto bed_polygon = Polygon::new_scale(m_bed_shape);
 	auto bb = BoundingBoxf(m_bed_shape);
-	bb.merge(Pointf(0, 0));  // origin needs to be in the visible area
-	auto bw = bb.size().x;
-	auto bh = bb.size().y;
+	bb.merge(Vec2d(0, 0));  // origin needs to be in the visible area
+	auto bw = bb.size()(0);
+	auto bh = bb.size()(1);
 	auto bcenter = bb.center();
 
 	// calculate the scaling factor for fitting bed shape in canvas area
 	auto sfactor = std::min(cw/bw, ch/bh);
-	auto shift = Pointf(
-		ccenter.x - bcenter.x * sfactor,
-		ccenter.y - bcenter.y * sfactor
+	auto shift = Vec2d(
+		ccenter(0) - bcenter(0) * sfactor,
+		ccenter(1) - bcenter(1) * sfactor
 		);
 	m_scale_factor = sfactor;
-	m_shift = Pointf(shift.x + cbb.min.x,
-					shift.y - (cbb.max.y - GetSize().GetHeight()));
+	m_shift = Vec2d(shift(0) + cbb.min(0),
+					shift(1) - (cbb.max(1) - GetSize().GetHeight()));
 
 	// draw bed fill
 	dc.SetBrush(wxBrush(wxColour(255, 255, 255), wxSOLID));
@@ -71,19 +71,18 @@ void Bed_2D::repaint()
 	for (auto pt: m_bed_shape)
 	{
 		Point pt_pix = to_pixels(pt);
-		pt_list.push_back(new wxPoint(pt_pix.x, pt_pix.y));
+		pt_list.push_back(new wxPoint(pt_pix(0), pt_pix(1)));
 	}
 	dc.DrawPolygon(&pt_list, 0, 0);
 
 	// draw grid
 	auto step = 10;  // 1cm grid
 	Polylines polylines;
-	for (auto x = bb.min.x - fmod(bb.min.x, step) + step; x < bb.max.x; x += step) {
-		Polyline pl = Polyline::new_scale({ Pointf(x, bb.min.y), Pointf(x, bb.max.y) });
-		polylines.push_back(pl);
+	for (auto x = bb.min(0) - fmod(bb.min(0), step) + step; x < bb.max(0); x += step) {
+		polylines.push_back(Polyline::new_scale({ Vec2d(x, bb.min(1)), Vec2d(x, bb.max(1)) }));
 	}
-	for (auto y = bb.min.y - fmod(bb.min.y, step) + step; y < bb.max.y; y += step) {
-		polylines.push_back(Polyline::new_scale({ Pointf(bb.min.x, y), Pointf(bb.max.x, y) }));
+	for (auto y = bb.min(1) - fmod(bb.min(1), step) + step; y < bb.max(1); y += step) {
+		polylines.push_back(Polyline::new_scale({ Vec2d(bb.min(0), y), Vec2d(bb.max(0), y) }));
 	}
 	polylines = intersection_pl(polylines, bed_polygon);
 
@@ -91,9 +90,9 @@ void Bed_2D::repaint()
 	for (auto pl : polylines)
 	{
 		for (size_t i = 0; i < pl.points.size()-1; i++){
-			Point pt1 = to_pixels(Pointf::new_unscale(pl.points[i]));
-			Point pt2 = to_pixels(Pointf::new_unscale(pl.points[i+1]));
-			dc.DrawLine(pt1.x, pt1.y, pt2.x, pt2.y);
+			Point pt1 = to_pixels(unscale(pl.points[i]));
+			Point pt2 = to_pixels(unscale(pl.points[i+1]));
+			dc.DrawLine(pt1(0), pt1(1), pt2(0), pt2(1));
 		}
 	}
 
@@ -102,65 +101,59 @@ void Bed_2D::repaint()
 	dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxTRANSPARENT));
 	dc.DrawPolygon(&pt_list, 0, 0);
 
-	auto origin_px = to_pixels(Pointf(0, 0));
+	auto origin_px = to_pixels(Vec2d(0, 0));
 
 	// draw axes
 	auto axes_len = 50;
 	auto arrow_len = 6;
 	auto arrow_angle = Geometry::deg2rad(45.0);
 	dc.SetPen(wxPen(wxColour(255, 0, 0), 2, wxSOLID));  // red
-	auto x_end = Pointf(origin_px.x + axes_len, origin_px.y);
-	dc.DrawLine(wxPoint(origin_px.x, origin_px.y), wxPoint(x_end.x, x_end.y));
+	auto x_end = Vec2d(origin_px(0) + axes_len, origin_px(1));
+	dc.DrawLine(wxPoint(origin_px(0), origin_px(1)), wxPoint(x_end(0), x_end(1)));
 	for (auto angle : { -arrow_angle, arrow_angle }){
-		auto end = x_end;
-		end.translate(-arrow_len, 0);
-		end.rotate(angle, x_end);
-		dc.DrawLine(wxPoint(x_end.x, x_end.y), wxPoint(end.x, end.y));
+		auto end = Eigen::Translation2d(x_end) * Eigen::Rotation2Dd(angle) * Eigen::Translation2d(- x_end) * Eigen::Vector2d(x_end(0) - arrow_len, x_end(1));
+		dc.DrawLine(wxPoint(x_end(0), x_end(1)), wxPoint(end(0), end(1)));
 	}
 
 	dc.SetPen(wxPen(wxColour(0, 255, 0), 2, wxSOLID));  // green
-	auto y_end = Pointf(origin_px.x, origin_px.y - axes_len);
-	dc.DrawLine(wxPoint(origin_px.x, origin_px.y), wxPoint(y_end.x, y_end.y));
+	auto y_end = Vec2d(origin_px(0), origin_px(1) - axes_len);
+	dc.DrawLine(wxPoint(origin_px(0), origin_px(1)), wxPoint(y_end(0), y_end(1)));
 	for (auto angle : { -arrow_angle, arrow_angle }) {
-		auto end = y_end;
-		end.translate(0, +arrow_len);
-		end.rotate(angle, y_end);
-		dc.DrawLine(wxPoint(y_end.x, y_end.y), wxPoint(end.x, end.y));
+		auto end = Eigen::Translation2d(y_end) * Eigen::Rotation2Dd(angle) * Eigen::Translation2d(- y_end) * Eigen::Vector2d(y_end(0), y_end(1) + arrow_len);
+		dc.DrawLine(wxPoint(y_end(0), y_end(1)), wxPoint(end(0), end(1)));
 	}
 
 	// draw origin
 	dc.SetPen(wxPen(wxColour(0, 0, 0), 1, wxSOLID));
 	dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxSOLID));
-	dc.DrawCircle(origin_px.x, origin_px.y, 3);
+	dc.DrawCircle(origin_px(0), origin_px(1), 3);
 
 	static const auto origin_label = wxString("(0,0)");
 	dc.SetTextForeground(wxColour(0, 0, 0));
 	dc.SetFont(wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL));
 	auto extent = dc.GetTextExtent(origin_label);
-	const auto origin_label_x = origin_px.x <= cw / 2 ? origin_px.x + 1 : origin_px.x - 1 - extent.GetWidth();
-	const auto origin_label_y = origin_px.y <= ch / 2 ? origin_px.y + 1 : origin_px.y - 1 - extent.GetHeight();
+	const auto origin_label_x = origin_px(0) <= cw / 2 ? origin_px(0) + 1 : origin_px(0) - 1 - extent.GetWidth();
+	const auto origin_label_y = origin_px(1) <= ch / 2 ? origin_px(1) + 1 : origin_px(1) - 1 - extent.GetHeight();
 	dc.DrawText(origin_label, origin_label_x, origin_label_y);
 
 	// draw current position
-	if (m_pos!= Pointf(0, 0)) {
+	if (m_pos!= Vec2d(0, 0)) {
 		auto pos_px = to_pixels(m_pos);
 		dc.SetPen(wxPen(wxColour(200, 0, 0), 2, wxSOLID));
 		dc.SetBrush(wxBrush(wxColour(200, 0, 0), wxTRANSPARENT));
-		dc.DrawCircle(pos_px.x, pos_px.y, 5);
+		dc.DrawCircle(pos_px(0), pos_px(1), 5);
 
-		dc.DrawLine(pos_px.x - 15, pos_px.y, pos_px.x + 15, pos_px.y);
-		dc.DrawLine(pos_px.x, pos_px.y - 15, pos_px.x, pos_px.y + 15);
+		dc.DrawLine(pos_px(0) - 15, pos_px(1), pos_px(0) + 15, pos_px(1));
+		dc.DrawLine(pos_px(0), pos_px(1) - 15, pos_px(0), pos_px(1) + 15);
 	}
 
 	m_painted = true;
 }
 
 // convert G - code coordinates into pixels
-Point Bed_2D::to_pixels(Pointf point){
-	auto p = Pointf(point);
-	p.scale(m_scale_factor);
-	p.translate(m_shift);
-	return Point(p.x, GetSize().GetHeight() - p.y); 
+Point Bed_2D::to_pixels(Vec2d point){
+	auto p = point * m_scale_factor + m_shift;
+	return Point(p(0), GetSize().GetHeight() - p(1)); 
 }
 
 void Bed_2D::mouse_event(wxMouseEvent event){
@@ -168,7 +161,7 @@ void Bed_2D::mouse_event(wxMouseEvent event){
 	if (!m_painted) return;
 
 	auto pos = event.GetPosition();
-	auto point = to_units(Point(pos.x, pos.y));  
+	auto point = to_units(Point(pos.x, pos.y));
 	if (event.LeftDown() || event.Dragging()) {
 		if (m_on_move)
 			m_on_move(point) ;
@@ -177,14 +170,11 @@ void Bed_2D::mouse_event(wxMouseEvent event){
 }
 
 // convert pixels into G - code coordinates
-Pointf Bed_2D::to_units(Point point){
-	auto p = Pointf(point.x, GetSize().GetHeight() - point.y);
-	p.translate(m_shift.negative());
-	p.scale(1 / m_scale_factor);
-	return p;
+Vec2d Bed_2D::to_units(Point point){
+	return (Vec2d(point(0), GetSize().GetHeight() - point(1)) - m_shift) * (1. / m_scale_factor);
 }
 
-void Bed_2D::set_pos(Pointf pos){
+void Bed_2D::set_pos(Vec2d pos){
 	m_pos = pos;
 	Refresh();
 }
diff --git a/xs/src/slic3r/GUI/2DBed.hpp b/xs/src/slic3r/GUI/2DBed.hpp
index 4b14986a2..d7a7f4260 100644
--- a/xs/src/slic3r/GUI/2DBed.hpp
+++ b/xs/src/slic3r/GUI/2DBed.hpp
@@ -14,15 +14,15 @@ class Bed_2D : public wxPanel
 	bool		m_painted = false;
 	bool		m_interactive = false;
 	double		m_scale_factor;
-	Pointf		m_shift;
-	Pointf		m_pos;
-	std::function<void(Pointf)>	m_on_move = nullptr;
+	Vec2d		m_shift = Vec2d::Zero();
+	Vec2d		m_pos = Vec2d::Zero();
+	std::function<void(Vec2d)>	m_on_move = nullptr;
 
-	Point		to_pixels(Pointf point);
-	Pointf		to_units(Point point);
+	Point		to_pixels(Vec2d point);
+	Vec2d		to_units(Point point);
 	void		repaint();
 	void		mouse_event(wxMouseEvent event);
-	void		set_pos(Pointf pos);
+	void		set_pos(Vec2d pos);
 
 public:
 	Bed_2D(wxWindow* parent) 
@@ -41,7 +41,7 @@ public:
 	}
 	~Bed_2D(){}
 
-	std::vector<Pointf>		m_bed_shape;
+	std::vector<Vec2d>		m_bed_shape;
 		
 };
 
diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp
index dd7a3fb4a..a3f7e0a4c 100644
--- a/xs/src/slic3r/GUI/3DScene.cpp
+++ b/xs/src/slic3r/GUI/3DScene.cpp
@@ -26,11 +26,6 @@
 
 #include "GUI.hpp"
 
-static const float UNIT_MATRIX[] = { 1.0f, 0.0f, 0.0f, 0.0f,
-                                     0.0f, 1.0f, 0.0f, 0.0f,
-                                     0.0f, 0.0f, 1.0f, 0.0f,
-                                     0.0f, 0.0f, 0.0f, 1.0f };
-
 namespace Slic3r {
 
 void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh)
@@ -44,7 +39,7 @@ void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh)
     for (int i = 0; i < mesh.stl.stats.number_of_facets; ++ i) {
         const stl_facet &facet = mesh.stl.facet_start[i];
         for (int j = 0; j < 3; ++ j)
-            this->push_geometry(facet.vertex[j].x, facet.vertex[j].y, facet.vertex[j].z, facet.normal.x, facet.normal.y, facet.normal.z);
+            this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2));
     }
 }
 
@@ -60,7 +55,7 @@ void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh &mesh)
     for (int i = 0; i < mesh.stl.stats.number_of_facets; ++i) {
         const stl_facet &facet = mesh.stl.facet_start[i];
         for (int j = 0; j < 3; ++j)
-            this->push_geometry(facet.vertex[j].x, facet.vertex[j].y, facet.vertex[j].z, facet.normal.x, facet.normal.y, facet.normal.z);
+            this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2));
 
         this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2);
         vertices_count += 3;
@@ -200,7 +195,8 @@ const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
 const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
 
 GLVolume::GLVolume(float r, float g, float b, float a)
-    : m_angle_z(0.0f)
+    : m_origin(0, 0, 0)
+    , m_angle_z(0.0f)
     , m_scale_factor(1.0f)
     , m_transformed_bounding_box_dirty(true)
     , m_transformed_convex_hull_bounding_box_dirty(true)
@@ -257,12 +253,12 @@ void GLVolume::set_render_color()
         set_render_color(color, 4);
 }
 
-const Pointf3& GLVolume::get_origin() const
+const Vec3d& GLVolume::get_origin() const
 {
     return m_origin;
 }
 
-void GLVolume::set_origin(const Pointf3& origin)
+void GLVolume::set_origin(const Vec3d& origin)
 {
     if (m_origin != origin)
     {
@@ -297,15 +293,13 @@ void GLVolume::set_convex_hull(const TriangleMesh& convex_hull)
     m_convex_hull = &convex_hull;
 }
 
-std::vector<float> GLVolume::world_matrix() const
+Transform3d GLVolume::world_matrix() const
 {
-    std::vector<float> world_mat(UNIT_MATRIX, std::end(UNIT_MATRIX));
-    Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
-    m.translate(Eigen::Vector3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z));
-    m.rotate(Eigen::AngleAxisf(m_angle_z, Eigen::Vector3f::UnitZ()));
-    m.scale(m_scale_factor);
-    ::memcpy((void*)world_mat.data(), (const void*)m.data(), 16 * sizeof(float));
-    return world_mat;
+    Transform3d matrix = Transform3d::Identity();
+    matrix.translate(m_origin);
+    matrix.rotate(Eigen::AngleAxisd((double)m_angle_z, Vec3d::UnitZ()));
+    matrix.scale((double)m_scale_factor);
+    return matrix;
 }
 
 BoundingBoxf3 GLVolume::transformed_bounding_box() const
@@ -376,7 +370,7 @@ void GLVolume::render() const
 
     ::glCullFace(GL_BACK);
     ::glPushMatrix();
-    ::glTranslated(m_origin.x, m_origin.y, m_origin.z);
+    ::glTranslated(m_origin(0), m_origin(1), m_origin(2));
     ::glRotatef(m_angle_z * 180.0f / PI, 0.0f, 0.0f, 1.0f);
     ::glScalef(m_scale_factor, m_scale_factor, m_scale_factor);
     if (this->indexed_vertex_array.indexed())
@@ -410,7 +404,7 @@ void GLVolume::render_using_layer_height() const
         glUniform1f(z_texture_row_to_normalized_id, (GLfloat)(1.0f / layer_height_texture_height()));
 
     if (z_cursor_id >= 0)
-        glUniform1f(z_cursor_id, (GLfloat)(layer_height_texture_data.print_object->model_object()->bounding_box().max.z * layer_height_texture_data.z_cursor_relative));
+        glUniform1f(z_cursor_id, (GLfloat)(layer_height_texture_data.print_object->model_object()->bounding_box().max(2) * layer_height_texture_data.z_cursor_relative));
 
     if (z_cursor_band_width_id >= 0)
         glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width);
@@ -502,7 +496,7 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
     ::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr);
 
     ::glPushMatrix();
-    ::glTranslated(m_origin.x, m_origin.y, m_origin.z);
+    ::glTranslated(m_origin(0), m_origin(1), m_origin(2));
     ::glRotatef(m_angle_z * 180.0f / PI, 0.0f, 0.0f, 1.0f);
     ::glScalef(m_scale_factor, m_scale_factor, m_scale_factor);
 
@@ -547,7 +541,7 @@ void GLVolume::render_legacy() const
     ::glNormalPointer(GL_FLOAT, 6 * sizeof(float), indexed_vertex_array.vertices_and_normals_interleaved.data());
 
     ::glPushMatrix();
-    ::glTranslated(m_origin.x, m_origin.y, m_origin.z);
+    ::glTranslated(m_origin(0), m_origin(1), m_origin(2));
     ::glRotatef(m_angle_z * 180.0f / PI, 0.0f, 0.0f, 1.0f);
     ::glScalef(m_scale_factor, m_scale_factor, m_scale_factor);
 
@@ -562,7 +556,7 @@ void GLVolume::render_legacy() const
 
 double GLVolume::layer_height_texture_z_to_row_id() const
 {
-    return (this->layer_height_texture.get() == nullptr) ? 0.0 : double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * this->layer_height_texture_data.print_object->model_object()->bounding_box().max.z);
+    return (this->layer_height_texture.get() == nullptr) ? 0.0 : double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * this->layer_height_texture_data.print_object->model_object()->bounding_box().max(2));
 }
 
 void GLVolume::generate_layer_height_texture(PrintObject *print_object, bool force)
@@ -667,7 +661,7 @@ std::vector<int> GLVolumeCollection::load_object(
             }
             v.is_modifier = model_volume->modifier;
             v.shader_outside_printer_detection_enabled = !model_volume->modifier;
-            v.set_origin(Pointf3(instance->offset.x, instance->offset.y, 0.0));
+            v.set_origin(Vec3d(instance->offset(0), instance->offset(1), 0.0));
             v.set_angle_z(instance->rotation);
             v.set_scale_factor(instance->scaling_factor);
         }
@@ -698,16 +692,16 @@ int GLVolumeCollection::load_wipe_tower_preview(
         // We'll now create the box with jagged edge. y-coordinates of the pre-generated model are shifted so that the front
         // edge has y=0 and centerline of the back edge has y=depth:
         Pointf3s points;
-        std::vector<Point3> facets;
+        std::vector<Vec3crd> facets;
         float out_points_idx[][3] = {{0, -depth, 0}, {0, 0, 0}, {38.453, 0, 0}, {61.547, 0, 0}, {100, 0, 0}, {100, -depth, 0}, {55.7735, -10, 0}, {44.2265, 10, 0},
                                      {38.453, 0, 1}, {0, 0, 1}, {0, -depth, 1}, {100, -depth, 1}, {100, 0, 1}, {61.547, 0, 1}, {55.7735, -10, 1}, {44.2265, 10, 1}};
         int out_facets_idx[][3] = {{0, 1, 2}, {3, 4, 5}, {6, 5, 0}, {3, 5, 6}, {6, 2, 7}, {6, 0, 2}, {8, 9, 10}, {11, 12, 13}, {10, 11, 14}, {14, 11, 13}, {15, 8, 14},
                                    {8, 10, 14}, {3, 12, 4}, {3, 13, 12}, {6, 13, 3}, {6, 14, 13}, {7, 14, 6}, {7, 15, 14}, {2, 15, 7}, {2, 8, 15}, {1, 8, 2}, {1, 9, 8},
                                    {0, 9, 1}, {0, 10, 9}, {5, 10, 0}, {5, 11, 10}, {4, 11, 5}, {4, 12, 11}};
         for (int i=0;i<16;++i)
-            points.push_back(Pointf3(out_points_idx[i][0] / (100.f/min_width), out_points_idx[i][1] + depth, out_points_idx[i][2]));
+            points.push_back(Vec3d(out_points_idx[i][0] / (100.f/min_width), out_points_idx[i][1] + depth, out_points_idx[i][2]));
         for (int i=0;i<28;++i)
-            facets.push_back(Point3(out_facets_idx[i][0], out_facets_idx[i][1], out_facets_idx[i][2]));
+            facets.push_back(Vec3crd(out_facets_idx[i][0], out_facets_idx[i][1], out_facets_idx[i][2]));
         TriangleMesh tooth_mesh(points, facets);
 
         // We have the mesh ready. It has one tooth and width of min_width. We will now append several of these together until we are close to
@@ -718,7 +712,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
             tooth_mesh.translate(min_width, 0.f, 0.f);
         }
 
-        mesh.scale(Pointf3(width/(n*min_width), 1.f, height)); // Scaling to proper width
+        mesh.scale(Vec3d(width/(n*min_width), 1.f, height)); // Scaling to proper width
     }
     else
         mesh = make_cube(width, depth, height);
@@ -738,7 +732,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
     else
         v.indexed_vertex_array.load_mesh_flat_shading(mesh);
 
-    v.set_origin(Pointf3(pos_x, pos_y, 0.));
+    v.set_origin(Vec3d(pos_x, pos_y, 0.));
 
     // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
     v.bounding_box = v.indexed_vertex_array.bounding_box();
@@ -824,9 +818,9 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
         return false;
 
     BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
-    BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config->opt_float("max_print_height")));
+    BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), unscale<double>(config->opt_float("max_print_height"))));
     // Allow the objects to protrude below the print bed
-    print_volume.min.z = -1e10;
+    print_volume.min(2) = -1e10;
 
     ModelInstance::EPrintVolumeState state = ModelInstance::PVS_Inside;
     bool all_contained = true;
@@ -989,8 +983,8 @@ static void thick_lines_to_indexed_vertex_array(
     // right, left, top, bottom
     int     idx_prev[4]      = { -1, -1, -1, -1 };
     double  bottom_z_prev    = 0.;
-    Pointf  b1_prev;
-    Vectorf v_prev;
+    Vec2d  b1_prev(Vec2d::Zero());
+    Vec2d v_prev(Vec2d::Zero());
     int     idx_initial[4]   = { -1, -1, -1, -1 };
     double  width_initial    = 0.;
     double  bottom_z_initial = 0.0;
@@ -1000,7 +994,7 @@ static void thick_lines_to_indexed_vertex_array(
     for (size_t ii = 0; ii < lines_end; ++ ii) {
         size_t i = (ii == lines.size()) ? 0 : ii;
         const Line &line = lines[i];
-        double len = unscale(line.length());
+        double len = unscale<double>(line.length());
         double inv_len = 1.0 / len;
         double bottom_z = top_z - heights[i];
         double middle_z = 0.5 * (top_z + bottom_z);
@@ -1010,29 +1004,29 @@ static void thick_lines_to_indexed_vertex_array(
         bool is_last = (ii == lines_end - 1);
         bool is_closing = closed && is_last;
 
-        Vectorf v = Vectorf::new_unscale(line.vector());
-        v.scale(inv_len);
+        Vec2d v = unscale(line.vector());
+        v *= inv_len;
 
-        Pointf a = Pointf::new_unscale(line.a);
-        Pointf b = Pointf::new_unscale(line.b);
-        Pointf a1 = a;
-        Pointf a2 = a;
-        Pointf b1 = b;
-        Pointf b2 = b;
+        Vec2d a = unscale(line.a);
+        Vec2d b = unscale(line.b);
+        Vec2d a1 = a;
+        Vec2d a2 = a;
+        Vec2d b1 = b;
+        Vec2d b2 = b;
         {
             double dist = 0.5 * width;  // scaled
-            double dx = dist * v.x;
-            double dy = dist * v.y;
-            a1.translate(+dy, -dx);
-            a2.translate(-dy, +dx);
-            b1.translate(+dy, -dx);
-            b2.translate(-dy, +dx);
+            double dx = dist * v(0);
+            double dy = dist * v(1);
+            a1 += Vec2d(+dy, -dx);
+            a2 += Vec2d(-dy, +dx);
+            b1 += Vec2d(+dy, -dx);
+            b2 += Vec2d(-dy, +dx);
         }
 
         // calculate new XY normals
         Vector n = line.normal();
-        Vectorf3 xy_right_normal = Vectorf3::new_unscale(n.x, n.y, 0);
-        xy_right_normal.scale(inv_len);
+        Vec3d xy_right_normal = unscale(n(0), n(1), 0);
+        xy_right_normal *= inv_len;
 
         int idx_a[4];
         int idx_b[4];
@@ -1050,7 +1044,7 @@ static void thick_lines_to_indexed_vertex_array(
         // Share top / bottom vertices if possible.
         if (is_first) {
             idx_a[TOP] = idx_last++;
-            volume.push_geometry(a.x, a.y, top_z   , 0., 0.,  1.); 
+            volume.push_geometry(a(0), a(1), top_z   , 0., 0.,  1.); 
         } else {
             idx_a[TOP] = idx_prev[TOP];
         }
@@ -1058,11 +1052,11 @@ static void thick_lines_to_indexed_vertex_array(
         if (is_first || bottom_z_different) {
             // Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
             idx_a[BOTTOM] = idx_last ++;
-            volume.push_geometry(a.x, a.y, bottom_z, 0., 0., -1.);
+            volume.push_geometry(a(0), a(1), bottom_z, 0., 0., -1.);
             idx_a[LEFT ] = idx_last ++;
-            volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
+            volume.push_geometry(a2(0), a2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), -xy_right_normal(2));
             idx_a[RIGHT] = idx_last ++;
-            volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
+            volume.push_geometry(a1(0), a1(1), middle_z, xy_right_normal(0), xy_right_normal(1), xy_right_normal(2));
         }
         else {
             idx_a[BOTTOM] = idx_prev[BOTTOM];
@@ -1076,16 +1070,16 @@ static void thick_lines_to_indexed_vertex_array(
         } else {
             // Continuing a previous segment.
             // Share left / right vertices if possible.
-			double v_dot    = dot(v_prev, v);
+			double v_dot    = v_prev.dot(v);
             bool   sharp    = v_dot < 0.707; // sin(45 degrees)
             if (sharp) {
                 if (!bottom_z_different)
                 {
                     // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
                     idx_a[RIGHT] = idx_last++;
-                    volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
+                    volume.push_geometry(a1(0), a1(1), middle_z, xy_right_normal(0), xy_right_normal(1), xy_right_normal(2));
                     idx_a[LEFT] = idx_last++;
-                    volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
+                    volume.push_geometry(a2(0), a2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), -xy_right_normal(2));
                 }
             }
             if (v_dot > 0.9) {
@@ -1101,32 +1095,32 @@ static void thick_lines_to_indexed_vertex_array(
                 {
                     // Create a sharp corner with an overshot and average the left / right normals.
                     // At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc.
-                    Pointf intersection;
+                    Vec2d intersection(Vec2d::Zero());
                     Geometry::ray_ray_intersection(b1_prev, v_prev, a1, v, intersection);
                     a1 = intersection;
                     a2 = 2. * a - intersection;
-                    assert(length(a1.vector_to(a)) < width);
-                    assert(length(a2.vector_to(a)) < width);
+                    assert((a - a1).norm() < width);
+                    assert((a - a2).norm() < width);
                     float *n_left_prev  = volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6;
                     float *p_left_prev  = n_left_prev  + 3;
                     float *n_right_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6;
                     float *p_right_prev = n_right_prev + 3;
-                    p_left_prev [0] = float(a2.x);
-                    p_left_prev [1] = float(a2.y);
-                    p_right_prev[0] = float(a1.x);
-                    p_right_prev[1] = float(a1.y);
-                    xy_right_normal.x += n_right_prev[0];
-                    xy_right_normal.y += n_right_prev[1];
-                    xy_right_normal.scale(1. / length(xy_right_normal));
-                    n_left_prev [0] = float(-xy_right_normal.x);
-                    n_left_prev [1] = float(-xy_right_normal.y);
-                    n_right_prev[0] = float( xy_right_normal.x);
-                    n_right_prev[1] = float( xy_right_normal.y);
+                    p_left_prev [0] = float(a2(0));
+                    p_left_prev [1] = float(a2(1));
+                    p_right_prev[0] = float(a1(0));
+                    p_right_prev[1] = float(a1(1));
+                    xy_right_normal(0) += n_right_prev[0];
+                    xy_right_normal(1) += n_right_prev[1];
+                    xy_right_normal *= 1. / xy_right_normal.norm();
+                    n_left_prev [0] = float(-xy_right_normal(0));
+                    n_left_prev [1] = float(-xy_right_normal(1));
+                    n_right_prev[0] = float( xy_right_normal(0));
+                    n_right_prev[1] = float( xy_right_normal(1));
                     idx_a[LEFT ] = idx_prev[LEFT ];
                     idx_a[RIGHT] = idx_prev[RIGHT];
                 }
             }
-            else if (cross(v_prev, v) > 0.) {
+            else if (cross2(v_prev, v) > 0.) {
                 // Right turn. Fill in the right turn wedge.
                 volume.push_triangle(idx_prev[RIGHT], idx_a   [RIGHT],  idx_prev[TOP]   );
                 volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a   [RIGHT] );
@@ -1162,20 +1156,20 @@ static void thick_lines_to_indexed_vertex_array(
             idx_b[TOP] = idx_initial[TOP];
         } else {
             idx_b[TOP] = idx_last ++;
-            volume.push_geometry(b.x, b.y, top_z   , 0., 0.,  1.);
+            volume.push_geometry(b(0), b(1), top_z   , 0., 0.,  1.);
         }
 
         if (is_closing && (width == width_initial) && (bottom_z == bottom_z_initial)) {
             idx_b[BOTTOM] = idx_initial[BOTTOM];
         } else {
             idx_b[BOTTOM] = idx_last ++;
-            volume.push_geometry(b.x, b.y, bottom_z, 0., 0., -1.);
+            volume.push_geometry(b(0), b(1), bottom_z, 0., 0., -1.);
         }
         // Generate new vertices for the end of this line segment.
         idx_b[LEFT  ] = idx_last ++;
-        volume.push_geometry(b2.x, b2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
+        volume.push_geometry(b2(0), b2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), -xy_right_normal(2));
         idx_b[RIGHT ] = idx_last ++;
-        volume.push_geometry(b1.x, b1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
+        volume.push_geometry(b1(0), b1(1), middle_z, xy_right_normal(0), xy_right_normal(1), xy_right_normal(2));
 
         memcpy(idx_prev, idx_b, 4 * sizeof(int));
         bottom_z_prev = bottom_z;
@@ -1234,15 +1228,15 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
     int      idx_initial[4] = { -1, -1, -1, -1 };
     int      idx_prev[4] = { -1, -1, -1, -1 };
     double   z_prev = 0.0;
-    Vectorf3 n_right_prev;
-    Vectorf3 n_top_prev;
-    Vectorf3 unit_v_prev;
+    Vec3d n_right_prev = Vec3d::Zero();
+    Vec3d n_top_prev = Vec3d::Zero();
+    Vec3d unit_v_prev = Vec3d::Zero();
     double   width_initial = 0.0;
 
     // new vertices around the line endpoints
     // left, right, top, bottom
-    Pointf3 a[4];
-    Pointf3 b[4];
+    Vec3d a[4] = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
+    Vec3d b[4] = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
 
     // loop once more in case of closed loops
     size_t lines_end = closed ? (lines.size() + 1) : lines.size();
@@ -1254,29 +1248,29 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
         double height = heights[i];
         double width = widths[i];
 
-        Vectorf3 unit_v = normalize(Vectorf3::new_unscale(line.vector()));
+        Vec3d unit_v = unscale(line.vector()).normalized();
 
-        Vectorf3 n_top;
-        Vectorf3 n_right;
-        Vectorf3 unit_positive_z(0.0, 0.0, 1.0);
+        Vec3d n_top = Vec3d::Zero();
+        Vec3d n_right = Vec3d::Zero();
+        Vec3d unit_positive_z(0.0, 0.0, 1.0);
 
-        if ((line.a.x == line.b.x) && (line.a.y == line.b.y))
+        if ((line.a(0) == line.b(0)) && (line.a(1) == line.b(1)))
         {
             // vertical segment
-            n_right = (line.a.z < line.b.z) ? Vectorf3(-1.0, 0.0, 0.0) : Vectorf3(1.0, 0.0, 0.0);
-            n_top = Vectorf3(0.0, 1.0, 0.0);
+            n_right = (line.a(2) < line.b(2)) ? Vec3d(-1.0, 0.0, 0.0) : Vec3d(1.0, 0.0, 0.0);
+            n_top = Vec3d(0.0, 1.0, 0.0);
         }
         else
         {
             // generic segment
-            n_right = normalize(cross(unit_v, unit_positive_z));
-            n_top = normalize(cross(n_right, unit_v));
+            n_right = unit_v.cross(unit_positive_z).normalized();
+            n_top = n_right.cross(unit_v).normalized();
         }
 
-        Vectorf3 rl_displacement = 0.5 * width * n_right;
-        Vectorf3 tb_displacement = 0.5 * height * n_top;
-        Pointf3 l_a = Pointf3::new_unscale(line.a);
-        Pointf3 l_b = Pointf3::new_unscale(line.b);
+        Vec3d rl_displacement = 0.5 * width * n_right;
+        Vec3d tb_displacement = 0.5 * height * n_top;
+        Vec3d l_a = unscale(line.a);
+        Vec3d l_b = unscale(line.b);
 
         a[RIGHT] = l_a + rl_displacement;
         a[LEFT] = l_a - rl_displacement;
@@ -1287,15 +1281,15 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
         b[TOP] = l_b + tb_displacement;
         b[BOTTOM] = l_b - tb_displacement;
 
-        Vectorf3 n_bottom = -n_top;
-        Vectorf3 n_left = -n_right;
+        Vec3d n_bottom = -n_top;
+        Vec3d n_left = -n_right;
 
         int idx_a[4];
         int idx_b[4];
         int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6);
 
-        bool z_different = (z_prev != l_a.z);
-        z_prev = l_b.z;
+        bool z_different = (z_prev != l_a(2));
+        z_prev = l_b(2);
 
         // Share top / bottom vertices if possible.
         if (ii == 0)
@@ -1329,9 +1323,9 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
         {
             // Continuing a previous segment.
             // Share left / right vertices if possible.
-            double v_dot = dot(unit_v_prev, unit_v);
+            double v_dot = unit_v_prev.dot(unit_v);
             bool is_sharp = v_dot < 0.707; // sin(45 degrees)
-            bool is_right_turn = dot(n_top_prev, cross(unit_v_prev, unit_v)) > 0.0;
+            bool is_right_turn = n_top_prev.dot(unit_v_prev.cross(unit_v)) > 0.0;
 
             if (is_sharp)
             {
@@ -1354,9 +1348,9 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
                 // At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc.
 
                 // averages normals
-                Vectorf3 average_n_right = normalize(0.5 * (n_right + n_right_prev));
-                Vectorf3 average_n_left = -average_n_right;
-                Vectorf3 average_rl_displacement = 0.5 * width * average_n_right;
+                Vec3d average_n_right = 0.5 * (n_right + n_right_prev).normalized();
+                Vec3d average_n_left = -average_n_right;
+                Vec3d average_rl_displacement = 0.5 * width * average_n_right;
 
                 // updates vertices around a
                 a[RIGHT] = l_a + average_rl_displacement;
@@ -1364,25 +1358,25 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
 
                 // updates previous line normals
                 float* normal_left_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT] * 6;
-                normal_left_prev[0] = float(average_n_left.x);
-                normal_left_prev[1] = float(average_n_left.y);
-                normal_left_prev[2] = float(average_n_left.z);
+                normal_left_prev[0] = float(average_n_left(0));
+                normal_left_prev[1] = float(average_n_left(1));
+                normal_left_prev[2] = float(average_n_left(2));
 
                 float* normal_right_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6;
-                normal_right_prev[0] = float(average_n_right.x);
-                normal_right_prev[1] = float(average_n_right.y);
-                normal_right_prev[2] = float(average_n_right.z);
+                normal_right_prev[0] = float(average_n_right(0));
+                normal_right_prev[1] = float(average_n_right(1));
+                normal_right_prev[2] = float(average_n_right(2));
 
                 // updates previous line's vertices around b
                 float* b_left_prev = normal_left_prev + 3;
-                b_left_prev[0] = float(a[LEFT].x);
-                b_left_prev[1] = float(a[LEFT].y);
-                b_left_prev[2] = float(a[LEFT].z);
+                b_left_prev[0] = float(a[LEFT](0));
+                b_left_prev[1] = float(a[LEFT](1));
+                b_left_prev[2] = float(a[LEFT](2));
 
                 float* b_right_prev = normal_right_prev + 3;
-                b_right_prev[0] = float(a[RIGHT].x);
-                b_right_prev[1] = float(a[RIGHT].y);
-                b_right_prev[2] = float(a[RIGHT].z);
+                b_right_prev[0] = float(a[RIGHT](0));
+                b_right_prev[1] = float(a[RIGHT](1));
+                b_right_prev[2] = float(a[RIGHT](2));
 
                 idx_a[LEFT] = idx_prev[LEFT];
                 idx_a[RIGHT] = idx_prev[RIGHT];
@@ -1479,14 +1473,14 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
 #undef BOTTOM
 }
 
-static void point_to_indexed_vertex_array(const Point3& point,
+static void point_to_indexed_vertex_array(const Vec3crd& point,
     double width,
     double height,
     GLIndexedVertexArray& volume)
 {
     // builds a double piramid, with vertices on the local axes, around the point
 
-    Pointf3 center = Pointf3::new_unscale(point);
+    Vec3d center = unscale(point);
 
     double scale_factor = 1.0;
     double w = scale_factor * width;
@@ -1500,13 +1494,13 @@ static void point_to_indexed_vertex_array(const Point3& point,
         idxs[i] = idx_last + i;
     }
 
-    Vectorf3 displacement_x(w, 0.0, 0.0);
-    Vectorf3 displacement_y(0.0, w, 0.0);
-    Vectorf3 displacement_z(0.0, 0.0, h);
+    Vec3d displacement_x(w, 0.0, 0.0);
+    Vec3d displacement_y(0.0, w, 0.0);
+    Vec3d displacement_z(0.0, 0.0, h);
 
-    Vectorf3 unit_x(1.0, 0.0, 0.0);
-    Vectorf3 unit_y(0.0, 1.0, 0.0);
-    Vectorf3 unit_z(0.0, 0.0, 1.0);
+    Vec3d unit_x(1.0, 0.0, 0.0);
+    Vec3d unit_y(0.0, 1.0, 0.0);
+    Vec3d unit_z(0.0, 0.0, 1.0);
 
     // vertices
     volume.push_geometry(center - displacement_x, -unit_x); // idxs[0]
@@ -1549,7 +1543,7 @@ void _3DScene::thick_lines_to_verts(const Lines3& lines,
     thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, volume.indexed_vertex_array);
 }
 
-static void thick_point_to_verts(const Point3& point,
+static void thick_point_to_verts(const Vec3crd& point,
     double width,
     double height,
     GLVolume& volume)
@@ -1655,7 +1649,7 @@ void _3DScene::polyline3_to_verts(const Polyline3& polyline, double width, doubl
     thick_lines_to_verts(lines, widths, heights, false, volume);
 }
 
-void _3DScene::point3_to_verts(const Point3& point, double width, double height, GLVolume& volume)
+void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume)
 {
     thick_point_to_verts(point, width, height, volume);
 }
diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp
index 4290f5bda..ac3a53fe3 100644
--- a/xs/src/slic3r/GUI/3DScene.hpp
+++ b/xs/src/slic3r/GUI/3DScene.hpp
@@ -119,8 +119,8 @@ public:
         push_geometry(float(x), float(y), float(z), float(nx), float(ny), float(nz));
     }
 
-    inline void push_geometry(const Pointf3& p, const Vectorf3& n) {
-        push_geometry(p.x, p.y, p.z, n.x, n.y, n.z);
+    inline void push_geometry(const Vec3d& p, const Vec3d& n) {
+        push_geometry(p(0), p(1), p(2), n(0), n(1), n(2));
     }
 
     inline void push_triangle(int idx1, int idx2, int idx3) {
@@ -176,17 +176,17 @@ public:
         BoundingBoxf3 bbox;
         if (! this->vertices_and_normals_interleaved.empty()) {
             bbox.defined = true;
-            bbox.min.x = bbox.max.x = this->vertices_and_normals_interleaved[3];
-            bbox.min.y = bbox.max.y = this->vertices_and_normals_interleaved[4];
-            bbox.min.z = bbox.max.z = this->vertices_and_normals_interleaved[5];
+            bbox.min(0) = bbox.max(0) = this->vertices_and_normals_interleaved[3];
+            bbox.min(1) = bbox.max(1) = this->vertices_and_normals_interleaved[4];
+            bbox.min(2) = bbox.max(2) = this->vertices_and_normals_interleaved[5];
             for (size_t i = 9; i < this->vertices_and_normals_interleaved.size(); i += 6) {
                 const float *verts = this->vertices_and_normals_interleaved.data() + i;
-                bbox.min.x = std::min<coordf_t>(bbox.min.x, verts[0]);
-                bbox.min.y = std::min<coordf_t>(bbox.min.y, verts[1]);
-                bbox.min.z = std::min<coordf_t>(bbox.min.z, verts[2]);
-                bbox.max.x = std::max<coordf_t>(bbox.max.x, verts[0]);
-                bbox.max.y = std::max<coordf_t>(bbox.max.y, verts[1]);
-                bbox.max.z = std::max<coordf_t>(bbox.max.z, verts[2]);
+                bbox.min(0) = std::min<coordf_t>(bbox.min(0), verts[0]);
+                bbox.min(1) = std::min<coordf_t>(bbox.min(1), verts[1]);
+                bbox.min(2) = std::min<coordf_t>(bbox.min(2), verts[2]);
+                bbox.max(0) = std::max<coordf_t>(bbox.max(0), verts[0]);
+                bbox.max(1) = std::max<coordf_t>(bbox.max(1), verts[1]);
+                bbox.max(2) = std::max<coordf_t>(bbox.max(2), verts[2]);
             }
         }
         return bbox;
@@ -255,7 +255,7 @@ public:
 
 private:
     // Offset of the volume to be rendered.
-    Pointf3               m_origin;
+    Vec3d                 m_origin;
     // Rotation around Z axis of the volume to be rendered.
     float                 m_angle_z;
     // Scale factor of the volume to be rendered.
@@ -323,8 +323,8 @@ public:
     // Sets render color in dependence of current state
     void set_render_color();
 
-    const Pointf3& get_origin() const;
-    void set_origin(const Pointf3& origin);
+    const Vec3d& get_origin() const;
+    void set_origin(const Vec3d& origin);
     void set_angle_z(float angle_z);
     void set_scale_factor(float scale_factor);
     void set_convex_hull(const TriangleMesh& convex_hull);
@@ -333,7 +333,7 @@ public:
     int                 volume_idx() const { return (this->composite_id / 1000) % 1000; }
     int                 instance_idx() const { return this->composite_id % 1000; }
 
-    std::vector<float> world_matrix() const;
+    Transform3d         world_matrix() const;
     BoundingBoxf3       transformed_bounding_box() const;
     BoundingBoxf3       transformed_convex_hull_bounding_box() const;
 
@@ -577,7 +577,7 @@ public:
     static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GLVolume& volume);
     static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume);
     static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume);
-    static void point3_to_verts(const Point3& point, double width, double height, GLVolume& volume);
+    static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume);
 };
 
 }
diff --git a/xs/src/slic3r/GUI/BedShapeDialog.cpp b/xs/src/slic3r/GUI/BedShapeDialog.cpp
index d52535589..e04f2b370 100644
--- a/xs/src/slic3r/GUI/BedShapeDialog.cpp
+++ b/xs/src/slic3r/GUI/BedShapeDialog.cpp
@@ -48,14 +48,14 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
 	auto optgroup = init_shape_options_page(_(L("Rectangular")));
 		ConfigOptionDef def;
 		def.type = coPoints;
-		def.default_value = new ConfigOptionPoints{ Pointf(200, 200) };
+		def.default_value = new ConfigOptionPoints{ Vec2d(200, 200) };
 		def.label = L("Size");
 		def.tooltip = L("Size in X and Y of the rectangular plate.");
 		Option option(def, "rect_size");
 		optgroup->append_single_option_line(option);
 
 		def.type = coPoints;
-		def.default_value = new ConfigOptionPoints{ Pointf(0, 0) };
+		def.default_value = new ConfigOptionPoints{ Vec2d(0, 0) };
 		def.label = L("Origin");
 		def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.");
 		option = Option(def, "rect_origin");
@@ -149,21 +149,21 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
 			// okay, it's a rectangle
 			// find origin
             coordf_t x_min, x_max, y_min, y_max;
-            x_max = x_min = points->values[0].x;
-			y_max = y_min = points->values[0].y;
+            x_max = x_min = points->values[0](0);
+			y_max = y_min = points->values[0](1);
 			for (auto pt : points->values)
             {
-                x_min = std::min(x_min, pt.x);
-                x_max = std::max(x_max, pt.x);
-                y_min = std::min(y_min, pt.y);
-                y_max = std::max(y_max, pt.y);
+                x_min = std::min(x_min, pt(0));
+                x_max = std::max(x_max, pt(0));
+                y_min = std::min(y_min, pt(1));
+                y_max = std::max(y_max, pt(1));
             }
 
-            auto origin = new ConfigOptionPoints{ Pointf(-x_min, -y_min) };
+            auto origin = new ConfigOptionPoints{ Vec2d(-x_min, -y_min) };
 
 			m_shape_options_book->SetSelection(SHAPE_RECTANGULAR);
 			auto optgroup = m_optgroups[SHAPE_RECTANGULAR];
-			optgroup->set_value("rect_size", new ConfigOptionPoints{ Pointf(x_max - x_min, y_max - y_min) });//[x_max - x_min, y_max - y_min]);
+			optgroup->set_value("rect_size", new ConfigOptionPoints{ Vec2d(x_max - x_min, y_max - y_min) });//[x_max - x_min, y_max - y_min]);
 			optgroup->set_value("rect_origin", origin);
 			update_shape();
 			return;
@@ -178,7 +178,7 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
 		double avg_dist = 0;
 		for (auto pt: polygon.points)
 		{
-			double distance = center.distance_to(pt);
+			double distance = (pt - center).cast<double>().norm();
 			vertex_distances.push_back(distance);
 			avg_dist += distance;
 		}
@@ -195,7 +195,7 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
 			// all vertices are equidistant to center
 			m_shape_options_book->SetSelection(SHAPE_CIRCULAR);
 			auto optgroup = m_optgroups[SHAPE_CIRCULAR];
-			boost::any ret = wxNumberFormatter::ToString(unscale(avg_dist * 2), 0);
+			boost::any ret = wxNumberFormatter::ToString(unscale<double>(avg_dist * 2), 0);
  			optgroup->set_value("diameter", ret);
 			update_shape();
 			return;
@@ -206,8 +206,8 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
 		// Invalid polygon.Revert to default bed dimensions.
 		m_shape_options_book->SetSelection(SHAPE_RECTANGULAR);
 		auto optgroup = m_optgroups[SHAPE_RECTANGULAR];
-		optgroup->set_value("rect_size", new ConfigOptionPoints{ Pointf(200, 200) });
-		optgroup->set_value("rect_origin", new ConfigOptionPoints{ Pointf(0, 0) });
+		optgroup->set_value("rect_size", new ConfigOptionPoints{ Vec2d(200, 200) });
+		optgroup->set_value("rect_origin", new ConfigOptionPoints{ Vec2d(0, 0) });
 		update_shape();
 		return;
 	}
@@ -230,19 +230,21 @@ void BedShapePanel::update_shape()
 {
 	auto page_idx = m_shape_options_book->GetSelection();
 	if (page_idx == SHAPE_RECTANGULAR) {
-		Pointf rect_size, rect_origin;
+		Vec2d rect_size(Vec2d::Zero());
+		Vec2d rect_origin(Vec2d::Zero());
 		try{
-			rect_size = boost::any_cast<Pointf>(m_optgroups[SHAPE_RECTANGULAR]->get_value("rect_size")); }
+			rect_size = boost::any_cast<Vec2d>(m_optgroups[SHAPE_RECTANGULAR]->get_value("rect_size")); }
 		catch (const std::exception &e){
-			return;}
+			return;
+		}
 		try{
-			rect_origin = boost::any_cast<Pointf>(m_optgroups[SHAPE_RECTANGULAR]->get_value("rect_origin"));
+			rect_origin = boost::any_cast<Vec2d>(m_optgroups[SHAPE_RECTANGULAR]->get_value("rect_origin"));
 		}
 		catch (const std::exception &e){
 			return;}
 		
-		auto x = rect_size.x;
-		auto y = rect_size.y;
+		auto x = rect_size(0);
+		auto y = rect_size(1);
 		// empty strings or '-' or other things
 		if (x == 0 || y == 0)	return;
 		double x0 = 0.0;
@@ -250,17 +252,17 @@ void BedShapePanel::update_shape()
 		double x1 = x;
 		double y1 = y;
 
-		auto dx = rect_origin.x;
-		auto dy = rect_origin.y;
+		auto dx = rect_origin(0);
+		auto dy = rect_origin(1);
 
 		x0 -= dx;
 		x1 -= dx;
 		y0 -= dy;
 		y1 -= dy;
-		m_canvas->m_bed_shape = {	Pointf(x0, y0),
-									Pointf(x1, y0),
-									Pointf(x1, y1),
-									Pointf(x0, y1)};
+		m_canvas->m_bed_shape = {	Vec2d(x0, y0),
+									Vec2d(x1, y0),
+									Vec2d(x1, y1),
+									Vec2d(x0, y1)};
 	} 
 	else if(page_idx == SHAPE_CIRCULAR) {
 		double diameter;
@@ -274,10 +276,10 @@ void BedShapePanel::update_shape()
 		auto r = diameter / 2;
 		auto twopi = 2 * PI;
 		auto edges = 60;
-		std::vector<Pointf> points;
+		std::vector<Vec2d> points;
 		for (size_t i = 1; i <= 60; ++i){
 			auto angle = i * twopi / edges;
-			points.push_back(Pointf(r*cos(angle), r*sin(angle)));
+			points.push_back(Vec2d(r*cos(angle), r*sin(angle)));
 		}
 		m_canvas->m_bed_shape = points;
 	}
@@ -330,9 +332,9 @@ void BedShapePanel::load_stl()
 	}
 
 	auto polygon = expolygons[0].contour;
-	std::vector<Pointf> points;
+	std::vector<Vec2d> points;
 	for (auto pt : polygon.points)
-		points.push_back(Pointf::new_unscale(pt));
+		points.push_back(unscale(pt));
 	m_canvas->m_bed_shape = points;
 	update_preview();
 }
diff --git a/xs/src/slic3r/GUI/BedShapeDialog.hpp b/xs/src/slic3r/GUI/BedShapeDialog.hpp
index 5ff488063..d8ba5a912 100644
--- a/xs/src/slic3r/GUI/BedShapeDialog.hpp
+++ b/xs/src/slic3r/GUI/BedShapeDialog.hpp
@@ -34,7 +34,7 @@ public:
 	void		load_stl();
 	
 	// Returns the resulting bed shape polygon. This value will be stored to the ini file.
-	std::vector<Pointf>	GetValue() { return m_canvas->m_bed_shape; }
+	std::vector<Vec2d>	GetValue() { return m_canvas->m_bed_shape; }
 };
 
 class BedShapeDialog : public wxDialog
@@ -46,7 +46,7 @@ public:
 	~BedShapeDialog(){  }
 
 	void		build_dialog(ConfigOptionPoints* default_pt);
-	std::vector<Pointf>	GetValue() { return m_panel->GetValue(); }
+	std::vector<Vec2d>	GetValue() { return m_panel->GetValue(); }
 };
 
 } // GUI
diff --git a/xs/src/slic3r/GUI/Field.cpp b/xs/src/slic3r/GUI/Field.cpp
index 757a18f11..3c7c817a6 100644
--- a/xs/src/slic3r/GUI/Field.cpp
+++ b/xs/src/slic3r/GUI/Field.cpp
@@ -632,9 +632,9 @@ void PointCtrl::BUILD()
 	wxSize field_size(40, -1);
 
 	auto default_pt = static_cast<ConfigOptionPoints*>(m_opt.default_value)->values.at(0);
-	double val = default_pt.x;
+	double val = default_pt(0);
 	wxString X = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None);
-	val = default_pt.y;
+	val = default_pt(1);
 	wxString Y = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None);
 
 	x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size);
@@ -655,13 +655,13 @@ void PointCtrl::BUILD()
 	y_textctrl->SetToolTip(get_tooltip_text(X+", "+Y));
 }
 
-void PointCtrl::set_value(const Pointf& value, bool change_event)
+void PointCtrl::set_value(const Vec2d& value, bool change_event)
 {
 	m_disable_change_event = !change_event;
 
-	double val = value.x;
+	double val = value(0);
 	x_textctrl->SetValue(val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None));
-	val = value.y;
+	val = value(1);
 	y_textctrl->SetValue(val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None));
 
 	m_disable_change_event = false;
@@ -669,8 +669,8 @@ void PointCtrl::set_value(const Pointf& value, bool change_event)
 
 void PointCtrl::set_value(const boost::any& value, bool change_event)
 {
-	Pointf pt;
-	const Pointf *ptf = boost::any_cast<Pointf>(&value);
+	Vec2d pt(Vec2d::Zero());
+	const Vec2d *ptf = boost::any_cast<Vec2d>(&value);
 	if (!ptf)
 	{
 		ConfigOptionPoints* pts = boost::any_cast<ConfigOptionPoints*>(value);
@@ -683,13 +683,10 @@ void PointCtrl::set_value(const boost::any& value, bool change_event)
 
 boost::any& PointCtrl::get_value()
 {
-	Pointf ret_point;
-	double val;
-	x_textctrl->GetValue().ToDouble(&val);
-	ret_point.x = val;
-	y_textctrl->GetValue().ToDouble(&val);
-	ret_point.y = val;
-	return m_value = ret_point;
+	double x, y;
+	x_textctrl->GetValue().ToDouble(&x);
+	y_textctrl->GetValue().ToDouble(&y);
+	return m_value = Vec2d(x, y);
 }
 
 void StaticText::BUILD()
diff --git a/xs/src/slic3r/GUI/Field.hpp b/xs/src/slic3r/GUI/Field.hpp
index db8d2a408..e19c47d68 100644
--- a/xs/src/slic3r/GUI/Field.hpp
+++ b/xs/src/slic3r/GUI/Field.hpp
@@ -372,7 +372,7 @@ public:
 
 	void			BUILD()  override;
 
-	void			set_value(const Pointf& value, bool change_event = false);
+	void			set_value(const Vec2d& value, bool change_event = false);
 	void			set_value(const boost::any& value, bool change_event = false);
 	boost::any&		get_value() override;
 
diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp
index b354e2979..a155769a5 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp
@@ -71,8 +71,8 @@ bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool
     if (generate_tex_coords)
         m_tex_coords = std::vector<float>(t_size, 0.0f);
 
-    float min_x = (float)unscale(triangles[0].points[0].x);
-    float min_y = (float)unscale(triangles[0].points[0].y);
+    float min_x = unscale<float>(triangles[0].points[0](0));
+    float min_y = unscale<float>(triangles[0].points[0](1));
     float max_x = min_x;
     float max_y = min_y;
 
@@ -83,8 +83,8 @@ bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool
         for (unsigned int v = 0; v < 3; ++v)
         {
             const Point& p = t.points[v];
-            float x = (float)unscale(p.x);
-            float y = (float)unscale(p.y);
+            float x = unscale<float>(p(0));
+            float y = unscale<float>(p(1));
 
             m_vertices[v_coord++] = x;
             m_vertices[v_coord++] = y;
@@ -137,11 +137,11 @@ bool GeometryBuffer::set_from_lines(const Lines& lines, float z)
     unsigned int coord = 0;
     for (const Line& l : lines)
     {
-        m_vertices[coord++] = (float)unscale(l.a.x);
-        m_vertices[coord++] = (float)unscale(l.a.y);
+        m_vertices[coord++] = unscale<float>(l.a(0));
+        m_vertices[coord++] = unscale<float>(l.a(1));
         m_vertices[coord++] = z;
-        m_vertices[coord++] = (float)unscale(l.b.x);
-        m_vertices[coord++] = (float)unscale(l.b.y);
+        m_vertices[coord++] = unscale<float>(l.b(0));
+        m_vertices[coord++] = unscale<float>(l.b(1));
         m_vertices[coord++] = z;
     }
 
@@ -317,9 +317,9 @@ bool GLCanvas3D::Bed::set_shape(const Pointfs& shape)
     _calc_bounding_box();
 
     ExPolygon poly;
-    for (const Pointf& p : m_shape)
+    for (const Vec2d& p : m_shape)
     {
-        poly.contour.append(Point(scale_(p.x), scale_(p.y)));
+        poly.contour.append(Point(scale_(p(0)), scale_(p(1))));
     }
 
     _calc_triangles(poly);
@@ -373,9 +373,9 @@ void GLCanvas3D::Bed::render(float theta) const
 void GLCanvas3D::Bed::_calc_bounding_box()
 {
     m_bounding_box = BoundingBoxf3();
-    for (const Pointf& p : m_shape)
+    for (const Vec2d& p : m_shape)
     {
-        m_bounding_box.merge(Pointf3(p.x, p.y, 0.0));
+        m_bounding_box.merge(Vec3d(p(0), p(1), 0.0));
     }
 }
 
@@ -391,18 +391,18 @@ void GLCanvas3D::Bed::_calc_triangles(const ExPolygon& poly)
 void GLCanvas3D::Bed::_calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox)
 {
     Polylines axes_lines;
-    for (coord_t x = bed_bbox.min.x; x <= bed_bbox.max.x; x += scale_(10.0))
+    for (coord_t x = bed_bbox.min(0); x <= bed_bbox.max(0); x += scale_(10.0))
     {
         Polyline line;
-        line.append(Point(x, bed_bbox.min.y));
-        line.append(Point(x, bed_bbox.max.y));
+        line.append(Point(x, bed_bbox.min(1)));
+        line.append(Point(x, bed_bbox.max(1)));
         axes_lines.push_back(line);
     }
-    for (coord_t y = bed_bbox.min.y; y <= bed_bbox.max.y; y += scale_(10.0))
+    for (coord_t y = bed_bbox.min(1); y <= bed_bbox.max(1); y += scale_(10.0))
     {
         Polyline line;
-        line.append(Point(bed_bbox.min.x, y));
-        line.append(Point(bed_bbox.max.x, y));
+        line.append(Point(bed_bbox.min(0), y));
+        line.append(Point(bed_bbox.max(0), y));
         axes_lines.push_back(line);
     }
 
@@ -591,7 +591,7 @@ bool GLCanvas3D::Bed::_are_equal(const Pointfs& bed_1, const Pointfs& bed_2)
 }
 
 GLCanvas3D::Axes::Axes()
-    : length(0.0f)
+    : origin(0, 0, 0), length(0.0f)
 {
 }
 
@@ -606,12 +606,12 @@ void GLCanvas3D::Axes::render(bool depth_test) const
     ::glBegin(GL_LINES);
     // draw line for x axis
     ::glColor3f(1.0f, 0.0f, 0.0f);
-    ::glVertex3f((GLfloat)origin.x, (GLfloat)origin.y, (GLfloat)origin.z);
-    ::glVertex3f((GLfloat)origin.x + length, (GLfloat)origin.y, (GLfloat)origin.z);
+    ::glVertex3f((GLfloat)origin(0), (GLfloat)origin(1), (GLfloat)origin(2));
+    ::glVertex3f((GLfloat)origin(0) + length, (GLfloat)origin(1), (GLfloat)origin(2));
     // draw line for y axis
     ::glColor3f(0.0f, 1.0f, 0.0f);
-    ::glVertex3f((GLfloat)origin.x, (GLfloat)origin.y, (GLfloat)origin.z);
-    ::glVertex3f((GLfloat)origin.x, (GLfloat)origin.y + length, (GLfloat)origin.z);
+    ::glVertex3f((GLfloat)origin(0), (GLfloat)origin(1), (GLfloat)origin(2));
+    ::glVertex3f((GLfloat)origin(0), (GLfloat)origin(1) + length, (GLfloat)origin(2));
     ::glEnd();
     // draw line for Z axis
     // (re-enable depth test so that axis is correctly shown when objects are behind it)
@@ -620,8 +620,8 @@ void GLCanvas3D::Axes::render(bool depth_test) const
 
     ::glBegin(GL_LINES);
     ::glColor3f(0.0f, 0.0f, 1.0f);
-    ::glVertex3f((GLfloat)origin.x, (GLfloat)origin.y, (GLfloat)origin.z);
-    ::glVertex3f((GLfloat)origin.x, (GLfloat)origin.y, (GLfloat)origin.z + length);
+    ::glVertex3f((GLfloat)origin(0), (GLfloat)origin(1), (GLfloat)origin(2));
+    ::glVertex3f((GLfloat)origin(0), (GLfloat)origin(1), (GLfloat)origin(2) + length);
     ::glEnd();
 }
 
@@ -655,10 +655,10 @@ void GLCanvas3D::CuttingPlane::_render_plane(const BoundingBoxf3& bb) const
         ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
         float margin = 20.0f;
-        float min_x = bb.min.x - margin;
-        float max_x = bb.max.x + margin;
-        float min_y = bb.min.y - margin;
-        float max_y = bb.max.y + margin;
+        float min_x = bb.min(0) - margin;
+        float max_x = bb.max(0) + margin;
+        float min_y = bb.min(1) - margin;
+        float max_y = bb.max(1) + margin;
 
         ::glBegin(GL_QUADS);
         ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
@@ -869,8 +869,8 @@ float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas)
 {
     const Point& mouse_pos = canvas.get_local_mouse_position();
     const Rect& rect = get_bar_rect_screen(canvas);
-    float x = (float)mouse_pos.x;
-    float y = (float)mouse_pos.y;
+    float x = (float)mouse_pos(0);
+    float y = (float)mouse_pos(1);
     float t = rect.get_top();
     float b = rect.get_bottom();
 
@@ -979,7 +979,7 @@ void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) co
 
 void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas3D& canvas, const GLVolume& volume, const PrintObject& print_object, const Rect& bar_rect) const
 {
-    float max_z = print_object.model_object()->bounding_box().max.z;
+    float max_z = print_object.model_object()->bounding_box().max(2);
 
     m_shader.start_using();
 
@@ -1040,7 +1040,7 @@ void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object,
     // Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region.
     layer_height_max *= 1.12;
 
-    coordf_t max_z = unscale(print_object.size.z);
+    coordf_t max_z = unscale<double>(print_object.size(2));
     double layer_height = dynamic_cast<const ConfigOptionFloat*>(print_object.config.option("layer_height"))->value;
     float l = bar_rect.get_left();
     float w = bar_rect.get_right() - l;
@@ -1075,11 +1075,12 @@ void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object,
 }
 
 const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX);
-const Pointf3 GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MAX);
+const Vec3d GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MAX);
 
 GLCanvas3D::Mouse::Drag::Drag()
     : start_position_2D(Invalid_2D_Point)
     , start_position_3D(Invalid_3D_Point)
+    , volume_center_offset(0, 0, 0)
     , move_with_shift(false)
     , move_volume_idx(-1)
     , gizmo_volume_idx(-1)
@@ -1175,7 +1176,7 @@ void GLCanvas3D::Gizmos::set_enabled(bool enable)
     m_enabled = enable;
 }
 
-void GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Pointf& mouse_pos)
+void GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos)
 {
     if (!m_enabled)
         return;
@@ -1194,14 +1195,14 @@ void GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Poin
         // we currently use circular icons for gizmo, so we check the radius
         if (it->second->get_state() != GLGizmoBase::On)
         {
-            bool inside = length(Pointf(OverlayOffsetX + half_tex_size, top_y + half_tex_size).vector_to(mouse_pos)) < half_tex_size;
+            bool inside = (mouse_pos - Vec2d(OverlayOffsetX + half_tex_size, top_y + half_tex_size)).norm() < half_tex_size;
             it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
         }
         top_y += (tex_size + OverlayGapY);
     }
 }
 
-void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Pointf& mouse_pos)
+void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos)
 {
     if (!m_enabled)
         return;
@@ -1218,7 +1219,7 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Poi
         float half_tex_size = 0.5f * tex_size;
 
         // we currently use circular icons for gizmo, so we check the radius
-        if (length(Pointf(OverlayOffsetX + half_tex_size, top_y + half_tex_size).vector_to(mouse_pos)) < half_tex_size)
+        if ((mouse_pos - Vec2d(OverlayOffsetX + half_tex_size, top_y + half_tex_size)).norm() < half_tex_size)
         {
             if ((it->second->get_state() == GLGizmoBase::On))
             {
@@ -1267,7 +1268,7 @@ void GLCanvas3D::Gizmos::set_hover_id(int id)
     }
 }
 
-bool GLCanvas3D::Gizmos::overlay_contains_mouse(const GLCanvas3D& canvas, const Pointf& mouse_pos) const
+bool GLCanvas3D::Gizmos::overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const
 {
     if (!m_enabled)
         return false;
@@ -1284,7 +1285,7 @@ bool GLCanvas3D::Gizmos::overlay_contains_mouse(const GLCanvas3D& canvas, const
         float half_tex_size = 0.5f * tex_size;
 
         // we currently use circular icons for gizmo, so we check the radius
-        if (length(Pointf(OverlayOffsetX + half_tex_size, top_y + half_tex_size).vector_to(mouse_pos)) < half_tex_size)
+        if ((mouse_pos - Vec2d(OverlayOffsetX + half_tex_size, top_y + half_tex_size)).norm() < half_tex_size)
             return true;
 
         top_y += (tex_size + OverlayGapY);
@@ -2078,7 +2079,7 @@ void GLCanvas3D::set_bed_shape(const Pointfs& shape)
     bool new_shape = m_bed.set_shape(shape);
 
     // Set the origin and size for painting of the coordinate system axes.
-    m_axes.origin = Pointf3(0.0, 0.0, (coordf_t)GROUND_Z);
+    m_axes.origin = Vec3d(0.0, 0.0, (coordf_t)GROUND_Z);
     set_axes_length(0.3f * (float)m_bed.get_bounding_box().max_size());
 
     if (new_shape)
@@ -2098,19 +2099,19 @@ void GLCanvas3D::set_auto_bed_shape()
     // draw a default square bed around object center
     const BoundingBoxf3& bbox = volumes_bounding_box();
     coordf_t max_size = bbox.max_size();
-    const Pointf3& center = bbox.center();
+    const Vec3d center = bbox.center();
 
     Pointfs bed_shape;
     bed_shape.reserve(4);
-    bed_shape.emplace_back(center.x - max_size, center.y - max_size);
-    bed_shape.emplace_back(center.x + max_size, center.y - max_size);
-    bed_shape.emplace_back(center.x + max_size, center.y + max_size);
-    bed_shape.emplace_back(center.x - max_size, center.y + max_size);
+    bed_shape.emplace_back(center(0) - max_size, center(1) - max_size);
+    bed_shape.emplace_back(center(0) + max_size, center(1) - max_size);
+    bed_shape.emplace_back(center(0) + max_size, center(1) + max_size);
+    bed_shape.emplace_back(center(0) - max_size, center(1) + max_size);
 
     set_bed_shape(bed_shape);
 
     // Set the origin for painting of the coordinate system axes.
-    m_axes.origin = Pointf3(center.x, center.y, (coordf_t)GROUND_Z);
+    m_axes.origin = Vec3d(center(0), center(1), (coordf_t)GROUND_Z);
 }
 
 void GLCanvas3D::set_axes_length(float length)
@@ -2462,7 +2463,7 @@ void GLCanvas3D::reload_scene(bool force)
         if ((extruders_count > 1) && semm && wt && !co)
         {
             // Height of a print (Show at least a slab)
-            coordf_t height = std::max(m_model->bounding_box().max.z, 10.0);
+            coordf_t height = std::max(m_model->bounding_box().max(2), 10.0);
 
             float x = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_x"))->value;
             float y = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_y"))->value;
@@ -2948,7 +2949,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
     else if (evt.Leaving())
     {
         // to remove hover on objects when the mouse goes out of this canvas
-        m_mouse.position = Pointf(-1.0, -1.0);
+        m_mouse.position = Vec2d(-1.0, -1.0);
         m_dirty = true;
     }
     else if (evt.LeftDClick() && (m_hover_volume_id != -1))
@@ -2964,14 +2965,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
         // on a volume or not.
         int volume_idx = m_hover_volume_id;
         m_layers_editing.state = LayersEditing::Unknown;
-        if ((layer_editing_object_idx != -1) && m_layers_editing.bar_rect_contains(*this, pos.x, pos.y))
+        if ((layer_editing_object_idx != -1) && m_layers_editing.bar_rect_contains(*this, pos(0), pos(1)))
         {
             // A volume is selected and the mouse is inside the layer thickness bar.
             // Start editing the layer height.
             m_layers_editing.state = LayersEditing::Editing;
             _perform_layer_editing_action(&evt);
         }
-        else if ((layer_editing_object_idx != -1) && m_layers_editing.reset_rect_contains(*this, pos.x, pos.y))
+        else if ((layer_editing_object_idx != -1) && m_layers_editing.reset_rect_contains(*this, pos(0), pos(1)))
         {
             if (evt.LeftDown())
             {
@@ -3039,7 +3040,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
                 {
                     // The mouse_to_3d gets the Z coordinate from the Z buffer at the screen coordinate pos x, y,
                     // an converts the screen space coordinate to unscaled object space.
-                    Pointf3 pos3d = (volume_idx == -1) ? Pointf3(DBL_MAX, DBL_MAX) : _mouse_to_3d(pos);
+                    Vec3d pos3d = (volume_idx == -1) ? Vec3d(DBL_MAX, DBL_MAX, DBL_MAX) : _mouse_to_3d(pos);
 
                     // Only accept the initial position, if it is inside the volume bounding box.
                     BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box();
@@ -3052,20 +3053,20 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
                         m_mouse.drag.start_position_3D = pos3d;
                         // Remember the shift to to the object center.The object center will later be used
                         // to limit the object placement close to the bed.
-                        m_mouse.drag.volume_center_offset = pos3d.vector_to(volume_bbox.center());
+                        m_mouse.drag.volume_center_offset = volume_bbox.center() - pos3d;
                     }
                 }
                 else if (evt.RightDown())
                 {
                     // forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while
                     // the context menu is already shown, ensuring it to disappear if the mouse is outside any volume
-                    m_mouse.position = Pointf((coordf_t)pos.x, (coordf_t)pos.y);
+                    m_mouse.position = Vec2d((double)pos(0), (double)pos(1));
                     render();
                     if (m_hover_volume_id != -1)
                     {
                         // if right clicking on volume, propagate event through callback (shows context menu)
                         if (m_volumes.volumes[volume_idx]->hover)
-                            m_on_right_click_callback.call(pos.x, pos.y);
+                            m_on_right_click_callback.call(pos(0), pos(1));
                     }
                 }
             }
@@ -3078,21 +3079,21 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
         // Get new position at the same Z of the initial click point.
         float z0 = 0.0f;
         float z1 = 1.0f;
-        Pointf3 cur_pos = Linef3(_mouse_to_3d(pos, &z0), _mouse_to_3d(pos, &z1)).intersect_plane(m_mouse.drag.start_position_3D.z);
+        Vec3d cur_pos = Linef3(_mouse_to_3d(pos, &z0), _mouse_to_3d(pos, &z1)).intersect_plane(m_mouse.drag.start_position_3D(2));
 
         // Clip the new position, so the object center remains close to the bed.
-        cur_pos.translate(m_mouse.drag.volume_center_offset);
-        Point cur_pos2(scale_(cur_pos.x), scale_(cur_pos.y));
+        cur_pos += m_mouse.drag.volume_center_offset;
+        Point cur_pos2(scale_(cur_pos(0)), scale_(cur_pos(1)));
         if (!m_bed.contains(cur_pos2))
         {
             Point ip = m_bed.point_projection(cur_pos2);
-            cur_pos.x = unscale(ip.x);
-            cur_pos.y = unscale(ip.y);
+            cur_pos(0) = unscale<double>(ip(0));
+            cur_pos(1) = unscale<double>(ip(1));
         }
-        cur_pos.translate(m_mouse.drag.volume_center_offset.negative());
+        cur_pos -= m_mouse.drag.volume_center_offset;
 
         // Calculate the translation vector.
-        Vectorf3 vector = m_mouse.drag.start_position_3D.vector_to(cur_pos);
+        Vec3d vector = cur_pos - m_mouse.drag.start_position_3D;
         // Get the volume being dragged.
         GLVolume* volume = m_volumes.volumes[m_mouse.drag.move_volume_idx];
         // Get all volumes belonging to the same group, if any.
@@ -3114,11 +3115,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 
         // Apply new temporary volume origin and ignore Z.
         for (GLVolume* v : volumes)
-        {
-            Pointf3 origin = v->get_origin();
-            origin.translate(vector.x, vector.y, 0.0);
-            v->set_origin(origin);
-        }
+            v->set_origin(v->get_origin() + Vec3d(vector(0), vector(1), 0.0));
 
         m_mouse.drag.start_position_3D = cur_pos;
         m_gizmos.refresh();
@@ -3180,8 +3177,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             {
                 bb.merge(volume->transformed_bounding_box());
             }
-            const Pointf3& size = bb.size();
-            m_on_update_geometry_info_callback.call(size.x, size.y, size.z, m_gizmos.get_scale());
+            const Vec3d& size = bb.size();
+            m_on_update_geometry_info_callback.call(size(0), size(1), size(2), m_gizmos.get_scale());
         }
 
         if ((m_gizmos.get_current_type() != Gizmos::Rotate) && (volumes.size() > 1))
@@ -3203,15 +3200,15 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             // if dragging over blank area with left button, rotate
             if (m_mouse.is_start_position_3D_defined())
             {
-                const Pointf3& orig = m_mouse.drag.start_position_3D;
-                m_camera.phi += (((float)pos.x - (float)orig.x) * TRACKBALLSIZE);
-                m_camera.set_theta(m_camera.get_theta() - ((float)pos.y - (float)orig.y) * TRACKBALLSIZE);
+                const Vec3d& orig = m_mouse.drag.start_position_3D;
+                m_camera.phi += (((float)pos(0) - (float)orig(0)) * TRACKBALLSIZE);
+                m_camera.set_theta(m_camera.get_theta() - ((float)pos(1) - (float)orig(1)) * TRACKBALLSIZE);
 
                 m_on_viewport_changed_callback.call();
 
                 m_dirty = true;
             }
-            m_mouse.drag.start_position_3D = Pointf3((coordf_t)pos.x, (coordf_t)pos.y, 0.0);
+            m_mouse.drag.start_position_3D = Vec3d((coordf_t)pos(0), (coordf_t)pos(1), 0.0);
         }
         else if (evt.MiddleIsDown() || evt.RightIsDown())
         {
@@ -3220,11 +3217,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             {
                 // get point in model space at Z = 0
                 float z = 0.0f;
-                const Pointf3& cur_pos = _mouse_to_3d(pos, &z);
-                Pointf3 orig = _mouse_to_3d(m_mouse.drag.start_position_2D, &z);
-                Pointf3 camera_target = m_camera.target;
-                camera_target.translate(orig.vector_to(cur_pos).negative());
-                m_camera.target = camera_target;
+                const Vec3d& cur_pos = _mouse_to_3d(pos, &z);
+                Vec3d orig = _mouse_to_3d(m_mouse.drag.start_position_2D, &z);
+                m_camera.target += orig - cur_pos;
 
                 m_on_viewport_changed_callback.call();
 
@@ -3307,7 +3302,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
     }
     else if (evt.Moving())
     {
-        m_mouse.position = Pointf((coordf_t)pos.x, (coordf_t)pos.y);
+        m_mouse.position = Vec2d((coordf_t)pos(0), (coordf_t)pos(1));
         // Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor hovers over.
         if (m_picking_enabled)
             m_dirty = true;
@@ -3676,25 +3671,25 @@ float GLCanvas3D::_get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) co
     ::glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
 
     // camera axes
-    Pointf3 right((coordf_t)matrix[0], (coordf_t)matrix[4], (coordf_t)matrix[8]);
-    Pointf3 up((coordf_t)matrix[1], (coordf_t)matrix[5], (coordf_t)matrix[9]);
-    Pointf3 forward((coordf_t)matrix[2], (coordf_t)matrix[6], (coordf_t)matrix[10]);
+    Vec3d right((coordf_t)matrix[0], (coordf_t)matrix[4], (coordf_t)matrix[8]);
+    Vec3d up((coordf_t)matrix[1], (coordf_t)matrix[5], (coordf_t)matrix[9]);
+    Vec3d forward((coordf_t)matrix[2], (coordf_t)matrix[6], (coordf_t)matrix[10]);
 
-    Pointf3 bb_min = bbox.min;
-    Pointf3 bb_max = bbox.max;
-    Pointf3 bb_center = bbox.center();
+    Vec3d bb_min = bbox.min;
+    Vec3d bb_max = bbox.max;
+    Vec3d bb_center = bbox.center();
 
     // bbox vertices in world space
-    std::vector<Pointf3> vertices;
+    std::vector<Vec3d> vertices;
     vertices.reserve(8);
     vertices.push_back(bb_min);
-    vertices.emplace_back(bb_max.x, bb_min.y, bb_min.z);
-    vertices.emplace_back(bb_max.x, bb_max.y, bb_min.z);
-    vertices.emplace_back(bb_min.x, bb_max.y, bb_min.z);
-    vertices.emplace_back(bb_min.x, bb_min.y, bb_max.z);
-    vertices.emplace_back(bb_max.x, bb_min.y, bb_max.z);
+    vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2));
+    vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2));
+    vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2));
+    vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2));
+    vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2));
     vertices.push_back(bb_max);
-    vertices.emplace_back(bb_min.x, bb_max.y, bb_max.z);
+    vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2));
 
     coordf_t max_x = 0.0;
     coordf_t max_y = 0.0;
@@ -3702,15 +3697,15 @@ float GLCanvas3D::_get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) co
     // margin factor to give some empty space around the bbox
     coordf_t margin_factor = 1.25;
 
-    for (const Pointf3 v : vertices)
+    for (const Vec3d v : vertices)
     {
         // project vertex on the plane perpendicular to camera forward axis
-        Pointf3 pos(v.x - bb_center.x, v.y - bb_center.y, v.z - bb_center.z);
-        Pointf3 proj_on_plane = pos - dot(pos, forward) * forward;
+        Vec3d pos(v(0) - bb_center(0), v(1) - bb_center(1), v(2) - bb_center(2));
+        Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
 
         // calculates vertex coordinate along camera xy axes
-        coordf_t x_on_plane = dot(proj_on_plane, right);
-        coordf_t y_on_plane = dot(proj_on_plane, up);
+        coordf_t x_on_plane = proj_on_plane.dot(right);
+        coordf_t y_on_plane = proj_on_plane.dot(up);
 
         max_x = std::max(max_x, margin_factor * std::abs(x_on_plane));
         max_y = std::max(max_y, margin_factor * std::abs(y_on_plane));
@@ -3802,15 +3797,15 @@ void GLCanvas3D::_camera_tranform() const
     ::glRotatef(-m_camera.get_theta(), 1.0f, 0.0f, 0.0f); // pitch
     ::glRotatef(m_camera.phi, 0.0f, 0.0f, 1.0f);          // yaw
 
-    Pointf3 neg_target = m_camera.target.negative();
-    ::glTranslatef((GLfloat)neg_target.x, (GLfloat)neg_target.y, (GLfloat)neg_target.z);
+    Vec3d neg_target = - m_camera.target;
+    ::glTranslatef((GLfloat)neg_target(0), (GLfloat)neg_target(1), (GLfloat)neg_target(2));
 }
 
 void GLCanvas3D::_picking_pass() const
 {
-    const Pointf& pos = m_mouse.position;
+    const Vec2d& pos = m_mouse.position;
 
-    if (m_picking_enabled && !m_mouse.dragging && (pos != Pointf(DBL_MAX, DBL_MAX)))
+    if (m_picking_enabled && !m_mouse.dragging && (pos != Vec2d(DBL_MAX, DBL_MAX)))
     {
         // Render the object for picking.
         // FIXME This cannot possibly work in a multi - sampled context as the color gets mangled by the anti - aliasing.
@@ -3838,10 +3833,10 @@ void GLCanvas3D::_picking_pass() const
 
         GLubyte color[4] = { 0, 0, 0, 0 };
         const Size& cnv_size = get_canvas_size();
-        bool inside = (0 <= pos.x) && (pos.x < cnv_size.get_width()) && (0 <= pos.y) && (pos.y < cnv_size.get_height());
+        bool inside = (0 <= pos(0)) && (pos(0) < cnv_size.get_width()) && (0 <= pos(1)) && (pos(1) < cnv_size.get_height());
         if (inside)
         {
-            ::glReadPixels(pos.x, cnv_size.get_height() - pos.y - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color);
+            ::glReadPixels(pos(0), cnv_size.get_height() - pos(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color);
             volume_id = color[0] + color[1] * 256 + color[2] * 256 * 256;
         }
 
@@ -3939,7 +3934,7 @@ void GLCanvas3D::_render_objects() const
             if (m_config != nullptr)
             {
                 const BoundingBoxf3& bed_bb = m_bed.get_bounding_box();
-                m_volumes.set_print_box((float)bed_bb.min.x, (float)bed_bb.min.y, 0.0f, (float)bed_bb.max.x, (float)bed_bb.max.y, (float)m_config->opt_float("max_print_height"));
+                m_volumes.set_print_box((float)bed_bb.min(0), (float)bed_bb.min(1), 0.0f, (float)bed_bb.max(0), (float)bed_bb.max(1), (float)m_config->opt_float("max_print_height"));
                 m_volumes.check_outside_state(m_config, nullptr);
             }
             // do not cull backfaces to show broken geometry, if any
@@ -4107,7 +4102,7 @@ void GLCanvas3D::_perform_layer_editing_action(wxMouseEvent* evt)
     {
         const Rect& rect = LayersEditing::get_bar_rect_screen(*this);
         float b = rect.get_bottom();
-        m_layers_editing.last_z = unscale(selected_obj->size.z) * (b - evt->GetY() - 1.0f) / (b - rect.get_top());
+        m_layers_editing.last_z = unscale<double>(selected_obj->size(2)) * (b - evt->GetY() - 1.0f) / (b - rect.get_top());
         m_layers_editing.last_action = evt->ShiftDown() ? (evt->RightIsDown() ? 3 : 2) : (evt->RightIsDown() ? 0 : 1);
     }
 
@@ -4137,10 +4132,10 @@ void GLCanvas3D::_perform_layer_editing_action(wxMouseEvent* evt)
     _start_timer();
 }
 
-Pointf3 GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
+Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
 {
     if (m_canvas == nullptr)
-        return Pointf3(DBL_MAX, DBL_MAX, DBL_MAX);
+        return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
 
     _camera_tranform();
 
@@ -4151,19 +4146,19 @@ Pointf3 GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
     GLdouble projection_matrix[16];
     ::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix);
 
-    GLint y = viewport[3] - (GLint)mouse_pos.y;
+    GLint y = viewport[3] - (GLint)mouse_pos(1);
     GLfloat mouse_z;
     if (z == nullptr)
-        ::glReadPixels((GLint)mouse_pos.x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, (void*)&mouse_z);
+        ::glReadPixels((GLint)mouse_pos(0), y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, (void*)&mouse_z);
     else
         mouse_z = *z;
 
     GLdouble out_x, out_y, out_z;
-    ::gluUnProject((GLdouble)mouse_pos.x, (GLdouble)y, (GLdouble)mouse_z, modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z);
-    return Pointf3((coordf_t)out_x, (coordf_t)out_y, (coordf_t)out_z);
+    ::gluUnProject((GLdouble)mouse_pos(0), (GLdouble)y, (GLdouble)mouse_z, modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z);
+    return Vec3d((coordf_t)out_x, (coordf_t)out_y, (coordf_t)out_z);
 }
 
-Pointf3 GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos)
+Vec3d GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos)
 {
     return mouse_ray(mouse_pos).intersect_plane(0.0);
 }
@@ -4883,7 +4878,7 @@ bool GLCanvas3D::_travel_paths_by_type(const GCodePreviewData& preview_data)
         TypesList::iterator type = std::find(types.begin(), types.end(), Type(polyline.type));
         if (type != types.end())
         {
-            type->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().min.z));
+            type->volume->print_zs.push_back(unscale<double>(polyline.polyline.bounding_box().min(2)));
             type->volume->offsets.push_back(type->volume->indexed_vertex_array.quad_indices.size());
             type->volume->offsets.push_back(type->volume->indexed_vertex_array.triangle_indices.size());
 
@@ -4949,7 +4944,7 @@ bool GLCanvas3D::_travel_paths_by_feedrate(const GCodePreviewData& preview_data)
         FeedratesList::iterator feedrate = std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate));
         if (feedrate != feedrates.end())
         {
-            feedrate->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().min.z));
+            feedrate->volume->print_zs.push_back(unscale<double>(polyline.polyline.bounding_box().min(2)));
             feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.quad_indices.size());
             feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.triangle_indices.size());
 
@@ -5015,7 +5010,7 @@ bool GLCanvas3D::_travel_paths_by_tool(const GCodePreviewData& preview_data, con
         ToolsList::iterator tool = std::find(tools.begin(), tools.end(), Tool(polyline.extruder_id));
         if (tool != tools.end())
         {
-            tool->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().min.z));
+            tool->volume->print_zs.push_back(unscale<double>(polyline.polyline.bounding_box().min(2)));
             tool->volume->offsets.push_back(tool->volume->indexed_vertex_array.quad_indices.size());
             tool->volume->offsets.push_back(tool->volume->indexed_vertex_array.triangle_indices.size());
 
@@ -5040,11 +5035,11 @@ void GLCanvas3D::_load_gcode_retractions(const GCodePreviewData& preview_data)
         m_volumes.volumes.emplace_back(volume);
 
         GCodePreviewData::Retraction::PositionsList copy(preview_data.retraction.positions);
-        std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2){ return p1.position.z < p2.position.z; });
+        std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2){ return p1.position(2) < p2.position(2); });
 
         for (const GCodePreviewData::Retraction::Position& position : copy)
         {
-            volume->print_zs.push_back(unscale(position.position.z));
+            volume->print_zs.push_back(unscale<double>(position.position(2)));
             volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size());
             volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size());
 
@@ -5071,11 +5066,11 @@ void GLCanvas3D::_load_gcode_unretractions(const GCodePreviewData& preview_data)
         m_volumes.volumes.emplace_back(volume);
 
         GCodePreviewData::Retraction::PositionsList copy(preview_data.unretraction.positions);
-        std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2){ return p1.position.z < p2.position.z; });
+        std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2){ return p1.position(2) < p2.position(2); });
 
         for (const GCodePreviewData::Retraction::Position& position : copy)
         {
-            volume->print_zs.push_back(unscale(position.position.z));
+            volume->print_zs.push_back(unscale<double>(position.position(2)));
             volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size());
             volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size());
 
@@ -5115,7 +5110,7 @@ void GLCanvas3D::_load_shells()
     }
 
     // adds wipe tower's volume
-    coordf_t max_z = m_print->objects[0]->model_object()->get_model()->bounding_box().max.z;
+    coordf_t max_z = m_print->objects[0]->model_object()->get_model()->bounding_box().max(2);
     const PrintConfig& config = m_print->config;
     unsigned int extruders_count = config.nozzle_diameter.size();
     if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) {
@@ -5198,9 +5193,9 @@ void GLCanvas3D::_update_toolpath_volumes_outside_state()
         if (opt != nullptr)
         {
             BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
-            print_volume = BoundingBoxf3(Pointf3(unscale(bed_box_2D.min.x) - tolerance_x, unscale(bed_box_2D.min.y) - tolerance_y, 0.0), Pointf3(unscale(bed_box_2D.max.x) + tolerance_x, unscale(bed_box_2D.max.y) + tolerance_y, m_config->opt_float("max_print_height")));
+            print_volume = BoundingBoxf3(Vec3d(unscale<double>(bed_box_2D.min(0)) - tolerance_x, unscale<double>(bed_box_2D.min(1)) - tolerance_y, 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)) + tolerance_x, unscale<double>(bed_box_2D.max(1)) + tolerance_y, m_config->opt_float("max_print_height")));
             // Allow the objects to protrude below the print bed
-            print_volume.min.z = -1e10;
+            print_volume.min(2) = -1e10;
         }
     }
 
@@ -5231,7 +5226,7 @@ void GLCanvas3D::_on_move(const std::vector<int>& volume_idxs)
 
     std::set<std::string> done;  // prevent moving instances twice
     bool object_moved = false;
-    Pointf3 wipe_tower_origin(0.0, 0.0, 0.0);
+    Vec3d wipe_tower_origin(0.0, 0.0, 0.0);
     for (int volume_idx : volume_idxs)
     {
         GLVolume* volume = m_volumes.volumes[volume_idx];
@@ -5250,8 +5245,8 @@ void GLCanvas3D::_on_move(const std::vector<int>& volume_idxs)
         {
             // Move a regular object.
             ModelObject* model_object = m_model->objects[obj_idx];
-            const Pointf3& origin = volume->get_origin();
-            model_object->instances[instance_idx]->offset = Pointf(origin.x, origin.y);
+            const Vec3d& origin = volume->get_origin();
+            model_object->instances[instance_idx]->offset = Vec2d(origin(0), origin(1));
             model_object->invalidate_bounding_box();
             object_moved = true;
         }
@@ -5263,8 +5258,8 @@ void GLCanvas3D::_on_move(const std::vector<int>& volume_idxs)
     if (object_moved)
         m_on_instance_moved_callback.call();
 
-    if (wipe_tower_origin != Pointf3(0.0, 0.0, 0.0))
-        m_on_wipe_tower_moved_callback.call(wipe_tower_origin.x, wipe_tower_origin.y);
+    if (wipe_tower_origin != Vec3d(0.0, 0.0, 0.0))
+        m_on_wipe_tower_moved_callback.call(wipe_tower_origin(0), wipe_tower_origin(1));
 }
 
 void GLCanvas3D::_on_select(int volume_idx)
diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp
index b3606d014..0cd2870eb 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp
@@ -120,7 +120,7 @@ public:
         float zoom;
         float phi;
 //        float distance;
-        Pointf3 target;
+        Vec3d target;
 
     private:
         float m_theta;
@@ -185,7 +185,7 @@ public:
 
     struct Axes
     {
-        Pointf3 origin;
+        Vec3d origin;
         float length;
 
         Axes();
@@ -299,11 +299,11 @@ public:
         struct Drag
         {
             static const Point Invalid_2D_Point;
-            static const Pointf3 Invalid_3D_Point;
+            static const Vec3d Invalid_3D_Point;
 
             Point start_position_2D;
-            Pointf3 start_position_3D;
-            Vectorf3 volume_center_offset;
+            Vec3d start_position_3D;
+            Vec3d volume_center_offset;
 
             bool move_with_shift;
             int move_volume_idx;
@@ -314,7 +314,7 @@ public:
         };
 
         bool dragging;
-        Pointf position;
+        Vec2d position;
         Drag drag;
 
         Mouse();
@@ -357,13 +357,13 @@ public:
         bool is_enabled() const;
         void set_enabled(bool enable);
 
-        void update_hover_state(const GLCanvas3D& canvas, const Pointf& mouse_pos);
-        void update_on_off_state(const GLCanvas3D& canvas, const Pointf& mouse_pos);
+        void update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos);
+        void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos);
         void reset_all_states();
 
         void set_hover_id(int id);
 
-        bool overlay_contains_mouse(const GLCanvas3D& canvas, const Pointf& mouse_pos) const;
+        bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const;
         bool grabber_contains_mouse() const;
         void update(const Linef3& mouse_ray);
         void refresh();
@@ -691,10 +691,10 @@ private:
 
     // Convert the screen space coordinate to an object space coordinate.
     // If the Z screen space coordinate is not provided, a depth buffer value is substituted.
-    Pointf3 _mouse_to_3d(const Point& mouse_pos, float* z = nullptr);
+    Vec3d _mouse_to_3d(const Point& mouse_pos, float* z = nullptr);
 
     // Convert the screen space coordinate to world coordinate on the bed.
-    Pointf3 _mouse_to_bed_3d(const Point& mouse_pos);
+    Vec3d _mouse_to_bed_3d(const Point& mouse_pos);
 
     // Returns the view ray line, in world coordinate, at the given mouse position.
     Linef3 mouse_ray(const Point& mouse_pos);
diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp
index 978b35495..6adad04d1 100644
--- a/xs/src/slic3r/GUI/GLGizmo.cpp
+++ b/xs/src/slic3r/GUI/GLGizmo.cpp
@@ -23,7 +23,7 @@ const float GLGizmoBase::Grabber::HalfSize = 2.0f;
 const float GLGizmoBase::Grabber::DraggingScaleFactor = 1.25f;
 
 GLGizmoBase::Grabber::Grabber()
-    : center(Pointf3(0.0, 0.0, 0.0))
+    : center(0.0, 0.0, 0.0)
     , angle_x(0.0f)
     , angle_y(0.0f)
     , angle_z(0.0f)
@@ -73,7 +73,7 @@ void GLGizmoBase::Grabber::render(const float* render_color) const
     ::glColor3f((GLfloat)render_color[0], (GLfloat)render_color[1], (GLfloat)render_color[2]);
 
     ::glPushMatrix();
-    ::glTranslatef((GLfloat)center.x, (GLfloat)center.y, (GLfloat)center.z);
+    ::glTranslatef((GLfloat)center(0), (GLfloat)center(1), (GLfloat)center(2));
 
     float rad_to_deg = 180.0f / (GLfloat)PI;
     ::glRotatef((GLfloat)angle_x * rad_to_deg, 1.0f, 0.0f, 0.0f);
@@ -249,7 +249,7 @@ GLGizmoRotate::GLGizmoRotate(GLGizmoRotate::Axis axis)
     : GLGizmoBase()
     , m_axis(axis)
     , m_angle(0.0f)
-    , m_center(Pointf3(0.0, 0.0, 0.0))
+    , m_center(0.0, 0.0, 0.0)
     , m_radius(0.0f)
     , m_keep_initial_values(false)
 {
@@ -287,18 +287,18 @@ bool GLGizmoRotate::on_init()
 }
 
 void GLGizmoRotate::on_update(const Linef3& mouse_ray)
-{
-    Pointf mouse_pos = mouse_position_in_local_plane(mouse_ray);
+{ 
+    Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(mouse_ray));
 
-    Vectorf orig_dir(1.0, 0.0);
-    Vectorf new_dir = normalize(mouse_pos);
+    Vec2d orig_dir = Vec2d::UnitX();
+    Vec2d new_dir = mouse_pos.normalized();
 
-    coordf_t theta = ::acos(clamp(-1.0, 1.0, dot(new_dir, orig_dir)));
-    if (cross(orig_dir, new_dir) < 0.0)
+    double theta = ::acos(clamp(-1.0, 1.0, new_dir.dot(orig_dir)));
+    if (cross2(orig_dir, new_dir) < 0.0)
         theta = 2.0 * (coordf_t)PI - theta;
 
     // snap
-    double len = length(mouse_pos);
+    double len = mouse_pos.norm();
     double in_radius = (double)m_radius / 3.0;
     double out_radius = 2.0 * (double)in_radius;
     if ((in_radius <= len) && (len <= out_radius))
@@ -323,16 +323,16 @@ void GLGizmoRotate::on_render(const BoundingBoxf3& box) const
 
     if (!m_keep_initial_values)
     {
-        const Pointf3& size = box.size();
         m_center = box.center();
 #if !ENABLE_GIZMOS_3D
-        m_center.z = 0.0;
+        const Vec3d& size = box.size();
+        m_center(2) = 0.0;
 #endif // !ENABLE_GIZMOS_3D
 
 #if ENABLE_GIZMOS_3D
         m_radius = Offset + box.radius();
 #else
-        m_radius = Offset + ::sqrt(sqr(0.5f * size.x) + sqr(0.5f * size.y));
+        m_radius = Offset + ::sqrt(sqr(0.5f * (float)size(0)) + sqr(0.5f * (float)size(1)));
 #endif // ENABLE_GIZMOS_3D
         m_keep_initial_values = true;
     }
@@ -481,7 +481,7 @@ void GLGizmoRotate::render_angle() const
 void GLGizmoRotate::render_grabber() const
 {
     float grabber_radius = m_radius + GrabberOffset;
-    m_grabbers[0].center = Pointf3(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0f);
+    m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0);
     m_grabbers[0].angle_z = m_angle;
 
 #if ENABLE_GIZMOS_3D
@@ -492,7 +492,7 @@ void GLGizmoRotate::render_grabber() const
 
     ::glBegin(GL_LINES);
     ::glVertex3f(0.0f, 0.0f, 0.0f);
-    ::glVertex3f((GLfloat)m_grabbers[0].center.x, (GLfloat)m_grabbers[0].center.y, (GLfloat)m_grabbers[0].center.z);
+    ::glVertex3f((GLfloat)m_grabbers[0].center(0), (GLfloat)m_grabbers[0].center(1), (GLfloat)m_grabbers[0].center(2));
     ::glEnd();
 
     ::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 3 * sizeof(float));
@@ -501,7 +501,7 @@ void GLGizmoRotate::render_grabber() const
 
 void GLGizmoRotate::transform_to_local() const
 {
-    ::glTranslatef((GLfloat)m_center.x, (GLfloat)m_center.y, (GLfloat)m_center.z);
+    ::glTranslatef((GLfloat)m_center(0), (GLfloat)m_center(1), (GLfloat)m_center(2));
 
     switch (m_axis)
     {
@@ -526,24 +526,24 @@ void GLGizmoRotate::transform_to_local() const
     }
 }
 
-Pointf GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray) const
+Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray) const
 {
-    float half_pi = 0.5f * (float)PI;
+    double half_pi = 0.5 * (double)PI;
 
-    Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
+    Transform3d m = Transform3d::Identity();
 
     switch (m_axis)
     {
     case X:
     {
-        m.rotate(Eigen::AngleAxisf(-half_pi, Eigen::Vector3f::UnitZ()));
-        m.rotate(Eigen::AngleAxisf(-half_pi, Eigen::Vector3f::UnitY()));
+        m.rotate(Eigen::AngleAxisd(-half_pi, Vec3d::UnitZ()));
+        m.rotate(Eigen::AngleAxisd(-half_pi, Vec3d::UnitY()));
         break;
     }
     case Y:
     {
-        m.rotate(Eigen::AngleAxisf(-(float)PI, Eigen::Vector3f::UnitZ()));
-        m.rotate(Eigen::AngleAxisf(-half_pi, Eigen::Vector3f::UnitX()));
+        m.rotate(Eigen::AngleAxisd(-(double)PI, Vec3d::UnitZ()));
+        m.rotate(Eigen::AngleAxisd(-half_pi, Vec3d::UnitX()));
         break;
     }
     default:
@@ -554,19 +554,19 @@ Pointf GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray) con
     }
     }
 
-    m.translate(Eigen::Vector3f((float)-m_center.x, (float)-m_center.y, (float)-m_center.z));
+    m.translate(-m_center);
 
-    Eigen::Matrix<float, 3, 2> world_ray;
-    Eigen::Matrix<float, 3, 2> local_ray;
-    world_ray(0, 0) = (float)mouse_ray.a.x;
-    world_ray(1, 0) = (float)mouse_ray.a.y;
-    world_ray(2, 0) = (float)mouse_ray.a.z;
-    world_ray(0, 1) = (float)mouse_ray.b.x;
-    world_ray(1, 1) = (float)mouse_ray.b.y;
-    world_ray(2, 1) = (float)mouse_ray.b.z;
+    Eigen::Matrix<double, 3, 2> world_ray;
+    Eigen::Matrix<double, 3, 2> local_ray;
+    world_ray(0, 0) = mouse_ray.a(0);
+    world_ray(1, 0) = mouse_ray.a(1);
+    world_ray(2, 0) = mouse_ray.a(2);
+    world_ray(0, 1) = mouse_ray.b(0);
+    world_ray(1, 1) = mouse_ray.b(1);
+    world_ray(2, 1) = mouse_ray.b(2);
     local_ray = m * world_ray.colwise().homogeneous();
 
-    return Linef3(Pointf3(local_ray(0, 0), local_ray(1, 0), local_ray(2, 0)), Pointf3(local_ray(0, 1), local_ray(1, 1), local_ray(2, 1))).intersect_plane(0.0);
+    return Linef3(Vec3d(local_ray(0, 0), local_ray(1, 0), local_ray(2, 0)), Vec3d(local_ray(0, 1), local_ray(1, 1), local_ray(2, 1))).intersect_plane(0.0);
 }
 
 GLGizmoRotate3D::GLGizmoRotate3D()
@@ -708,17 +708,17 @@ bool GLGizmoScale::on_init()
 void GLGizmoScale::on_start_dragging()
 {
     if (m_hover_id != -1)
-        m_starting_drag_position = m_grabbers[m_hover_id].center;
+        m_starting_drag_position = to_2d(m_grabbers[m_hover_id].center);
 }
 
 void GLGizmoScale::on_update(const Linef3& mouse_ray)
 {
-    Pointf mouse_pos = mouse_ray.intersect_plane(0.0);
-    Pointf center(0.5 * (m_grabbers[1].center.x + m_grabbers[0].center.x), 0.5 * (m_grabbers[3].center.y + m_grabbers[0].center.y));
+    Vec2d mouse_pos = to_2d(mouse_ray.intersect_plane(0.0));
+    Vec2d center(0.5 * (m_grabbers[1].center(0) + m_grabbers[0].center(0)), 0.5 * (m_grabbers[3].center(1) + m_grabbers[0].center(1)));
 
-    coordf_t orig_len = length(m_starting_drag_position - center);
-    coordf_t new_len = length(mouse_pos - center);
-    coordf_t ratio = (orig_len != 0.0) ? new_len / orig_len : 1.0;
+    double orig_len = (m_starting_drag_position - center).norm();
+    double new_len = (mouse_pos - center).norm();
+    double ratio = (orig_len != 0.0) ? new_len / orig_len : 1.0;
 
     m_scale = m_starting_scale * (float)ratio;
 }
@@ -727,15 +727,15 @@ void GLGizmoScale::on_render(const BoundingBoxf3& box) const
 {
     ::glDisable(GL_DEPTH_TEST);
 
-    coordf_t min_x = box.min.x - (coordf_t)Offset;
-    coordf_t max_x = box.max.x + (coordf_t)Offset;
-    coordf_t min_y = box.min.y - (coordf_t)Offset;
-    coordf_t max_y = box.max.y + (coordf_t)Offset;
+    double min_x = box.min(0) - (double)Offset;
+    double max_x = box.max(0) + (double)Offset;
+    double min_y = box.min(1) - (double)Offset;
+    double max_y = box.max(1) + (double)Offset;
 
-    m_grabbers[0].center = Pointf3(min_x, min_y, 0.0f);
-    m_grabbers[1].center = Pointf3(max_x, min_y, 0.0f);
-    m_grabbers[2].center = Pointf3(max_x, max_y, 0.0f);
-    m_grabbers[3].center = Pointf3(min_x, max_y, 0.0f);
+    m_grabbers[0].center = Vec3d(min_x, min_y, 0.0);
+    m_grabbers[1].center = Vec3d(max_x, min_y, 0.0);
+    m_grabbers[2].center = Vec3d(max_x, max_y, 0.0);
+    m_grabbers[3].center = Vec3d(min_x, max_y, 0.0);
 
     ::glLineWidth(2.0f);
     ::glColor3fv(m_drag_color);
@@ -744,7 +744,7 @@ void GLGizmoScale::on_render(const BoundingBoxf3& box) const
     ::glBegin(GL_LINE_LOOP);
     for (unsigned int i = 0; i < 4; ++i)
     {
-        ::glVertex3f((GLfloat)m_grabbers[i].center.x, (GLfloat)m_grabbers[i].center.y, 0.0f);
+        ::glVertex3f((GLfloat)m_grabbers[i].center(0), (GLfloat)m_grabbers[i].center(1), 0.0f);
     }
     ::glEnd();
 
@@ -841,34 +841,34 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const
 {
     ::glEnable(GL_DEPTH_TEST);
 
-    Vectorf3 offset_vec((coordf_t)Offset, (coordf_t)Offset, (coordf_t)Offset);
+    Vec3d offset_vec((double)Offset, (double)Offset, (double)Offset);
 
     m_box = BoundingBoxf3(box.min - offset_vec, box.max + offset_vec);
-    const Pointf3& center = m_box.center();
+    const Vec3d& center = m_box.center();
 
     // x axis
-    m_grabbers[0].center = Pointf3(m_box.min.x, center.y, center.z);
-    m_grabbers[1].center = Pointf3(m_box.max.x, center.y, center.z);
+    m_grabbers[0].center = Vec3d(m_box.min(0), center(1), center(2));
+    m_grabbers[1].center = Vec3d(m_box.max(0), center(1), center(2));
     ::memcpy((void*)m_grabbers[0].color, (const void*)RED, 3 * sizeof(float));
     ::memcpy((void*)m_grabbers[1].color, (const void*)RED, 3 * sizeof(float));
 
     // y axis
-    m_grabbers[2].center = Pointf3(center.x, m_box.min.y, center.z);
-    m_grabbers[3].center = Pointf3(center.x, m_box.max.y, center.z);
+    m_grabbers[2].center = Vec3d(center(0), m_box.min(1), center(2));
+    m_grabbers[3].center = Vec3d(center(0), m_box.max(1), center(2));
     ::memcpy((void*)m_grabbers[2].color, (const void*)GREEN, 3 * sizeof(float));
     ::memcpy((void*)m_grabbers[3].color, (const void*)GREEN, 3 * sizeof(float));
 
     // z axis
-    m_grabbers[4].center = Pointf3(center.x, center.y, m_box.min.z);
-    m_grabbers[5].center = Pointf3(center.x, center.y, m_box.max.z);
+    m_grabbers[4].center = Vec3d(center(0), center(1), m_box.min(2));
+    m_grabbers[5].center = Vec3d(center(0), center(1), m_box.max(2));
     ::memcpy((void*)m_grabbers[4].color, (const void*)BLUE, 3 * sizeof(float));
     ::memcpy((void*)m_grabbers[5].color, (const void*)BLUE, 3 * sizeof(float));
 
     // uniform
-    m_grabbers[6].center = Pointf3(m_box.min.x, m_box.min.y, m_box.min.z);
-    m_grabbers[7].center = Pointf3(m_box.max.x, m_box.min.y, m_box.min.z);
-    m_grabbers[8].center = Pointf3(m_box.max.x, m_box.max.y, m_box.min.z);
-    m_grabbers[9].center = Pointf3(m_box.min.x, m_box.max.y, m_box.min.z);
+    m_grabbers[6].center = Vec3d(m_box.min(0), m_box.min(1), m_box.min(2));
+    m_grabbers[7].center = Vec3d(m_box.max(0), m_box.min(1), m_box.min(2));
+    m_grabbers[8].center = Vec3d(m_box.max(0), m_box.max(1), m_box.min(2));
+    m_grabbers[9].center = Vec3d(m_box.min(0), m_box.max(1), m_box.min(2));
     for (int i = 6; i < 10; ++i)
     {
         ::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 3 * sizeof(float));
@@ -942,26 +942,26 @@ void GLGizmoScale3D::render_box() const
 {
     // bottom face
     ::glBegin(GL_LINE_LOOP);
-    ::glVertex3f((GLfloat)m_box.min.x, (GLfloat)m_box.min.y, (GLfloat)m_box.min.z);
-    ::glVertex3f((GLfloat)m_box.min.x, (GLfloat)m_box.max.y, (GLfloat)m_box.min.z);
-    ::glVertex3f((GLfloat)m_box.max.x, (GLfloat)m_box.max.y, (GLfloat)m_box.min.z);
-    ::glVertex3f((GLfloat)m_box.max.x, (GLfloat)m_box.min.y, (GLfloat)m_box.min.z);
+    ::glVertex3f((GLfloat)m_box.min(0), (GLfloat)m_box.min(1), (GLfloat)m_box.min(2));
+    ::glVertex3f((GLfloat)m_box.min(0), (GLfloat)m_box.max(1), (GLfloat)m_box.min(2));
+    ::glVertex3f((GLfloat)m_box.max(0), (GLfloat)m_box.max(1), (GLfloat)m_box.min(2));
+    ::glVertex3f((GLfloat)m_box.max(0), (GLfloat)m_box.min(1), (GLfloat)m_box.min(2));
     ::glEnd();
 
     // top face
     ::glBegin(GL_LINE_LOOP);
-    ::glVertex3f((GLfloat)m_box.min.x, (GLfloat)m_box.min.y, (GLfloat)m_box.max.z);
-    ::glVertex3f((GLfloat)m_box.min.x, (GLfloat)m_box.max.y, (GLfloat)m_box.max.z);
-    ::glVertex3f((GLfloat)m_box.max.x, (GLfloat)m_box.max.y, (GLfloat)m_box.max.z);
-    ::glVertex3f((GLfloat)m_box.max.x, (GLfloat)m_box.min.y, (GLfloat)m_box.max.z);
+    ::glVertex3f((GLfloat)m_box.min(0), (GLfloat)m_box.min(1), (GLfloat)m_box.max(2));
+    ::glVertex3f((GLfloat)m_box.min(0), (GLfloat)m_box.max(1), (GLfloat)m_box.max(2));
+    ::glVertex3f((GLfloat)m_box.max(0), (GLfloat)m_box.max(1), (GLfloat)m_box.max(2));
+    ::glVertex3f((GLfloat)m_box.max(0), (GLfloat)m_box.min(1), (GLfloat)m_box.max(2));
     ::glEnd();
 
     // vertical edges
     ::glBegin(GL_LINES);
-    ::glVertex3f((GLfloat)m_box.min.x, (GLfloat)m_box.min.y, (GLfloat)m_box.min.z); ::glVertex3f((GLfloat)m_box.min.x, (GLfloat)m_box.min.y, (GLfloat)m_box.max.z);
-    ::glVertex3f((GLfloat)m_box.min.x, (GLfloat)m_box.max.y, (GLfloat)m_box.min.z); ::glVertex3f((GLfloat)m_box.min.x, (GLfloat)m_box.max.y, (GLfloat)m_box.max.z);
-    ::glVertex3f((GLfloat)m_box.max.x, (GLfloat)m_box.max.y, (GLfloat)m_box.min.z); ::glVertex3f((GLfloat)m_box.max.x, (GLfloat)m_box.max.y, (GLfloat)m_box.max.z);
-    ::glVertex3f((GLfloat)m_box.max.x, (GLfloat)m_box.min.y, (GLfloat)m_box.min.z); ::glVertex3f((GLfloat)m_box.max.x, (GLfloat)m_box.min.y, (GLfloat)m_box.max.z);
+    ::glVertex3f((GLfloat)m_box.min(0), (GLfloat)m_box.min(1), (GLfloat)m_box.min(2)); ::glVertex3f((GLfloat)m_box.min(0), (GLfloat)m_box.min(1), (GLfloat)m_box.max(2));
+    ::glVertex3f((GLfloat)m_box.min(0), (GLfloat)m_box.max(1), (GLfloat)m_box.min(2)); ::glVertex3f((GLfloat)m_box.min(0), (GLfloat)m_box.max(1), (GLfloat)m_box.max(2));
+    ::glVertex3f((GLfloat)m_box.max(0), (GLfloat)m_box.max(1), (GLfloat)m_box.min(2)); ::glVertex3f((GLfloat)m_box.max(0), (GLfloat)m_box.max(1), (GLfloat)m_box.max(2));
+    ::glVertex3f((GLfloat)m_box.max(0), (GLfloat)m_box.min(1), (GLfloat)m_box.min(2)); ::glVertex3f((GLfloat)m_box.max(0), (GLfloat)m_box.min(1), (GLfloat)m_box.max(2));
     ::glEnd();
 }
 
@@ -971,25 +971,25 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int
     if ((id_1 < grabbers_count) && (id_2 < grabbers_count))
     {
         ::glBegin(GL_LINES);
-        ::glVertex3f((GLfloat)m_grabbers[id_1].center.x, (GLfloat)m_grabbers[id_1].center.y, (GLfloat)m_grabbers[id_1].center.z);
-        ::glVertex3f((GLfloat)m_grabbers[id_2].center.x, (GLfloat)m_grabbers[id_2].center.y, (GLfloat)m_grabbers[id_2].center.z);
+        ::glVertex3f((GLfloat)m_grabbers[id_1].center(0), (GLfloat)m_grabbers[id_1].center(1), (GLfloat)m_grabbers[id_1].center(2));
+        ::glVertex3f((GLfloat)m_grabbers[id_2].center(0), (GLfloat)m_grabbers[id_2].center(1), (GLfloat)m_grabbers[id_2].center(2));
         ::glEnd();
     }
 }
 
-Linef3 transform(const Linef3& line, const Eigen::Transform<float, 3, Eigen::Affine>& t)
+Linef3 transform(const Linef3& line, const Transform3d& t)
 {
-    Eigen::Matrix<float, 3, 2> world_line;
-    Eigen::Matrix<float, 3, 2> local_line;
-    world_line(0, 0) = (float)line.a.x;
-    world_line(1, 0) = (float)line.a.y;
-    world_line(2, 0) = (float)line.a.z;
-    world_line(0, 1) = (float)line.b.x;
-    world_line(1, 1) = (float)line.b.y;
-    world_line(2, 1) = (float)line.b.z;
+    Eigen::Matrix<double, 3, 2> world_line;
+    Eigen::Matrix<double, 3, 2> local_line;
+    world_line(0, 0) = line.a(0);
+    world_line(1, 0) = line.a(1);
+    world_line(2, 0) = line.a(2);
+    world_line(0, 1) = line.b(0);
+    world_line(1, 1) = line.b(1);
+    world_line(2, 1) = line.b(2);
     local_line = t * world_line.colwise().homogeneous();
 
-    return Linef3(Pointf3(local_line(0, 0), local_line(1, 0), local_line(2, 0)), Pointf3(local_line(0, 1), local_line(1, 1), local_line(2, 1)));
+    return Linef3(Vec3d(local_line(0, 0), local_line(1, 0), local_line(2, 0)), Vec3d(local_line(0, 1), local_line(1, 1), local_line(2, 1)));
 }
 
 void GLGizmoScale3D::do_scale_x(const Linef3& mouse_ray)
@@ -1020,8 +1020,8 @@ void GLGizmoScale3D::do_scale_z(const Linef3& mouse_ray)
 
 void GLGizmoScale3D::do_scale_uniform(const Linef3& mouse_ray)
 {
-    Pointf3 center = m_starting_center;
-    center.z = m_box.min.z;
+    Vec3d center = m_starting_center;
+    center(2) = m_box.min(2);
     double ratio = calc_ratio(0, mouse_ray, center);
 
     if (ratio > 0.0)
@@ -1032,17 +1032,17 @@ void GLGizmoScale3D::do_scale_uniform(const Linef3& mouse_ray)
     }
 }
 
-double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Pointf3& center) const
+double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Vec3d& center) const
 {
     double ratio = 0.0;
 
-    Vectorf3 starting_vec = m_starting_drag_position - center;
-    double len_starting_vec = length(starting_vec);
+    Vec3d starting_vec = m_starting_drag_position - center;
+    double len_starting_vec = starting_vec.norm();
     if (len_starting_vec == 0.0)
         return ratio;
 
-    Vectorf3 starting_vec_dir = normalize(starting_vec);
-    Vectorf3 mouse_dir = mouse_ray.unit_vector();
+    Vec3d starting_vec_dir = starting_vec.normalized();
+    Vec3d mouse_dir = mouse_ray.unit_vector();
     unsigned int plane_id = preferred_plane_id;
 
     // 1st try to see if the mouse direction is close enough to the preferred plane normal
@@ -1051,17 +1051,17 @@ double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3&
     {
     case 0:
     {
-        dot_to_normal = std::abs(dot(mouse_dir, Vectorf3(0.0, 0.0, 1.0)));
+        dot_to_normal = std::abs(mouse_dir.dot(Vec3d::UnitZ()));
         break;
     }
     case 1:
     {
-        dot_to_normal = std::abs(dot(mouse_dir, Vectorf3(0.0, -1.0, 0.0)));
+        dot_to_normal = std::abs(mouse_dir.dot(-Vec3d::UnitY()));
         break;
     }
     case 2:
     {
-        dot_to_normal = std::abs(dot(mouse_dir, Vectorf3(1.0, 0.0, 0.0)));
+        dot_to_normal = std::abs(mouse_dir.dot(Vec3d::UnitX()));
         break;
     }
     }
@@ -1073,9 +1073,9 @@ double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3&
         typedef std::map<double, unsigned int> ProjsMap;
         ProjsMap projs_map;
 
-        projs_map.insert(ProjsMap::value_type(std::abs(dot(mouse_dir, Vectorf3(0.0, 0.0, 1.0))), 0));  // plane xy
-        projs_map.insert(ProjsMap::value_type(std::abs(dot(mouse_dir, Vectorf3(0.0, -1.0, 0.0))), 1)); // plane xz
-        projs_map.insert(ProjsMap::value_type(std::abs(dot(mouse_dir, Vectorf3(1.0, 0.0, 0.0))), 2));  // plane yz
+        projs_map.insert(ProjsMap::value_type(std::abs(mouse_dir.dot(Vec3d::UnitZ())), 0));  // plane xy
+        projs_map.insert(ProjsMap::value_type(std::abs(mouse_dir.dot(-Vec3d::UnitY())), 1)); // plane xz
+        projs_map.insert(ProjsMap::value_type(std::abs(mouse_dir.dot(Vec3d::UnitX())), 2));  // plane yz
         plane_id = projs_map.rbegin()->second;
     }
 
@@ -1084,36 +1084,36 @@ double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3&
     case 0:
     {
         // calculates the intersection of the mouse ray with the plane parallel to plane XY and passing through the given center
-        Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
-        m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)center.z));
-        Pointf mouse_pos_2d = transform(mouse_ray, m).intersect_plane(0.0);
+        Transform3d m = Transform3d::Identity();
+        m.translate(-center);
+        Vec2d mouse_pos_2d = to_2d(transform(mouse_ray, m).intersect_plane(0.0));
 
         // ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
-        ratio = dot(Vectorf3(mouse_pos_2d.x, mouse_pos_2d.y, 0.0), starting_vec_dir) / len_starting_vec;
+        ratio = starting_vec_dir.dot(Vec3d(mouse_pos_2d(0), mouse_pos_2d(1), 0.0)) / len_starting_vec;
         break;
     }
     case 1:
     {
         // calculates the intersection of the mouse ray with the plane parallel to plane XZ and passing through the given center
-        Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
-        m.rotate(Eigen::AngleAxisf(-0.5f * (float)PI, Eigen::Vector3f::UnitX()));
-        m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)center.z));
-        Pointf mouse_pos_2d = transform(mouse_ray, m).intersect_plane(0.0);
+        Transform3d m = Transform3d::Identity();
+        m.rotate(Eigen::AngleAxisd(-0.5 * (double)PI, Vec3d::UnitX()));
+        m.translate(-center);
+        Vec2d mouse_pos_2d = to_2d(transform(mouse_ray, m).intersect_plane(0.0));
 
         // ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
-        ratio = dot(Vectorf3(mouse_pos_2d.x, 0.0, mouse_pos_2d.y), starting_vec_dir) / len_starting_vec;
+        ratio = starting_vec_dir.dot(Vec3d(mouse_pos_2d(0), 0.0, mouse_pos_2d(1))) / len_starting_vec;
         break;
     }
     case 2:
     {
         // calculates the intersection of the mouse ray with the plane parallel to plane YZ and passing through the given center
-        Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
-        m.rotate(Eigen::AngleAxisf(-0.5f * (float)PI, Eigen::Vector3f::UnitY()));
-        m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)center.z));
-        Pointf mouse_pos_2d = transform(mouse_ray, m).intersect_plane(0.0);
+        Transform3d m = Transform3d::Identity();
+        m.rotate(Eigen::AngleAxisd(-0.5f * (double)PI, Vec3d::UnitY()));
+        m.translate(-center);
+        Vec2d mouse_pos_2d = to_2d(transform(mouse_ray, m).intersect_plane(0.0));
 
         // ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
-        ratio = dot(Vectorf3(0.0, mouse_pos_2d.y, -mouse_pos_2d.x), starting_vec_dir) / len_starting_vec;
+        ratio = starting_vec_dir.dot(Vec3d(0.0, mouse_pos_2d(1), -mouse_pos_2d(0))) / len_starting_vec;
         break;
     }
     }
diff --git a/xs/src/slic3r/GUI/GLGizmo.hpp b/xs/src/slic3r/GUI/GLGizmo.hpp
index b584286b4..0bef4bf63 100644
--- a/xs/src/slic3r/GUI/GLGizmo.hpp
+++ b/xs/src/slic3r/GUI/GLGizmo.hpp
@@ -12,7 +12,6 @@
 namespace Slic3r {
 
 class BoundingBoxf3;
-class Pointf3;
 class Linef3;
 
 namespace GUI {
@@ -25,7 +24,7 @@ protected:
         static const float HalfSize;
         static const float DraggingScaleFactor;
 
-        Pointf3 center;
+        Vec3d center;
         float angle_x;
         float angle_y;
         float angle_z;
@@ -142,7 +141,7 @@ private:
     Axis m_axis;
     float m_angle;
 
-    mutable Pointf3 m_center;
+    mutable Vec3d m_center;
     mutable float m_radius;
     mutable bool m_keep_initial_values;
 
@@ -169,7 +168,8 @@ private:
     void render_grabber() const;
 
     void transform_to_local() const;
-    Pointf mouse_position_in_local_plane(const Linef3& mouse_ray) const;
+    // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate
+    Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray) const;
 };
 
 class GLGizmoRotate3D : public GLGizmoBase
@@ -234,7 +234,7 @@ class GLGizmoScale : public GLGizmoBase
     float m_scale;
     float m_starting_scale;
 
-    Pointf m_starting_drag_position;
+    Vec2d m_starting_drag_position;
 
 public:
     GLGizmoScale();
@@ -264,8 +264,8 @@ class GLGizmoScale3D : public GLGizmoBase
     float m_starting_scale_y;
     float m_starting_scale_z;
 
-    Pointf3 m_starting_drag_position;
-    Pointf3 m_starting_center;
+    Vec3d m_starting_drag_position;
+    Vec3d m_starting_center;
 
 public:
     GLGizmoScale3D();
@@ -302,7 +302,7 @@ private:
     void do_scale_z(const Linef3& mouse_ray);
     void do_scale_uniform(const Linef3& mouse_ray);
 
-    double calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Pointf3& center) const;
+    double calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Vec3d& center) const;
 };
 
 } // namespace GUI
diff --git a/xs/src/slic3r/GUI/GLToolbar.cpp b/xs/src/slic3r/GUI/GLToolbar.cpp
index fd993f5a2..e82369db4 100644
--- a/xs/src/slic3r/GUI/GLToolbar.cpp
+++ b/xs/src/slic3r/GUI/GLToolbar.cpp
@@ -1,5 +1,7 @@
+#include "../../libslic3r/point.hpp"
 #include "GLToolbar.hpp"
 
+#include "../../libslic3r/libslic3r.h"
 #include "../../slic3r/GUI/GLCanvas3D.hpp"
 
 #include <GL/glew.h>
@@ -267,7 +269,7 @@ bool GLToolbar::is_item_pressed(const std::string& name) const
     return false;
 }
 
-void GLToolbar::update_hover_state(const Pointf& mouse_pos)
+void GLToolbar::update_hover_state(const Vec2d& mouse_pos)
 {
     if (!m_enabled)
         return;
@@ -288,7 +290,7 @@ void GLToolbar::update_hover_state(const Pointf& mouse_pos)
     }
 }
 
-int GLToolbar::contains_mouse(const Pointf& mouse_pos) const
+int GLToolbar::contains_mouse(const Vec2d& mouse_pos) const
 {
     if (!m_enabled)
         return -1;
@@ -342,7 +344,6 @@ void GLToolbar::do_action(unsigned int item_id)
 }
 
 void GLToolbar::render() const
-//void GLToolbar::render(const Pointf& mouse_pos) const
 {
     if (!m_enabled || m_items.empty())
         return;
@@ -407,13 +408,13 @@ float GLToolbar::_get_main_size() const
     return size;
 }
 
-void GLToolbar::_update_hover_state_horizontal(const Pointf& mouse_pos)
+void GLToolbar::_update_hover_state_horizontal(const Vec2d& mouse_pos)
 {
     float zoom = m_parent.get_camera_zoom();
     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
 
     Size cnv_size = m_parent.get_canvas_size();
-    Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom);
+    Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
 
     float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
     float scaled_separator_size = m_layout.separator_size * inv_zoom;
@@ -437,7 +438,7 @@ void GLToolbar::_update_hover_state_horizontal(const Pointf& mouse_pos)
             float bottom = top - scaled_icons_size;
 
             GLToolbarItem::EState state = item->get_state();
-            bool inside = (left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top);
+            bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top);
 
             switch (state)
             {
@@ -487,13 +488,13 @@ void GLToolbar::_update_hover_state_horizontal(const Pointf& mouse_pos)
     m_parent.set_tooltip(tooltip);
 }
 
-void GLToolbar::_update_hover_state_vertical(const Pointf& mouse_pos)
+void GLToolbar::_update_hover_state_vertical(const Vec2d& mouse_pos)
 {
     float zoom = m_parent.get_camera_zoom();
     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
 
     Size cnv_size = m_parent.get_canvas_size();
-    Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom);
+    Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
 
     float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
     float scaled_separator_size = m_layout.separator_size * inv_zoom;
@@ -517,7 +518,7 @@ void GLToolbar::_update_hover_state_vertical(const Pointf& mouse_pos)
             float bottom = top - scaled_icons_size;
 
             GLToolbarItem::EState state = item->get_state();
-            bool inside = (left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top);
+            bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top);
 
             switch (state)
             {
@@ -567,13 +568,13 @@ void GLToolbar::_update_hover_state_vertical(const Pointf& mouse_pos)
     m_parent.set_tooltip(tooltip);
 }
 
-int GLToolbar::_contains_mouse_horizontal(const Pointf& mouse_pos) const
+int GLToolbar::_contains_mouse_horizontal(const Vec2d& mouse_pos) const
 {
     float zoom = m_parent.get_camera_zoom();
     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
 
     Size cnv_size = m_parent.get_canvas_size();
-    Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom);
+    Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
 
     float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
     float scaled_separator_size = m_layout.separator_size * inv_zoom;
@@ -598,7 +599,7 @@ int GLToolbar::_contains_mouse_horizontal(const Pointf& mouse_pos) const
             float right = left + scaled_icons_size;
             float bottom = top - scaled_icons_size;
             
-            if ((left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top))
+            if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top))
                 return id;
             
             left += icon_stride;
@@ -608,13 +609,13 @@ int GLToolbar::_contains_mouse_horizontal(const Pointf& mouse_pos) const
     return -1;
 }
 
-int GLToolbar::_contains_mouse_vertical(const Pointf& mouse_pos) const
+int GLToolbar::_contains_mouse_vertical(const Vec2d& mouse_pos) const
 {
     float zoom = m_parent.get_camera_zoom();
     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
 
     Size cnv_size = m_parent.get_canvas_size();
-    Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom);
+    Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
 
     float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom;
     float scaled_separator_size = m_layout.separator_size * inv_zoom;
@@ -639,7 +640,7 @@ int GLToolbar::_contains_mouse_vertical(const Pointf& mouse_pos) const
             float right = left + scaled_icons_size;
             float bottom = top - scaled_icons_size;
 
-            if ((left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top))
+            if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top))
                 return id;
 
             top -= icon_stride;
diff --git a/xs/src/slic3r/GUI/GLToolbar.hpp b/xs/src/slic3r/GUI/GLToolbar.hpp
index b6eb6b19c..18d3f130d 100644
--- a/xs/src/slic3r/GUI/GLToolbar.hpp
+++ b/xs/src/slic3r/GUI/GLToolbar.hpp
@@ -8,9 +8,6 @@
 #include <vector>
 
 namespace Slic3r {
-
-class Pointf;
-
 namespace GUI {
 
 class GLCanvas3D;
@@ -148,10 +145,10 @@ public:
 
     bool is_item_pressed(const std::string& name) const;
 
-    void update_hover_state(const Pointf& mouse_pos);
+    void update_hover_state(const Vec2d& mouse_pos);
 
     // returns the id of the item under the given mouse position or -1 if none
-    int contains_mouse(const Pointf& mouse_pos) const;
+    int contains_mouse(const Vec2d& mouse_pos) const;
 
     void do_action(unsigned int item_id);
 
@@ -163,10 +160,11 @@ private:
     float _get_height_horizontal() const;
     float _get_height_vertical() const;
     float _get_main_size() const;
-    void _update_hover_state_horizontal(const Pointf& mouse_pos);
-    void _update_hover_state_vertical(const Pointf& mouse_pos);
-    int _contains_mouse_horizontal(const Pointf& mouse_pos) const;
-    int _contains_mouse_vertical(const Pointf& mouse_pos) const;
+    void _update_hover_state_horizontal(const Vec2d& mouse_pos);
+    void _update_hover_state_vertical(const Vec2d& mouse_pos);
+    int _contains_mouse_horizontal(const Vec2d& mouse_pos) const;
+    int _contains_mouse_vertical(const Vec2d& mouse_pos) const;
+
     void _render_horizontal() const;
     void _render_vertical() const;
 };
diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index 8555f0b92..18f63f65e 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -610,10 +610,10 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
 			break;
 		case coPoints:{
 			if (opt_key.compare("bed_shape") == 0){
-				config.option<ConfigOptionPoints>(opt_key)->values = boost::any_cast<std::vector<Pointf>>(value);
+				config.option<ConfigOptionPoints>(opt_key)->values = boost::any_cast<std::vector<Vec2d>>(value);
 				break;
 			}
-			ConfigOptionPoints* vec_new = new ConfigOptionPoints{ boost::any_cast<Pointf>(value) };
+			ConfigOptionPoints* vec_new = new ConfigOptionPoints{ boost::any_cast<Vec2d>(value) };
 			config.option<ConfigOptionPoints>(opt_key)->set_at(vec_new, opt_index, 0);
 			}
 			break;
@@ -895,10 +895,10 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
 			g_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e)
 			{
 				auto &config = g_PresetBundle->project_config;
-                std::vector<double> init_matrix = (config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values;
-                std::vector<double> init_extruders = (config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values;
+                const std::vector<double> &init_matrix    = (config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values;
+                const std::vector<double> &init_extruders = (config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values;
 
-                WipingDialog dlg(parent,std::vector<float>(init_matrix.begin(),init_matrix.end()),std::vector<float>(init_extruders.begin(),init_extruders.end()));
+                WipingDialog dlg(parent,cast<float>(init_matrix),cast<float>(init_extruders));
 
 				if (dlg.ShowModal() == wxID_OK) {
                     std::vector<float> matrix = dlg.get_matrix();
diff --git a/xs/src/slic3r/GUI/RammingChart.cpp b/xs/src/slic3r/GUI/RammingChart.cpp
index 2603a5eab..8954ff93b 100644
--- a/xs/src/slic3r/GUI/RammingChart.cpp
+++ b/xs/src/slic3r/GUI/RammingChart.cpp
@@ -261,7 +261,7 @@ std::vector<float> Chart::get_ramming_speed(float sampling) const {
 std::vector<std::pair<float,float>> Chart::get_buttons() const {
     std::vector<std::pair<float, float>> buttons_out;
     for (const auto& button : m_buttons)
-        buttons_out.push_back(std::make_pair(button.get_pos().m_x,button.get_pos().m_y));            
+        buttons_out.push_back(std::make_pair(float(button.get_pos().m_x),float(button.get_pos().m_y)));
     return buttons_out;
 }
     
diff --git a/xs/src/xsinit.h b/xs/src/xsinit.h
index 9365f1979..c9e363602 100644
--- a/xs/src/xsinit.h
+++ b/xs/src/xsinit.h
@@ -68,7 +68,16 @@ extern "C" {
     #undef fputc
     #undef fwrite
     #undef fclose
+
+	// Breaks compilation with Eigen matrices embedded into Slic3r::Point.
+	#undef malloc
+	#undef realloc
+	#undef free
+	#undef select
 #endif /* _MSC_VER */
+#undef Zero
+#undef Packet
+#undef _
 }
 #endif
 
@@ -188,9 +197,9 @@ void from_SV_check(SV* poly_sv, Polyline* THIS);
 SV* to_SV_pureperl(const Point* THIS);
 void from_SV(SV* point_sv, Point* point);
 void from_SV_check(SV* point_sv, Point* point);
-SV* to_SV_pureperl(const Pointf* point);
-bool from_SV(SV* point_sv, Pointf* point);
-bool from_SV_check(SV* point_sv, Pointf* point);
+SV* to_SV_pureperl(const Vec2d* point);
+bool from_SV(SV* point_sv, Vec2d* point);
+bool from_SV_check(SV* point_sv, Vec2d* point);
 void from_SV_check(SV* surface_sv, Surface* THIS);
 SV* to_SV(TriangleMesh* THIS);
 
diff --git a/xs/xsp/BoundingBox.xsp b/xs/xsp/BoundingBox.xsp
index ebeb17822..a34cad0bc 100644
--- a/xs/xsp/BoundingBox.xsp
+++ b/xs/xsp/BoundingBox.xsp
@@ -25,15 +25,15 @@
     double radius();
     Clone<Point> min_point() %code{% RETVAL = THIS->min; %};
     Clone<Point> max_point() %code{% RETVAL = THIS->max; %};
-    int x_min() %code{% RETVAL = THIS->min.x; %};
-    int x_max() %code{% RETVAL = THIS->max.x; %};
-    int y_min() %code{% RETVAL = THIS->min.y; %};
-    int y_max() %code{% RETVAL = THIS->max.y; %};
-    void set_x_min(double val) %code{% THIS->min.x = val; %};
-    void set_x_max(double val) %code{% THIS->max.x = val; %};
-    void set_y_min(double val) %code{% THIS->min.y = val; %};
-    void set_y_max(double val) %code{% THIS->max.y = val; %};
-    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%ld,%ld;%ld,%ld", THIS->min.x, THIS->min.y, THIS->max.x, THIS->max.y); RETVAL = buf; %};
+    int x_min() %code{% RETVAL = THIS->min(0); %};
+    int x_max() %code{% RETVAL = THIS->max(0); %};
+    int y_min() %code{% RETVAL = THIS->min(1); %};
+    int y_max() %code{% RETVAL = THIS->max(1); %};
+    void set_x_min(double val) %code{% THIS->min(0) = val; %};
+    void set_x_max(double val) %code{% THIS->max(0) = val; %};
+    void set_y_min(double val) %code{% THIS->min(1) = val; %};
+    void set_y_max(double val) %code{% THIS->max(1) = val; %};
+    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%ld,%ld;%ld,%ld", THIS->min(0), THIS->min(1), THIS->max(0), THIS->max(1)); RETVAL = buf; %};
     bool defined() %code{% RETVAL = THIS->defined; %};
 
 %{
@@ -56,24 +56,24 @@ new_from_points(CLASS, points)
     Clone<BoundingBoxf> clone()
         %code{% RETVAL = THIS; %};
     void merge(BoundingBoxf* bb) %code{% THIS->merge(*bb); %};
-    void merge_point(Pointf* point) %code{% THIS->merge(*point); %};
+    void merge_point(Vec2d* point) %code{% THIS->merge(*point); %};
     void scale(double factor);
     void translate(double x, double y);
-    Clone<Pointf> size();
-    Clone<Pointf> center();
+    Clone<Vec2d> size();
+    Clone<Vec2d> center();
     double radius();
     bool empty() %code{% RETVAL = empty(*THIS); %};
-    Clone<Pointf> min_point() %code{% RETVAL = THIS->min; %};
-    Clone<Pointf> max_point() %code{% RETVAL = THIS->max; %};
-    double x_min() %code{% RETVAL = THIS->min.x; %};
-    double x_max() %code{% RETVAL = THIS->max.x; %};
-    double y_min() %code{% RETVAL = THIS->min.y; %};
-    double y_max() %code{% RETVAL = THIS->max.y; %};
-    void set_x_min(double val) %code{% THIS->min.x = val; %};
-    void set_x_max(double val) %code{% THIS->max.x = val; %};
-    void set_y_min(double val) %code{% THIS->min.y = val; %};
-    void set_y_max(double val) %code{% THIS->max.y = val; %};
-    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf;%lf,%lf", THIS->min.x, THIS->min.y, THIS->max.x, THIS->max.y); RETVAL = buf; %};
+    Clone<Vec2d> min_point() %code{% RETVAL = THIS->min; %};
+    Clone<Vec2d> max_point() %code{% RETVAL = THIS->max; %};
+    double x_min() %code{% RETVAL = THIS->min(0); %};
+    double x_max() %code{% RETVAL = THIS->max(0); %};
+    double y_min() %code{% RETVAL = THIS->min(1); %};
+    double y_max() %code{% RETVAL = THIS->max(1); %};
+    void set_x_min(double val) %code{% THIS->min(0) = val; %};
+    void set_x_max(double val) %code{% THIS->max(0) = val; %};
+    void set_y_min(double val) %code{% THIS->min(1) = val; %};
+    void set_y_max(double val) %code{% THIS->max(1) = val; %};
+    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf;%lf,%lf", THIS->min(0), THIS->min(1), THIS->max(0), THIS->max(1)); RETVAL = buf; %};
     bool defined() %code{% RETVAL = THIS->defined; %};
     
 %{
@@ -96,23 +96,23 @@ new_from_points(CLASS, points)
     Clone<BoundingBoxf3> clone()
         %code{% RETVAL = THIS; %};
     void merge(BoundingBoxf3* bb) %code{% THIS->merge(*bb); %};
-    void merge_point(Pointf3* point) %code{% THIS->merge(*point); %};
+    void merge_point(Vec3d* point) %code{% THIS->merge(*point); %};
     void scale(double factor);
     void translate(double x, double y, double z);
     void offset(double delta);
-    bool contains_point(Pointf3* point) %code{% RETVAL = THIS->contains(*point); %};
-    Clone<Pointf3> size();
-    Clone<Pointf3> center();
+    bool contains_point(Vec3d* point) %code{% RETVAL = THIS->contains(*point); %};
+    Clone<Vec3d> size();
+    Clone<Vec3d> center();
     double radius();
     bool empty() %code{% RETVAL = empty(*THIS); %};
-    Clone<Pointf3> min_point() %code{% RETVAL = THIS->min; %};
-    Clone<Pointf3> max_point() %code{% RETVAL = THIS->max; %};
-    double x_min() %code{% RETVAL = THIS->min.x; %};
-    double x_max() %code{% RETVAL = THIS->max.x; %};
-    double y_min() %code{% RETVAL = THIS->min.y; %};
-    double y_max() %code{% RETVAL = THIS->max.y; %};
-    double z_min() %code{% RETVAL = THIS->min.z; %};
-    double z_max() %code{% RETVAL = THIS->max.z; %};
-    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf,%lf;%lf,%lf,%lf", THIS->min.x, THIS->min.y, THIS->min.z, THIS->max.x, THIS->max.y, THIS->max.z); RETVAL = buf; %};
+    Clone<Vec3d> min_point() %code{% RETVAL = THIS->min; %};
+    Clone<Vec3d> max_point() %code{% RETVAL = THIS->max; %};
+    double x_min() %code{% RETVAL = THIS->min(0); %};
+    double x_max() %code{% RETVAL = THIS->max(0); %};
+    double y_min() %code{% RETVAL = THIS->min(1); %};
+    double y_max() %code{% RETVAL = THIS->max(1); %};
+    double z_min() %code{% RETVAL = THIS->min(2); %};
+    double z_max() %code{% RETVAL = THIS->max(2); %};
+    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf,%lf;%lf,%lf,%lf", THIS->min(0), THIS->min(1), THIS->min(2), THIS->max(0), THIS->max(1), THIS->max(2)); RETVAL = buf; %};
     bool defined() %code{% RETVAL = THIS->defined; %};
 };
diff --git a/xs/xsp/GCode.xsp b/xs/xsp/GCode.xsp
index c1856ccf7..9e04edd4c 100644
--- a/xs/xsp/GCode.xsp
+++ b/xs/xsp/GCode.xsp
@@ -35,9 +35,9 @@
             }
         %};
 
-    Ref<Pointf> origin()
+    Ref<Vec2d> origin()
         %code{% RETVAL = &(THIS->origin()); %};
-    void set_origin(Pointf* pointf)
+    void set_origin(Vec2d* pointf)
         %code{% THIS->set_origin(*pointf); %};
     Ref<Point> last_pos()
         %code{% RETVAL = &(THIS->last_pos()); %};
diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp
index 515675a31..5f1b55cf3 100644
--- a/xs/xsp/GUI_3DScene.xsp
+++ b/xs/xsp/GUI_3DScene.xsp
@@ -55,14 +55,10 @@
     int                 object_idx() const;
     int                 volume_idx() const;
     int                 instance_idx() const;
-    Clone<Pointf3>      origin() const
+    Clone<Vec3d>        origin() const
         %code%{ RETVAL = THIS->get_origin(); %};
     void                translate(double x, double y, double z)
-        %code%{
-                Pointf3 o = THIS->get_origin();
-                o.translate(x, y, z);
-                THIS->set_origin(o);
-             %};
+        %code%{ THIS->set_origin(THIS->get_origin() + Vec3d(x, y, z)); %};
     Clone<BoundingBoxf3> bounding_box() const
         %code%{ RETVAL = THIS->bounding_box; %};
 
diff --git a/xs/xsp/Geometry.xsp b/xs/xsp/Geometry.xsp
index b23bbeffa..b7e92ba69 100644
--- a/xs/xsp/Geometry.xsp
+++ b/xs/xsp/Geometry.xsp
@@ -8,7 +8,7 @@
 
 %package{Slic3r::Geometry};
 
-Pointfs arrange(size_t total_parts, Pointf* part, coordf_t dist, BoundingBoxf* bb = NULL)
+Pointfs arrange(size_t total_parts, Vec2d* part, coordf_t dist, BoundingBoxf* bb = NULL)
     %code{% 
         Pointfs points;
         if (! Slic3r::Geometry::arrange(total_parts, *part, dist, bb, points))
diff --git a/xs/xsp/Line.xsp b/xs/xsp/Line.xsp
index 92429e57a..777dc41fa 100644
--- a/xs/xsp/Line.xsp
+++ b/xs/xsp/Line.xsp
@@ -29,7 +29,6 @@
     bool parallel_to_line(Line* line)
         %code{% RETVAL = THIS->parallel_to(*line); %};
     Clone<Point> midpoint();
-    Clone<Point> point_at(double distance);
     Clone<Point> intersection_infinite(Line* other)
         %code{%
             Point p;
@@ -37,8 +36,8 @@
             if (!res) CONFESS("Intersection failed");
             RETVAL = p;
         %};
-    Clone<Polyline> as_polyline()
-        %code{% RETVAL = Polyline(*THIS); %};
+    Polyline* as_polyline()
+        %code{% RETVAL = new Polyline(THIS->a, THIS->b); %};
     Clone<Point> normal();
     Clone<Point> vector();
     double ccw(Point* point)
@@ -70,7 +69,7 @@ Line::coincides_with(line_sv)
     CODE:
         Line line;
         from_SV_check(line_sv, &line);
-        RETVAL = THIS->coincides_with(line);
+        RETVAL = (*THIS) == line;
     OUTPUT:
         RETVAL
 
@@ -79,15 +78,15 @@ Line::coincides_with(line_sv)
 
 
 %name{Slic3r::Linef3} class Linef3 {
-    Linef3(Pointf3* a, Pointf3* b)
+    Linef3(Vec3d* a, Vec3d* b)
         %code{% RETVAL = new Linef3(*a, *b); %};
     ~Linef3();
     Clone<Linef3> clone()
         %code{% RETVAL = THIS; %};
-    Ref<Pointf3> a()
+    Ref<Vec3d> a()
         %code{% RETVAL = &THIS->a; %};
-    Ref<Pointf3> b()
+    Ref<Vec3d> b()
         %code{% RETVAL = &THIS->b; %};
-    Clone<Pointf3> intersect_plane(double z);
+    Clone<Vec3d> intersect_plane(double z);
     void scale(double factor);
 };
diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp
index 25c26c380..ac265a3b3 100644
--- a/xs/xsp/Model.xsp
+++ b/xs/xsp/Model.xsp
@@ -81,7 +81,7 @@
 
     bool add_default_instances();
     Clone<BoundingBoxf3> bounding_box();
-    void center_instances_around_point(Pointf* point)
+    void center_instances_around_point(Vec2d* point)
         %code%{ THIS->center_instances_around_point(*point); %};
     void translate(double x, double y, double z);
     Clone<TriangleMesh> mesh();
@@ -289,9 +289,9 @@ ModelMaterial::attributes()
     void set_layer_height_profile(std::vector<double> profile)
         %code%{ THIS->layer_height_profile = profile; THIS->layer_height_profile_valid = true; %};
 
-    Ref<Pointf3> origin_translation()
+    Ref<Vec3d> origin_translation()
         %code%{ RETVAL = &THIS->origin_translation; %};
-    void set_origin_translation(Pointf3* point)
+    void set_origin_translation(Vec3d* point)
         %code%{ THIS->origin_translation = *point; %};
     
     bool needed_repair() const;
@@ -299,7 +299,7 @@ ModelMaterial::attributes()
     int facets_count();
     void center_around_origin();
     void translate(double x, double y, double z);
-    void scale_xyz(Pointf3* versor)
+    void scale_xyz(Vec3d* versor)
         %code{% THIS->scale(*versor); %};
     void rotate(float angle, Axis axis);
     void mirror(Axis axis);
@@ -357,14 +357,14 @@ ModelMaterial::attributes()
         %code%{ RETVAL = THIS->rotation; %};
     double scaling_factor()
         %code%{ RETVAL = THIS->scaling_factor; %};
-    Ref<Pointf> offset()
+    Ref<Vec2d> offset()
         %code%{ RETVAL = &THIS->offset; %};
 
     void set_rotation(double val)
         %code%{ THIS->rotation = val; THIS->get_object()->invalidate_bounding_box(); %};
     void set_scaling_factor(double val)
         %code%{ THIS->scaling_factor = val; THIS->get_object()->invalidate_bounding_box(); %};
-    void set_offset(Pointf *offset)
+    void set_offset(Vec2d *offset)
         %code%{ THIS->offset = *offset; %};
     
     void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const;
diff --git a/xs/xsp/Point.xsp b/xs/xsp/Point.xsp
index b7aded6a0..beefc6249 100644
--- a/xs/xsp/Point.xsp
+++ b/xs/xsp/Point.xsp
@@ -3,6 +3,7 @@
 %{
 #include <xsinit.h>
 #include "libslic3r/Point.hpp"
+#include "libslic3r/Line.hpp"
 #include "libslic3r/Polygon.hpp"
 #include "libslic3r/Polyline.hpp"
 %}
@@ -12,44 +13,44 @@
     ~Point();
     Clone<Point> clone()
         %code{% RETVAL=THIS; %}; 
-    void scale(double factor);
-    void translate(double x, double y);
+    void scale(double factor)
+        %code{% *THIS *= factor; %};
+    void translate(double x, double y)
+        %code{% *THIS += Point(x, y); %};
     SV* arrayref()
         %code{% RETVAL = to_SV_pureperl(THIS); %};
     SV* pp()
         %code{% RETVAL = to_SV_pureperl(THIS); %};
     int x()
-        %code{% RETVAL = THIS->x; %};
+        %code{% RETVAL = (*THIS)(0); %};
     int y()
-        %code{% RETVAL = THIS->y; %};
+        %code{% RETVAL = (*THIS)(1); %};
     void set_x(int val)
-        %code{% THIS->x = val; %};
+        %code{% (*THIS)(0) = val; %};
     void set_y(int val)
-        %code{% THIS->y = val; %};
+        %code{% (*THIS)(1) = val; %};
     int nearest_point_index(Points points);
     Clone<Point> nearest_point(Points points)
         %code{% Point p; THIS->nearest_point(points, &p); RETVAL = p; %};
     double distance_to(Point* point)
-        %code{% RETVAL = THIS->distance_to(*point); %};
+        %code{% RETVAL = (*point - *THIS).cast<double>().norm(); %};
     double distance_to_line(Line* line)
-        %code{% RETVAL = THIS->distance_to(*line); %};
+        %code{% RETVAL = line->distance_to(*THIS); %};
     double perp_distance_to_line(Line* line)
-        %code{% RETVAL = THIS->perp_distance_to(*line); %};
+        %code{% RETVAL = line->perp_distance_to(*THIS); %};
     double ccw(Point* p1, Point* p2)
         %code{% RETVAL = THIS->ccw(*p1, *p2); %};
     double ccw_angle(Point* p1, Point* p2)
         %code{% RETVAL = THIS->ccw_angle(*p1, *p2); %};
-    Clone<Point> projection_onto_polygon(Polygon* polygon)
+    Point* projection_onto_polygon(Polygon* polygon)
         %code{% RETVAL = new Point(THIS->projection_onto(*polygon)); %};
-    Clone<Point> projection_onto_polyline(Polyline* polyline)
+    Point* projection_onto_polyline(Polyline* polyline)
         %code{% RETVAL = new Point(THIS->projection_onto(*polyline)); %};
-    Clone<Point> projection_onto_line(Line* line)
+    Point* projection_onto_line(Line* line)
         %code{% RETVAL = new Point(THIS->projection_onto(*line)); %};
-    Clone<Point> negative()
-        %code{% RETVAL = new Point(THIS->negative()); %};
-    bool coincides_with_epsilon(Point* point)
-        %code{% RETVAL = THIS->coincides_with_epsilon(*point); %};
-    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%ld,%ld", THIS->x, THIS->y); RETVAL = buf; %};
+    Point* negative()
+        %code{% RETVAL = new Point(- *THIS); %};
+    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%ld,%ld", (*THIS)(0), (*THIS)(1)); RETVAL = buf; %};
 
 %{
 
@@ -68,7 +69,7 @@ Point::coincides_with(point_sv)
     CODE:
         Point point;
         from_SV_check(point_sv, &point);
-        RETVAL = THIS->coincides_with(point);
+        RETVAL = (*THIS) == point;
     OUTPUT:
         RETVAL
 
@@ -76,72 +77,62 @@ Point::coincides_with(point_sv)
 
 };
 
-%name{Slic3r::Point3} class Point3 {
-    Point3(int _x = 0, int _y = 0, int _z = 0);
-    ~Point3();
-    Clone<Point3> clone()
-        %code{% RETVAL = THIS; %};
-    int x()
-        %code{% RETVAL = THIS->x; %};
-    int y()
-        %code{% RETVAL = THIS->y; %};
-    int z()
-        %code{% RETVAL = THIS->z; %};
-    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%ld,%ld,%ld", THIS->x, THIS->y, THIS->z); RETVAL = buf; %};
-};
-
-%name{Slic3r::Pointf} class Pointf {
-    Pointf(double _x = 0, double _y = 0);
-    ~Pointf();
-    Clone<Pointf> clone()
+%name{Slic3r::Pointf} class Vec2d {
+    Vec2d(double _x = 0, double _y = 0);
+    ~Vec2d();
+    Clone<Vec2d> clone()
         %code{% RETVAL = THIS; %};
     SV* arrayref()
         %code{% RETVAL = to_SV_pureperl(THIS); %};
     SV* pp()
         %code{% RETVAL = to_SV_pureperl(THIS); %};
     double x()
-        %code{% RETVAL = THIS->x; %};
+        %code{% RETVAL = (*THIS)(0); %};
     double y()
-        %code{% RETVAL = THIS->y; %};
+        %code{% RETVAL = (*THIS)(1); %};
     void set_x(double val)
-        %code{% THIS->x = val; %};
+        %code{% (*THIS)(0) = val; %};
     void set_y(double val)
-        %code{% THIS->y = val; %};
-    void translate(double x, double y);
-    void scale(double factor);
-    void rotate(double angle, Pointf* center)
-        %code{% THIS->rotate(angle, *center); %};
-    Clone<Pointf> negative()
-        %code{% RETVAL = THIS->negative(); %};
-    Clone<Pointf> vector_to(Pointf* point)
-        %code{% RETVAL = THIS->vector_to(*point); %};
-    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf", THIS->x, THIS->y); RETVAL = buf; %};
+        %code{% (*THIS)(1) = val; %};
+    void translate(double x, double y)
+        %code{% *THIS += Vec2d(x, y); %};
+    void scale(double factor)
+        %code{% *THIS *= factor; %};
+    void rotate(double angle, Vec2d* center)
+        %code{% *THIS = Eigen::Translation2d(*center) * Eigen::Rotation2Dd(angle) * Eigen::Translation2d(- *center) * Eigen::Vector2d((*THIS)(0), (*THIS)(1)); %};
+    Vec2d* negative()
+        %code{% RETVAL = new Vec2d(- *THIS); %};
+    Vec2d* vector_to(Vec2d* point)
+        %code{% RETVAL = new Vec2d(*point - *THIS); %};
+    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf", (*THIS)(0), (*THIS)(1)); RETVAL = buf; %};
 };
 
-%name{Slic3r::Pointf3} class Pointf3 {
-    Pointf3(double _x = 0, double _y = 0, double _z = 0);
-    ~Pointf3();
-    Clone<Pointf3> clone()
+%name{Slic3r::Pointf3} class Vec3d {
+    Vec3d(double _x = 0, double _y = 0, double _z = 0);
+    ~Vec3d();
+    Clone<Vec3d> clone()
         %code{% RETVAL = THIS; %};
     double x()
-        %code{% RETVAL = THIS->x; %};
+        %code{% RETVAL = (*THIS)(0); %};
     double y()
-        %code{% RETVAL = THIS->y; %};
+        %code{% RETVAL = (*THIS)(1); %};
     double z()
-        %code{% RETVAL = THIS->z; %};
+        %code{% RETVAL = (*THIS)(2); %};
     void set_x(double val)
-        %code{% THIS->x = val; %};
+        %code{% (*THIS)(0) = val; %};
     void set_y(double val)
-        %code{% THIS->y = val; %};
+        %code{% (*THIS)(1) = val; %};
     void set_z(double val)
-        %code{% THIS->z = val; %};
-    void translate(double x, double y, double z);
-    void scale(double factor);
-    double distance_to(Pointf3* point)
-        %code{% RETVAL = THIS->distance_to(*point); %};
-    Clone<Pointf3> negative()
-        %code{% RETVAL = THIS->negative(); %};
-    Clone<Pointf3> vector_to(Pointf3* point)
-        %code{% RETVAL = THIS->vector_to(*point); %};
-    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf,%lf", THIS->x, THIS->y, THIS->z); RETVAL = buf; %};
+        %code{% (*THIS)(2) = val; %};
+    void translate(double x, double y, double z)
+        %code{% *THIS += Vec3d(x, y, z); %};
+    void scale(double factor)
+        %code{% *THIS *= factor; %};
+    double distance_to(Vec3d* point)
+        %code{% RETVAL = (*point - *THIS).norm(); %};
+    Vec3d* negative()
+        %code{% RETVAL = new Vec3d(- *THIS); %};
+    Vec3d* vector_to(Vec3d* point)
+        %code{% RETVAL = new Vec3d(*point - *THIS); %};
+    std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf,%lf", (*THIS)(0), (*THIS)(1), (*THIS)(2)); RETVAL = buf; %};
 };
diff --git a/xs/xsp/Polygon.xsp b/xs/xsp/Polygon.xsp
index f5db9f515..a94425477 100644
--- a/xs/xsp/Polygon.xsp
+++ b/xs/xsp/Polygon.xsp
@@ -39,7 +39,6 @@
         %code{% THIS->triangulate_convex(&RETVAL); %};
     Clone<Point> centroid();
     Clone<BoundingBox> bounding_box();
-    std::string wkt();
     Points concave_points(double angle);
     Points convex_points(double angle);
     Clone<Point> point_projection(Point* point)
diff --git a/xs/xsp/Polyline.xsp b/xs/xsp/Polyline.xsp
index 60d7c6aca..0dbd0e572 100644
--- a/xs/xsp/Polyline.xsp
+++ b/xs/xsp/Polyline.xsp
@@ -38,7 +38,6 @@
     bool is_straight();
     Clone<BoundingBox> bounding_box();
     void remove_duplicate_points();
-    std::string wkt();
 %{
 
 Polyline*
diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp
index 717064916..ee9779f68 100644
--- a/xs/xsp/Print.xsp
+++ b/xs/xsp/Print.xsp
@@ -63,8 +63,6 @@ _constant()
         %code%{ RETVAL = THIS->layer_height_ranges; %};
     std::vector<double> layer_height_profile()
         %code%{ RETVAL = THIS->layer_height_profile; %};
-    Ref<Point3> size()
-        %code%{ RETVAL = &THIS->size; %};
     Clone<BoundingBox> bounding_box();
     
     Points _shifted_copies()
@@ -72,7 +70,7 @@ _constant()
     void set_shifted_copies(Points value)
         %code%{ THIS->_shifted_copies = value; %};
 
-    bool add_copy(Pointf* point)
+    bool add_copy(Vec2d* point)
         %code%{ RETVAL = THIS->add_copy(*point); %};
     bool delete_last_copy();
     bool delete_all_copies();
@@ -176,15 +174,6 @@ _constant()
     void set_step_started(PrintStep step)
         %code%{ THIS->state.set_started(step); %};
     
-    void clear_filament_stats()
-        %code%{
-            THIS->filament_stats.clear();
-        %};
-    void set_filament_stats(int extruder_id, float length)
-        %code%{
-            THIS->filament_stats.insert(std::pair<size_t,float>(extruder_id, 0));
-            THIS->filament_stats[extruder_id] += length;
-        %};
     SV* filament_stats()
         %code%{
             HV* hv = newHV();
diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp
index d4578303b..2bc20da3a 100644
--- a/xs/xsp/TriangleMesh.xsp
+++ b/xs/xsp/TriangleMesh.xsp
@@ -16,7 +16,7 @@
     void repair();
     void WriteOBJFile(char* output_file);
     void scale(float factor);
-    void scale_xyz(Pointf3* versor)
+    void scale_xyz(Vec3d* versor)
         %code{% THIS->scale(*versor); %};
     void translate(float x, float y, float z);
     void rotate_x(float angle);
@@ -33,7 +33,7 @@
     ExPolygons horizontal_projection();
     Clone<Polygon> convex_hull();
     Clone<BoundingBoxf3> bounding_box();
-    Clone<Pointf3> center()
+    Clone<Vec3d> center()
         %code{% RETVAL = THIS->bounding_box().center(); %};
     int facets_count();
     void reset_repair_stats();
@@ -60,14 +60,14 @@ TriangleMesh::ReadFromPerl(vertices, facets)
         for (int i = 0; i < stl.stats.number_of_facets; i++) {
             AV* facet_av = (AV*)SvRV(*av_fetch(facets_av, i, 0));
             stl_facet facet;
-            facet.normal.x = 0;
-            facet.normal.y = 0;
-            facet.normal.z = 0;
+            facet.normal(0) = 0;
+            facet.normal(1) = 0;
+            facet.normal(2) = 0;
             for (unsigned int v = 0; v <= 2; v++) {
                 AV* vertex_av = (AV*)SvRV(*av_fetch(vertices_av, SvIV(*av_fetch(facet_av, v, 0)), 0));
-                facet.vertex[v].x = SvNV(*av_fetch(vertex_av, 0, 0));
-                facet.vertex[v].y = SvNV(*av_fetch(vertex_av, 1, 0));
-                facet.vertex[v].z = SvNV(*av_fetch(vertex_av, 2, 0));
+                facet.vertex[v](0) = SvNV(*av_fetch(vertex_av, 0, 0));
+                facet.vertex[v](1) = SvNV(*av_fetch(vertex_av, 1, 0));
+                facet.vertex[v](2) = SvNV(*av_fetch(vertex_av, 2, 0));
             }
             facet.extra[0] = 0;
             facet.extra[1] = 0;
@@ -110,9 +110,9 @@ TriangleMesh::vertices()
             AV* vertex = newAV();
             av_store(vertices, i, newRV_noinc((SV*)vertex));
             av_extend(vertex, 2);
-            av_store(vertex, 0, newSVnv(THIS->stl.v_shared[i].x));
-            av_store(vertex, 1, newSVnv(THIS->stl.v_shared[i].y));
-            av_store(vertex, 2, newSVnv(THIS->stl.v_shared[i].z));
+            av_store(vertex, 0, newSVnv(THIS->stl.v_shared[i](0)));
+            av_store(vertex, 1, newSVnv(THIS->stl.v_shared[i](1)));
+            av_store(vertex, 2, newSVnv(THIS->stl.v_shared[i](2)));
         }
         
         RETVAL = newRV_noinc((SV*)vertices);
@@ -155,9 +155,9 @@ TriangleMesh::normals()
             AV* facet = newAV();
             av_store(normals, i, newRV_noinc((SV*)facet));
             av_extend(facet, 2);
-            av_store(facet, 0, newSVnv(THIS->stl.facet_start[i].normal.x));
-            av_store(facet, 1, newSVnv(THIS->stl.facet_start[i].normal.y));
-            av_store(facet, 2, newSVnv(THIS->stl.facet_start[i].normal.z));
+            av_store(facet, 0, newSVnv(THIS->stl.facet_start[i].normal(0)));
+            av_store(facet, 1, newSVnv(THIS->stl.facet_start[i].normal(1)));
+            av_store(facet, 2, newSVnv(THIS->stl.facet_start[i].normal(2)));
         }
         
         RETVAL = newRV_noinc((SV*)normals);
@@ -169,9 +169,9 @@ TriangleMesh::size()
     CODE:
         AV* size = newAV();
         av_extend(size, 2);
-        av_store(size, 0, newSVnv(THIS->stl.stats.size.x));
-        av_store(size, 1, newSVnv(THIS->stl.stats.size.y));
-        av_store(size, 2, newSVnv(THIS->stl.stats.size.z));
+        av_store(size, 0, newSVnv(THIS->stl.stats.size(0)));
+        av_store(size, 1, newSVnv(THIS->stl.stats.size(1)));
+        av_store(size, 2, newSVnv(THIS->stl.stats.size(2)));
         RETVAL = newRV_noinc((SV*)size);
     OUTPUT:
         RETVAL
@@ -181,7 +181,7 @@ TriangleMesh::slice(z)
     std::vector<double> z
     CODE:
         // convert doubles to floats
-        std::vector<float> z_f(z.begin(), z.end());
+        std::vector<float> z_f = cast<float>(z);
         
         std::vector<ExPolygons> layers;
         TriangleMeshSlicer mslicer(THIS);
@@ -216,12 +216,12 @@ TriangleMesh::cut(z, upper, lower)
 std::vector<double>
 TriangleMesh::bb3()
     CODE:
-        RETVAL.push_back(THIS->stl.stats.min.x);
-        RETVAL.push_back(THIS->stl.stats.min.y);
-        RETVAL.push_back(THIS->stl.stats.max.x);
-        RETVAL.push_back(THIS->stl.stats.max.y);
-        RETVAL.push_back(THIS->stl.stats.min.z);
-        RETVAL.push_back(THIS->stl.stats.max.z);
+        RETVAL.push_back(THIS->stl.stats.min(0));
+        RETVAL.push_back(THIS->stl.stats.min(1));
+        RETVAL.push_back(THIS->stl.stats.max(0));
+        RETVAL.push_back(THIS->stl.stats.max(1));
+        RETVAL.push_back(THIS->stl.stats.min(2));
+        RETVAL.push_back(THIS->stl.stats.max(2));
     OUTPUT:
         RETVAL
 
diff --git a/xs/xsp/my.map b/xs/xsp/my.map
index ba20ee236..d85734086 100644
--- a/xs/xsp/my.map
+++ b/xs/xsp/my.map
@@ -66,13 +66,13 @@ Point3*                    O_OBJECT_SLIC3R
 Ref<Point3>                O_OBJECT_SLIC3R_T
 Clone<Point3>              O_OBJECT_SLIC3R_T
 
-Pointf*                    O_OBJECT_SLIC3R
-Ref<Pointf>                O_OBJECT_SLIC3R_T
-Clone<Pointf>              O_OBJECT_SLIC3R_T
+Vec2d*                     O_OBJECT_SLIC3R
+Ref<Vec2d>                 O_OBJECT_SLIC3R_T
+Clone<Vec2d>               O_OBJECT_SLIC3R_T
 
-Pointf3*                   O_OBJECT_SLIC3R
-Ref<Pointf3>               O_OBJECT_SLIC3R_T
-Clone<Pointf3>             O_OBJECT_SLIC3R_T
+Vec3d*                     O_OBJECT_SLIC3R
+Ref<Vec3d>                 O_OBJECT_SLIC3R_T
+Clone<Vec3d>               O_OBJECT_SLIC3R_T
 
 Line*                      O_OBJECT_SLIC3R
 Ref<Line>                  O_OBJECT_SLIC3R_T
diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt
index cee75fe26..b3d73b9b3 100644
--- a/xs/xsp/typemap.xspt
+++ b/xs/xsp/typemap.xspt
@@ -22,12 +22,12 @@
 %typemap{Point3*};
 %typemap{Ref<Point3>}{simple};
 %typemap{Clone<Point3>}{simple};
-%typemap{Pointf*};
-%typemap{Ref<Pointf>}{simple};
-%typemap{Clone<Pointf>}{simple};
-%typemap{Pointf3*};
-%typemap{Ref<Pointf3>}{simple};
-%typemap{Clone<Pointf3>}{simple};
+%typemap{Vec2d*};
+%typemap{Ref<Vec2d>}{simple};
+%typemap{Clone<Vec2d>}{simple};
+%typemap{Vec3d*};
+%typemap{Ref<Vec3d>}{simple};
+%typemap{Clone<Vec3d>}{simple};
 %typemap{BoundingBox*};
 %typemap{Ref<BoundingBox>}{simple};
 %typemap{Clone<BoundingBox>}{simple};