From a165ad4ecb4f4cf8c79cc61cb51db5e7b63375e2 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Tue, 1 May 2012 10:53:52 +0200
Subject: [PATCH] Large memory saving and speed boost

---
 MANIFEST                                    |   1 -
 lib/Slic3r.pm                               |   1 -
 lib/Slic3r/Layer.pm                         |   2 +-
 lib/Slic3r/TriangleMesh.pm                  | 116 +++++++++++---------
 lib/Slic3r/TriangleMesh/IntersectionLine.pm |  25 -----
 5 files changed, 68 insertions(+), 77 deletions(-)
 delete mode 100644 lib/Slic3r/TriangleMesh/IntersectionLine.pm

diff --git a/MANIFEST b/MANIFEST
index e49804081..195f2ede3 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -37,7 +37,6 @@ lib/Slic3r/Print/Object.pm
 lib/Slic3r/Surface.pm
 lib/Slic3r/SVG.pm
 lib/Slic3r/TriangleMesh.pm
-lib/Slic3r/TriangleMesh/IntersectionLine.pm
 MANIFEST			This list of files
 README.markdown
 slic3r.pl
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index 3b77246b5..004c3aa1f 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -35,7 +35,6 @@ use Slic3r::Print;
 use Slic3r::Print::Object;
 use Slic3r::Surface;
 use Slic3r::TriangleMesh;
-use Slic3r::TriangleMesh::IntersectionLine;
 
 our $have_threads       = $Config{useithreads} && eval "use threads; use Thread::Queue; 1";
 our $threads            = $have_threads ? 4 : undef;
diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm
index 52433eb73..ca22104c4 100644
--- a/lib/Slic3r/Layer.pm
+++ b/lib/Slic3r/Layer.pm
@@ -18,7 +18,7 @@ has 'slicing_errors' => (is => 'rw');
 # these need to be merged in continuos (closed) polylines
 has 'lines' => (
     is      => 'rw',
-    #isa     => 'ArrayRef[Slic3r::TriangleMesh::IntersectionLine]',
+    #isa     => 'ArrayRef[ArrayRef]',
     default => sub { [] },
 );
 
diff --git a/lib/Slic3r/TriangleMesh.pm b/lib/Slic3r/TriangleMesh.pm
index 809c98c39..9fa7641a8 100644
--- a/lib/Slic3r/TriangleMesh.pm
+++ b/lib/Slic3r/TriangleMesh.pm
@@ -15,6 +15,17 @@ has 'edges_facets'  => (is => 'ro', default => sub { [] }); # id => [ $f1_id, $f
 use constant MIN => 0;
 use constant MAX => 1;
 
