From 25bafe7ff11601e95627fc6e81af905b33e52ea7 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Tue, 14 May 2013 13:52:29 +0200
Subject: [PATCH] Memory (and maybe speed?) optimization in STL reader

---
 lib/Slic3r/Format/STL.pm | 52 +++++++++++++++++++++-------------------
 1 file changed, 28 insertions(+), 24 deletions(-)

diff --git a/lib/Slic3r/Format/STL.pm b/lib/Slic3r/Format/STL.pm
index 5c992230e..659568092 100644
--- a/lib/Slic3r/Format/STL.pm
+++ b/lib/Slic3r/Format/STL.pm
@@ -33,26 +33,11 @@ sub read_file {
     }
     
     my $facets = [];
-    $mode eq 'ascii'
-        ? _read_ascii($fh, $facets)
-        : _read_binary($fh, $facets);
-    close $fh;
-    
     my $vertices = [];
-    {
-        my %vertices_map = ();    # given a vertex's coordinates, what's its index?
-        for (my $f = 0; $f <= $#$facets; $f++) {
-            for (-3..-1) {
-                my $point_id = join ',', @{$facets->[$f][$_]};
-                if (exists $vertices_map{$point_id}) {
-                    $facets->[$f][$_] = $vertices_map{$point_id};
-                } else {
-                    push @$vertices, $facets->[$f][$_];
-                    $facets->[$f][$_] = $vertices_map{$point_id} = $#$vertices;
-                }
-            }
-        }
-    }
+    $mode eq 'ascii'
+        ? _read_ascii($fh, $facets, $vertices)
+        : _read_binary($fh, $facets, $vertices);
+    close $fh;
     
     my $model = Slic3r::Model->new;
     my $object = $model->add_object(vertices => $vertices);
@@ -61,11 +46,12 @@ sub read_file {
 }
 
 sub _read_ascii {
-    my ($fh, $facets) = @_;
+    my ($fh, $facets, $vertices) = @_;
     
     my $point_re = qr/([^ ]+)\s+([^ ]+)\s+([^ ]+)/;
     
     my $facet;
+    my %vertices_map = ();
     seek $fh, 0, 0;
     while (my $_ = <$fh>) {
         if (!$facet) {
@@ -77,7 +63,15 @@ sub _read_ascii {
                 undef $facet;
             } else {
                 /^\s*vertex\s+$point_re/o or next;
-                push @$facet, [map $_ * 1, $1, $2, $3];
+                my $vertex_id = join ',', $1, $2, $3;
+                my $vertex_idx;
+                if (exists $vertices_map{$vertex_id}) {
+                    $vertex_idx = $vertices_map{$vertex_id};
+                } else {
+                    push @$vertices, [map $_ * 1, $1, $2, $3];
+                    $vertex_idx = $vertices_map{$vertex_id} = $#$vertices;
+                }
+                push @$facet, $vertex_idx;
             }
         }
     }
@@ -87,15 +81,25 @@ sub _read_ascii {
 }
 
 sub _read_binary {
-    my ($fh, $facets) = @_;
+    my ($fh, $facets, $vertices) = @_;
     
     die "bigfloat" unless length(pack "f", 1) == 4;
     
+    my %vertices_map = ();
     binmode $fh;
     seek $fh, 80 + 4, 0;
     while (read $fh, my $_, 4*4*3+2) {
-        my @v = unpack '(f<3)4';
-        push @$facets, [ [@v[3..5]], [@v[6..8]], [@v[9..11]] ];  # ignore normal: [@v[0..2]]
+        push @$facets, my $facet = [];
+        for (unpack 'x[f3](a[f3])3') {  # ignore normal
+            my $vertex_idx;
+            if (exists $vertices_map{$_}) {
+                $vertex_idx = $vertices_map{$_};
+            } else {
+                push @$vertices, [ unpack 'f<3', $_ ];
+                $vertex_idx = $vertices_map{$_} = $#$vertices;
+            }
+            push @$facet, $vertex_idx;
+        }
     }
 }