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;