+use constant I_B                => 0;
+use constant I_A_ID             => 1;
+use constant I_B_ID             => 2;
+use constant I_FACET_INDEX      => 3;
+use constant I_PREV_FACET_INDEX => 4;
+use constant I_NEXT_FACET_INDEX => 5;
+use constant I_FACET_EDGE       => 6;
+
+use constant FE_TOP             => 0;
+use constant FE_BOTTOM          => 1;
+
 # always make sure BUILD is idempotent
 sub BUILD {
     my $self = shift;
@@ -133,11 +144,11 @@ sub make_loops {
     # remove tangent edges
     {
         for (my $i = 0; $i <= $#lines; $i++) {
-            next unless defined $lines[$i] && $lines[$i]->facet_edge;
+            next unless defined $lines[$i] && $lines[$i]->[I_FACET_EDGE];
             # if the line is a facet edge, find another facet edge
             # having the same endpoints but in reverse order
             for (my $j = $i+1; $j <= $#lines; $j++) {
-                next unless defined $lines[$j] && $lines[$j]->facet_edge;
+                next unless defined $lines[$j] && $lines[$j]->[I_FACET_EDGE];
                 
                 # are these facets adjacent? (sharing a common edge on this layer)
                 if ($lines[$i]->a_id == $lines[$j]->b_id && $lines[$i]->b_id == $lines[$j]->a_id) {
@@ -145,7 +156,7 @@ sub make_loops {
                     # if they are both oriented upwards or downwards (like a 'V')
                     # then we can remove both edges from this layer since it won't 
                     # affect the sliced shape
-                    if ($lines[$j]->facet_edge eq $lines[$i]->facet_edge) {
+                    if ($lines[$j]->[I_FACET_EDGE] eq $lines[$i]->[I_FACET_EDGE]) {
                         $lines[$i] = undef;
                         $lines[$j] = undef;
                         last;
@@ -154,7 +165,7 @@ sub make_loops {
                     # if one of them is oriented upwards and the other is oriented
                     # downwards, let's only keep one of them (it doesn't matter which
                     # one since all 'top' lines were reversed at slicing)
-                    if ($lines[$i]->facet_edge eq 'top' && $lines[$j]->facet_edge eq 'bottom') {
+                    if ($lines[$i]->[I_FACET_EDGE] eq FE_TOP && $lines[$j]->[I_FACET_EDGE] eq FE_BOTTOM) {
                         $lines[$j] = undef;
                         last;
                     }
@@ -170,25 +181,25 @@ sub make_loops {
     my %prev_count = ();  # how many lines have the same prev_facet_index
     my %a_count    = ();  # how many lines have the same a_id
     foreach my $line (@lines) {
-        if (defined $line->prev_facet_index) {
-            $prev_count{$line->prev_facet_index}++;
+        if (defined $line->[I_PREV_FACET_INDEX]) {
+            $prev_count{$line->[I_PREV_FACET_INDEX]}++;
         }
-        if (defined $line->a_id) {
-            $a_count{$line->a_id}++;
+        if (defined $line->[I_A_ID]) {
+            $a_count{$line->[I_A_ID]}++;
         }
     }
     
     foreach my $point_id (grep $a_count{$_} > 1, keys %a_count) {
-        my @lines_starting_here = grep defined $_->a_id && $_->a_id == $point_id, @lines;
+        my @lines_starting_here = grep defined $_->[I_A_ID] && $_->[I_A_ID] == $point_id, @lines;
         Slic3r::debugf "%d lines start at point %d\n", scalar(@lines_starting_here), $point_id;
         
         # if two lines start at this point, one being a 'top' facet edge and the other being a 'bottom' one,
         # then remove the top one and those following it (removing the top or the bottom one is an arbitrary
         # choice)
-        if (@lines_starting_here == 2 && join(',', sort map $_->facet_edge, @lines_starting_here) eq 'bottom,top') {
-            my @to_remove = grep $_->facet_edge eq 'top', @lines_starting_here;
-            while (!grep defined $_->b_id && $_->b_id == $to_remove[-1]->b_id && $_ ne $to_remove[-1], @lines) {
-                push @to_remove, grep defined $_->a_id && $_->a_id == $to_remove[-1]->b_id, @lines;
+        if (@lines_starting_here == 2 && join('', sort map $_->[I_FACET_EDGE], @lines_starting_here) eq FE_BOTTOM.FE_TOP) {
+            my @to_remove = grep $_->[I_FACET_EDGE] eq FE_TOP, @lines_starting_here;
+            while (!grep defined $_->[I_B_ID] && $_->[I_B_ID] == $to_remove[-1]->[I_B_ID] && $_ ne $to_remove[-1], @lines) {
+                push @to_remove, grep defined $_->[I_A_ID] && $_->[I_A_ID] == $to_remove[-1]->[I_B_ID], @lines;
             }
             my %to_remove = map {$_ => 1} @to_remove;
             @lines = grep !$to_remove{$_}, @lines;
@@ -197,8 +208,8 @@ sub make_loops {
             if (0) {
                 require "Slic3r/SVG.pm";
                 Slic3r::SVG::output(undef, "same_point.svg",
-                    lines       => [ map $_->line, grep !$_->facet_edge, @lines ],
-                    red_lines   => [ map $_->line, grep $_->facet_edge, @lines ],
+                    lines       => [ map $_->line, grep !$_->[I_FACET_EDGE], @lines ],
+                    red_lines   => [ map $_->line, grep $_->[I_FACET_EDGE], @lines ],
                     points      => [ $self->vertices->[$point_id] ],
                     no_arrows => 0,
                 );
@@ -207,11 +218,11 @@ sub make_loops {
     }
     
     # optimization: build indexes of lines
-    my %by_facet_index = map { $lines[$_]->facet_index => $_ }
-        grep defined $lines[$_]->facet_index,
+    my %by_facet_index = map { $lines[$_]->[I_FACET_INDEX] => $_ }
+        grep defined $lines[$_]->[I_FACET_INDEX],
         (0..$#lines);
-    my %by_a_id = map { $lines[$_]->a_id => $_ }
-        grep defined $lines[$_]->a_id,
+    my %by_a_id = map { $lines[$_]->[I_A_ID] => $_ }
+        grep defined $lines[$_]->[I_A_ID],
         (0..$#lines);
     
     my (@polygons, %visited_lines) = ();
@@ -219,14 +230,14 @@ sub make_loops {
         my $line = $lines[$i];
         next if $visited_lines{$line};
         my @points = ();
-        my $first_facet_index = $line->facet_index;
+        my $first_facet_index = $line->[I_FACET_INDEX];
         
         do {
             my $next_line;
-            if (defined $line->next_facet_index && exists $by_facet_index{$line->next_facet_index}) {
-                $next_line = $lines[$by_facet_index{$line->next_facet_index}];
-            } elsif (defined $line->b_id && exists $by_a_id{$line->b_id}) {
-                $next_line = $lines[$by_a_id{$line->b_id}];
+            if (defined $line->[I_NEXT_FACET_INDEX] && exists $by_facet_index{$line->[I_NEXT_FACET_INDEX]}) {
+                $next_line = $lines[$by_facet_index{$line->[I_NEXT_FACET_INDEX]}];
+            } elsif (defined $line->[I_B_ID] && exists $by_a_id{$line->[I_B_ID]}) {
+                $next_line = $lines[$by_a_id{$line->[I_B_ID]}];
             } else {
                 Slic3r::debugf "  line has no next_facet_index or b_id\n";
                 $layer->slicing_errors(1);
@@ -237,20 +248,20 @@ sub make_loops {
                 Slic3r::debugf "  failed to close this loop\n";
                 $layer->slicing_errors(1);
                 next CYCLE;
-            } elsif (defined $next_line->prev_facet_index && $next_line->prev_facet_index != $line->facet_index) {
+            } elsif (defined $next_line->[I_PREV_FACET_INDEX] && $next_line->[I_PREV_FACET_INDEX] != $line->[I_FACET_INDEX]) {
                 Slic3r::debugf "  wrong prev_facet_index\n";
                 $layer->slicing_errors(1);
                 next CYCLE;
-            } elsif (defined $next_line->a_id && $next_line->a_id != $line->b_id) {
+            } elsif (defined $next_line->[I_A_ID] && $next_line->[I_A_ID] != $line->b_id) {
                 Slic3r::debugf "  wrong a_id\n";
                 $layer->slicing_errors(1);
                 next CYCLE;
             }
             
-            push @points, $next_line->b;
+            push @points, $next_line->[I_B];
             $visited_lines{$next_line} = 1;
             $line = $next_line;
-        } while ($first_facet_index != $line->facet_index);
+        } while ($first_facet_index != $line->[I_FACET_INDEX]);
     
         push @polygons, Slic3r::Polygon->new(@points);
         Slic3r::debugf "  Discovered %s polygon of %d points\n",
@@ -400,19 +411,23 @@ sub intersect_facet {
         
         if ($a->[Z] == $b->[Z] && $a->[Z] == $z) {
             # edge is horizontal and belongs to the current layer
-            my $edge_type = (grep $self->vertices->[$_][Z] < $z, @vertices_ids) ? 'top' : 'bottom';
-            if ($edge_type eq 'top') {
+            my $edge_type = (grep $self->vertices->[$_][Z] < $z, @vertices_ids) ? FE_TOP : FE_BOTTOM;
+            if ($edge_type eq FE_TOP) {
                 ($a, $b) = ($b, $a);
                 ($a_id, $b_id) = ($b_id, $a_id);
             }
-            push @lines, Slic3r::TriangleMesh::IntersectionLine->new(
-                a           => [$a->[X], $a->[Y]],
-                b           => [$b->[X], $b->[Y]],
-                a_id        => $a_id,
-                b_id        => $b_id,
-                facet_edge  => $edge_type,
-                facet_index => $facet_id,
-            );
+            push @lines, [
+                [$b->[X], $b->[Y]],     # I_B
+                $a_id,                  # I_A_ID
+                $b_id,                  # I_B_ID
+                $facet_id,              # I_FACET_INDEX
+                undef,                  # I_PREV_FACET_INDEX
+                undef,                  # I_NEXT_FACET_INDEX
+                $edge_type,             # I_FACET_EDGE
+                
+                # Unused data:
+                # a             => [$a->[X], $a->[Y]],
+            ];
             #print "Horizontal edge at $z!\n";
             
         } elsif ($a->[Z] == $z) {
@@ -461,17 +476,20 @@ sub intersect_facet {
         $next_facet_index = +(grep $_ != $facet_id, @{$self->edges_facets->[$points[A][3]]})[0]
             if defined $points[A][3];
         
-        return Slic3r::TriangleMesh::IntersectionLine->new(
-            a      => [$points[B][X], $points[B][Y]],
-            b      => [$points[A][X], $points[A][Y]],
-            a_id   => $points[B][2],
-            b_id   => $points[A][2],
-            facet_index => $facet_id,
-            prev_edge_id => $points[B][3],
-            next_edge_id => $points[A][3],
-            prev_facet_index => $prev_facet_index,
-            next_facet_index => $next_facet_index,
-        );
+        return [
+            [$points[A][X], $points[A][Y]],     # I_B
+            $points[B][2],                      # I_A_ID
+            $points[A][2],                      # I_B_ID
+            $facet_id,                          # I_FACET_INDEX
+            $prev_facet_index,                  # I_PREV_FACET_INDEX
+            $next_facet_index,                  # I_NEXT_FACET_INDEX
+            undef,                              # I_FACET_EDGE
+            
+            # Unused data:
+            # a             => [$points[B][X], $points[B][Y]],
+            # prev_edge_id  => $points[B][3],
+            # next_edge_id  => $points[A][3],
+        ];
         #printf "  intersection points at z = %f: %f,%f - %f,%f\n", $z, map @$_, @intersection_points;
     }
     
diff --git a/lib/Slic3r/TriangleMesh/IntersectionLine.pm b/lib/Slic3r/TriangleMesh/IntersectionLine.pm
deleted file mode 100644
index 9ef4f0b6c..000000000
--- a/lib/Slic3r/TriangleMesh/IntersectionLine.pm
+++ /dev/null
@@ -1,25 +0,0 @@
-package Slic3r::TriangleMesh::IntersectionLine;
-use Moo;
-
-has 'a'             => (is => 'ro', required => 1);
-has 'b'             => (is => 'ro', required => 1);
-has 'a_id'          => (is => 'ro', required => 1);
-has 'b_id'          => (is => 'ro', required => 1);
-has 'facet_index'   => (is => 'ro', required => 1);
-has 'prev_facet_index' => (is => 'ro', required => 0);
-has 'next_facet_index' => (is => 'ro', required => 0);
-has 'prev_edge_id'  => (is => 'ro', required => 0);
-has 'next_edge_id'  => (is => 'ro', required => 0);
-has 'facet_edge'    => (is => 'ro', default => sub {0});
-
-sub points {
-    my $self = shift;
-    return [$self->a, $self->b];
-}
-
-sub line {
-    my $self = shift;
-    return Slic3r::Line->new($self->a, $self->b);
-}
-
-1;