From e75dbf37fa8834e90f577a7e9b3df52134497b79 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Sat, 23 Nov 2013 19:25:33 +0100
Subject: [PATCH] Never scale TriangleMesh objects

---
 lib/Slic3r/Layer.pm        |  2 +-
 lib/Slic3r/Layer/Region.pm |  2 +-
 lib/Slic3r/Print.pm        |  9 +++++----
 lib/Slic3r/Print/Object.pm |  2 +-
 xs/src/TriangleMesh.cpp    | 31 +++++++++++++++++++++++--------
 xs/t/01_trianglemesh.t     |  3 ++-
 6 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm
index 3dbddda76..193a9cf34 100644
--- a/lib/Slic3r/Layer.pm
+++ b/lib/Slic3r/Layer.pm
@@ -11,7 +11,7 @@ has 'upper_layer'       => (is => 'rw', weak_ref => 1);
 has 'regions'           => (is => 'ro', default => sub { [] });
 has 'slicing_errors'    => (is => 'rw');
 
-has 'slice_z'           => (is => 'ro', required => 1); # Z used for slicing in scaled coordinates
+has 'slice_z'           => (is => 'ro', required => 1); # Z used for slicing in unscaled coordinates
 has 'print_z'           => (is => 'ro', required => 1); # Z used for printing in unscaled coordinates
 has 'height'            => (is => 'ro', required => 1); # layer height in unscaled coordinates
 
diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm
index e264bfe5f..2b4a6d19d 100644
--- a/lib/Slic3r/Layer/Region.pm
+++ b/lib/Slic3r/Layer/Region.pm
@@ -135,7 +135,7 @@ sub _merge_loops {
     $slices = offset2_ex($slices, +$safety_offset, -$safety_offset);
     
     Slic3r::debugf "Layer %d (slice_z = %.2f, print_z = %.2f): %d surface(s) having %d holes detected from %d polylines\n",
-        $self->id, unscale($self->slice_z), $self->print_z,
+        $self->id, $self->slice_z, $self->print_z,
         scalar(@$slices), scalar(map @{$_->holes}, @$slices), scalar(@$loops)
         if $Slic3r::debug;
     
diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm
index a77f05542..1b3dd253d 100644
--- a/lib/Slic3r/Print.pm
+++ b/lib/Slic3r/Print.pm
@@ -129,8 +129,6 @@ sub add_model {
                 $mesh->rotate($object->instances->[0]->rotation, $object->center_2D);
                 $mesh->scale($object->instances->[0]->scaling_factor);
             }
-            
-            $mesh->scale(1 / &Slic3r::SCALING_FACTOR);
             $mesh->repair;
         }
         
@@ -140,6 +138,9 @@ sub add_model {
         my @align2 = map -$bb->extents->[$_][MIN], (X,Y,Z);
         $_->translate(@align2) for grep $_, @meshes;
         
+        my $scaled_bb = $bb->clone;
+        $scaled_bb->scale(1 / &Slic3r::SCALING_FACTOR);
+        
         # initialize print object
         push @{$self->objects}, Slic3r::Print::Object->new(
             print       => $self,
@@ -150,7 +151,7 @@ sub add_model {
                     ? (map [ scale($_->offset->[X] - $align[X]) - $align2[X], scale($_->offset->[Y] - $align[Y]) - $align2[Y] ], @{$object->instances})
                     : [0,0],
             ],
-            size        => $bb->size,  # transformed size
+            size        => $scaled_bb->size,  # transformed size
             input_file  => $object->input_file,
             config_overrides    => $object->config,
             layer_height_ranges => $object->layer_height_ranges,
@@ -514,7 +515,7 @@ EOF
     my @previous_layer_slices = ();
     for my $layer_id (0..$self->layer_count-1) {
         my @layers = map $_->layers->[$layer_id], @{$self->objects};
-        printf $fh qq{  <g id="layer%d" slic3r:z="%s">\n}, $layer_id, unscale +(grep defined $_, @layers)[0]->slice_z;
+        printf $fh qq{  <g id="layer%d" slic3r:z="%s">\n}, $layer_id, +(grep defined $_, @layers)[0]->slice_z;
         
         my @current_layer_slices = ();
         for my $obj_idx (0 .. $#{$self->objects}) {
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index dcca3c5b2..1314afdcf 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -63,7 +63,7 @@ sub BUILD {
             id      => $id,
             height  => $height,
             print_z => $print_z,
-            slice_z => scale $slice_z,
+            slice_z => $slice_z,
         );
         if (@{$self->layers} >= 2) {
             $self->layers->[-2]->upper_layer($self->layers->[-1]);
diff --git a/xs/src/TriangleMesh.cpp b/xs/src/TriangleMesh.cpp
index fcd27a3b1..962e92a7b 100644
--- a/xs/src/TriangleMesh.cpp
+++ b/xs/src/TriangleMesh.cpp
@@ -165,7 +165,7 @@ void
 TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
 {
     /*
-       This method gets called with a list of Z coordinates and outputs
+       This method gets called with a list of unscaled Z coordinates and outputs
        a vector pointer having the same number of items as the original list.
        Each item is a vector of polygons created by slicing our mesh at the 
        given heights.
@@ -240,10 +240,21 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
     
     std::vector<IntersectionLines> lines(z.size());
     
+    // clone shared vertices coordinates and scale them
+    stl_vertex* v_scaled_shared = (stl_vertex*)calloc(this->stl.stats.shared_vertices, sizeof(stl_vertex));
+    std::copy(this->stl.v_shared, this->stl.v_shared + this->stl.stats.shared_vertices, v_scaled_shared);
+    for (int i = 0; i < this->stl.stats.shared_vertices; i++) {
+        v_scaled_shared[i].x /= SCALING_FACTOR;
+        v_scaled_shared[i].y /= SCALING_FACTOR;
+        v_scaled_shared[i].z /= SCALING_FACTOR;
+    }
+    
     for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; facet_idx++) {
-        stl_facet* facet = &(this->stl.facet_start[facet_idx]);
-        float min_z = fminf(facet->vertex[0].z, fminf(facet->vertex[1].z, facet->vertex[2].z));
-        float max_z = fmaxf(facet->vertex[0].z, fmaxf(facet->vertex[1].z, facet->vertex[2].z));
+        stl_facet* facet = &this->stl.facet_start[facet_idx];
+        
+        // find facet extents
+        double min_z = fminf(facet->vertex[0].z, fminf(facet->vertex[1].z, facet->vertex[2].z));
+        double max_z = fmaxf(facet->vertex[0].z, fmaxf(facet->vertex[1].z, facet->vertex[2].z));
         
         #ifdef SLIC3R_DEBUG
         printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx,
@@ -260,6 +271,7 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
             continue;
         }
         
+        // find layer extents
         std::vector<double>::const_iterator min_layer, max_layer;
         min_layer = std::lower_bound(z.begin(), z.end(), min_z); // first layer whose slice_z is >= min_z
         max_layer = std::upper_bound(z.begin() + (min_layer - z.begin()), z.end(), max_z) - 1; // last layer whose slice_z is <= max_z
@@ -269,7 +281,8 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
         
         for (std::vector<double>::const_iterator it = min_layer; it != max_layer + 1; ++it) {
             std::vector<double>::size_type layer_idx = it - z.begin();
-            double slice_z = *it;
+            double slice_z_u = *it;   // unscaled
+            double slice_z = slice_z_u / SCALING_FACTOR;
             std::vector<IntersectionPoint> points;
             std::vector< std::vector<IntersectionPoint>::size_type > points_on_layer;
             bool found_horizontal_edge = false;
@@ -289,8 +302,8 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
                 int edge_id = facets_edges[facet_idx][j % 3];
                 int a_id = this->stl.v_indices[facet_idx].vertex[j % 3];
                 int b_id = this->stl.v_indices[facet_idx].vertex[(j+1) % 3];
-                stl_vertex* a = &(this->stl.v_shared[a_id]);
-                stl_vertex* b = &(this->stl.v_shared[b_id]);
+                stl_vertex* a = &v_scaled_shared[a_id];
+                stl_vertex* b = &v_scaled_shared[b_id];
                 
                 if (a->z == b->z && a->z == slice_z) {
                     // edge is horizontal and belongs to the current layer
@@ -298,7 +311,7 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
                     /* We assume that this method is never being called for horizontal
                        facets, so no other edge is going to be on this layer. */
                     IntersectionLine line;
-                    if (facet->vertex[0].z < slice_z || facet->vertex[1].z < slice_z || facet->vertex[2].z < slice_z) {
+                    if (facet->vertex[0].z < slice_z_u || facet->vertex[1].z < slice_z_u || facet->vertex[2].z < slice_z_u) {
                         line.edge_type = feTop;
                         std::swap(a, b);
                         std::swap(a_id, b_id);
@@ -367,6 +380,8 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
         }
     }
     
+    free(v_scaled_shared);
+    
     // build loops
     layers.resize(z.size());
     for (std::vector<IntersectionLines>::iterator it = lines.begin(); it != lines.end(); ++it) {
diff --git a/xs/t/01_trianglemesh.t b/xs/t/01_trianglemesh.t
index 71ae47319..c9eb44de4 100644
--- a/xs/t/01_trianglemesh.t
+++ b/xs/t/01_trianglemesh.t
@@ -80,9 +80,10 @@ my $cube = {
     $m->repair;
     my @z = (2,4,8,6,8,10,12,14,16,18,20);
     my $result = $m->slice(\@z);
+    my $SCALING_FACTOR = 0.000001;
     for my $i (0..$#z) {
         is scalar(@{$result->[$i]}), 1, 'number of returned polygons per layer';
-        is $result->[$i][0]->area, 20*20, 'size of returned polygon';
+        is $result->[$i][0]->area, 20*20/($SCALING_FACTOR**2), 'size of returned polygon';
         ok $result->[$i][0]->is_counter_clockwise, 'orientation of returned polygon';
     }
 }