diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index 2f10a9fe6..2058a6e07 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -114,6 +114,7 @@ sub thread_cleanup { *Slic3r::ExPolygon::Collection::DESTROY = sub {}; *Slic3r::ExtrusionLoop::DESTROY = sub {}; *Slic3r::ExtrusionPath::DESTROY = sub {}; + *Slic3r::ExtrusionPath::Collection::DESTROY = sub {}; *Slic3r::Line::DESTROY = sub {}; *Slic3r::Point::DESTROY = sub {}; *Slic3r::Polygon::DESTROY = sub {}; diff --git a/lib/Slic3r/ExtrusionPath/Collection.pm b/lib/Slic3r/ExtrusionPath/Collection.pm index 4577d3b7b..3354efaee 100644 --- a/lib/Slic3r/ExtrusionPath/Collection.pm +++ b/lib/Slic3r/ExtrusionPath/Collection.pm @@ -42,12 +42,15 @@ sub cleanup { my $self = shift; # split paths at angles that are too acute to be printed as they will cause blobs - @{$self->paths} = map $_->split_at_acute_angles, @{$self->paths}; + my @paths = map $_->split_at_acute_angles, @$self; + $self->clear; + $self->append(@paths); } sub detect_arcs { my $self = shift; - @{$self->paths} = map $_->detect_arcs(@_), @{$self->paths}; + + return map $_->detect_arcs(@_), @$self; } 1; diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 94762a7cc..5a172776b 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -211,11 +211,7 @@ sub extrude_loop { $extrusion_path->intersect_expolygons($self->_layer_overhangs); # reapply the nearest point search for starting point - { - my $collection = Slic3r::ExtrusionPath::Collection->new; - $collection->append(@paths); - @paths = $collection->chained_path($start_at, 1); - } + @paths = Slic3r::ExtrusionPath::Collection->new(@paths)->chained_path($start_at, 1); } else { push @paths, $extrusion_path; } diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index 3b70e3f25..19c9b18eb 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -29,19 +29,19 @@ has 'slices' => (is => 'rw', default => sub { Slic3r::Surface::Collection->new } # collection of polygons or polylines representing thin walls contained # in the original geometry -has 'thin_walls' => (is => 'rw', default => sub { [] }); +has 'thin_walls' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new }); # collection of extrusion paths/loops filling gaps -has 'thin_fills' => (is => 'rw', default => sub { [] }); +has 'thin_fills' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new }); # collection of surfaces for infill generation has 'fill_surfaces' => (is => 'rw', default => sub { Slic3r::Surface::Collection->new }); # ordered collection of extrusion paths/loops to build all perimeters -has 'perimeters' => (is => 'rw', default => sub { [] }); +has 'perimeters' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new }); # ordered collection of extrusion paths to fill surfaces -has 'fills' => (is => 'rw', default => sub { [] }); +has 'fills' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new }); sub BUILD { my $self = shift; @@ -100,13 +100,11 @@ sub make_surfaces { 1, ); - $self->thin_walls([]); + $self->thin_walls->clear; if (@$diff) { my $area_threshold = $self->perimeter_flow->scaled_spacing ** 2; @$diff = grep $_->area > ($area_threshold), @$diff; - - @{$self->thin_walls} = map $_->medial_axis($self->perimeter_flow->scaled_width), @$diff; - + $self->thin_walls->append(map $_->medial_axis($self->perimeter_flow->scaled_width), @$diff); Slic3r::debugf " %d thin walls detected\n", scalar(@{$self->thin_walls}) if @{$self->thin_walls}; } } @@ -156,9 +154,9 @@ sub make_perimeters { my $infill_spacing = $self->solid_infill_flow->scaled_spacing; my $gap_area_threshold = $self->perimeter_flow->scaled_width ** 2; - $self->perimeters([]); + $self->perimeters->clear; $self->fill_surfaces->clear; - $self->thin_fills([]); + $self->thin_fills->clear; my @contours = (); # array of Polygons with ccw orientation my @holes = (); # array of Polygons with cw orientation @@ -278,7 +276,7 @@ sub make_perimeters { || ($self->layer->id == 0 && $Slic3r::Config->brim_width > 0); # append perimeters - push @{ $self->perimeters }, @loops; + $self->perimeters->append(@loops); # add thin walls as perimeters push @{ $self->perimeters }, Slic3r::ExtrusionPath::Collection->new( @@ -333,11 +331,11 @@ sub _fill_gaps { role => EXTR_ROLE_SOLIDFILL, flow_spacing => $flow->spacing, ); - push @{ $self->thin_fills }, map { + $self->thin_fills->append(map { $_->isa('Slic3r::Polygon') ? Slic3r::ExtrusionLoop->new(polygon => $_, %path_args)->split_at_first_point # we should keep these as loops : Slic3r::ExtrusionPath->new(polyline => $_, %path_args), - } map $_->medial_axis($flow->scaled_width), @this_width; + } map $_->medial_axis($flow->scaled_width), @this_width); Slic3r::debugf " %d gaps filled with extrusion width = %s\n", scalar @this_width, $width if @{ $self->thin_fills }; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 23a7099d9..4358f47cb 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -395,33 +395,17 @@ sub export_gcode { thread_cb => sub { my $q = shift; $Slic3r::Geometry::Clipper::clipper = Math::Clipper->new; - my $fills = {}; while (defined (my $obj_layer = $q->dequeue)) { my ($obj_idx, $layer_id, $region_id) = @$obj_layer; my $object = $self->objects->[$obj_idx]; - $fills->{$obj_idx} ||= {}; - $fills->{$obj_idx}{$layer_id} ||= {}; - $fills->{$obj_idx}{$layer_id}{$region_id} = [ - $object->fill_maker->make_fill($object->layers->[$layer_id]->regions->[$region_id]), - ]; - } - return $fills; - }, - collect_cb => sub { - my $fills = shift; - foreach my $obj_idx (keys %$fills) { - my $object = $self->objects->[$obj_idx]; - foreach my $layer_id (keys %{$fills->{$obj_idx}}) { - my $layer = $object->layers->[$layer_id]; - foreach my $region_id (keys %{$fills->{$obj_idx}{$layer_id}}) { - $layer->regions->[$region_id]->fills($fills->{$obj_idx}{$layer_id}{$region_id}); - } - } + my $layerm = $object->layers->[$layer_id]->regions->[$region_id]; + $layerm->fills->append( $object->fill_maker->make_fill($layerm) ); } }, + collect_cb => sub {}, no_threads_cb => sub { foreach my $layerm (map @{$_->regions}, map @{$_->layers}, @{$self->objects}) { - $layerm->fills([ $layerm->layer->object->fill_maker->make_fill($layerm) ]); + $layerm->fills->append($layerm->layer->object->fill_maker->make_fill($layerm)); } }, ); @@ -587,7 +571,7 @@ sub make_skirt { my @layer_points = ( (map @$_, map @$_, map @{$_->slices}, @layers), (map @$_, map @{$_->thin_walls}, map @{$_->regions}, @layers), - (map @{$_->polyline}, map @{$_->support_fills->paths}, grep $_->support_fills, @layers), + (map @{$_->polyline}, map @{$_->support_fills}, grep $_->support_fills, @layers), ); push @points, map move_points($_, @layer_points), @{$self->objects->[$obj_idx]->copies}; } @@ -647,7 +631,7 @@ sub make_brim { my @object_islands = ( (map $_->contour, @{$layer0->slices}), (map { $_->isa('Slic3r::Polygon') ? $_ : $_->grow($grow_distance) } map @{$_->thin_walls}, @{$layer0->regions}), - (map $_->polyline->grow($grow_distance), map @{$_->support_fills->paths}, grep $_->support_fills, $layer0), + (map $_->polyline->grow($grow_distance), map @{$_->support_fills}, grep $_->support_fills, $layer0), ); foreach my $copy (@{$self->objects->[$obj_idx]->copies}) { push @islands, map $_->clone->translate(@$copy), @object_islands; diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 7b76ba7da..da41b36a0 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -315,31 +315,11 @@ sub make_perimeters { thread_cb => sub { my $q = shift; $Slic3r::Geometry::Clipper::clipper = Math::Clipper->new; - my $result = {}; while (defined (my $layer_id = $q->dequeue)) { - my $layer = $self->layers->[$layer_id]; - $layer->make_perimeters; - $result->{$layer_id} ||= {}; - foreach my $region_id (0 .. $#{$layer->regions}) { - my $layerm = $layer->regions->[$region_id]; - $result->{$layer_id}{$region_id} = { - perimeters => $layerm->perimeters, - fill_surfaces => $layerm->fill_surfaces, - thin_fills => $layerm->thin_fills, - }; - } - } - return $result; - }, - collect_cb => sub { - my $result = shift; - foreach my $layer_id (keys %$result) { - foreach my $region_id (keys %{$result->{$layer_id}}) { - $self->layers->[$layer_id]->regions->[$region_id]->$_($result->{$layer_id}{$region_id}{$_}) - for qw(perimeters fill_surfaces thin_fills); - } + $self->layers->[$layer_id]->make_perimeters; } }, + collect_cb => sub {}, no_threads_cb => sub { $_->make_perimeters for @{$self->layers}; }, @@ -988,9 +968,6 @@ sub generate_support_material { }; return @paths; }; - my %layer_paths = (); - my %layer_contact_paths = (); - my %layer_islands = (); my $process_layer = sub { my ($layer_id) = @_; my $layer = $self->layers->[$layer_id]; @@ -1026,6 +1003,9 @@ sub generate_support_material { } return ($paths, $contact_paths, $islands); }; + my %layer_paths = (); + my %layer_contact_paths = (); + my %layer_islands = (); Slic3r::parallelize( items => [ keys %layers ], thread_cb => sub { @@ -1051,8 +1031,8 @@ sub generate_support_material { $layer->support_islands($layer_islands{$layer_id}); $layer->support_fills(Slic3r::ExtrusionPath::Collection->new); $layer->support_contact_fills(Slic3r::ExtrusionPath::Collection->new); - push @{$layer->support_fills->paths}, @{$layer_paths{$layer_id}}; - push @{$layer->support_contact_fills->paths}, @{$layer_contact_paths{$layer_id}}; + $layer->support_fills->append(@{$layer_paths{$layer_id}}); + $layer->support_contact_fills->append(@{$layer_contact_paths{$layer_id}}); } } } diff --git a/t/arcs.t b/t/arcs.t index 3b14903c8..7d15b63f8 100644 --- a/t/arcs.t +++ b/t/arcs.t @@ -22,11 +22,10 @@ use Slic3r::Geometry qw(scaled_epsilon scale X Y); [86948.77,175149.09], [119825.35,100585], ), role => EXTR_ROLE_FILL, flow_spacing => 0.5); - my $collection = Slic3r::ExtrusionPath::Collection->new(paths => [$path]); - $collection->detect_arcs(30); + my @paths = $path->detect_arcs(30); - is scalar(@{$collection->paths}), 3, 'path collection now contains three paths'; - isa_ok $collection->paths->[1], 'Slic3r::ExtrusionPath::Arc', 'second one'; + is scalar(@paths), 3, 'path collection now contains three paths'; + isa_ok $paths[1], 'Slic3r::ExtrusionPath::Arc', 'second one'; } #========================================================== @@ -50,30 +49,27 @@ use Slic3r::Geometry qw(scaled_epsilon scale X Y); flow_spacing => 0.5, ); - my $collection1 = Slic3r::ExtrusionPath::Collection->new(paths => [$path1]); - my $collection2 = Slic3r::ExtrusionPath::Collection->new(paths => [$path2]); + my @paths1 = $path1->detect_arcs(10, scale 1); + my @paths2 = $path2->detect_arcs(10, scale 1); - $collection1->detect_arcs(10, scale 1); - $collection2->detect_arcs(10, scale 1); + is scalar(@paths1), 1, 'path collection now contains one path'; + is scalar(@paths2), 1, 'path collection now contains one path'; - is scalar(@{$collection1->paths}), 1, 'path collection now contains one path'; - is scalar(@{$collection2->paths}), 1, 'path collection now contains one path'; - - isa_ok $collection1->paths->[0], 'Slic3r::ExtrusionPath::Arc', 'path'; - isa_ok $collection2->paths->[0], 'Slic3r::ExtrusionPath::Arc', 'path'; + isa_ok $paths1[0], 'Slic3r::ExtrusionPath::Arc', 'path'; + isa_ok $paths2[0], 'Slic3r::ExtrusionPath::Arc', 'path'; my $expected_length = scale 7.06858347057701; - ok abs($collection1->paths->[0]->length - $expected_length) < scaled_epsilon, 'cw oriented arc has correct length'; - ok abs($collection2->paths->[0]->length - $expected_length) < scaled_epsilon, 'ccw oriented arc has correct length'; + ok abs($paths1[0]->length - $expected_length) < scaled_epsilon, 'cw oriented arc has correct length'; + ok abs($paths2[0]->length - $expected_length) < scaled_epsilon, 'ccw oriented arc has correct length'; - is $collection1->paths->[0]->orientation, 'cw', 'cw orientation was correctly detected'; - is $collection2->paths->[0]->orientation, 'ccw', 'ccw orientation was correctly detected'; - is $collection1->paths->[0]->flow_spacing, $path1->flow_spacing, 'flow spacing was correctly preserved'; + is $paths1[0]->orientation, 'cw', 'cw orientation was correctly detected'; + is $paths2[0]->orientation, 'ccw', 'ccw orientation was correctly detected'; + is $paths1[0]->flow_spacing, $path1->flow_spacing, 'flow spacing was correctly preserved'; - my $center1 = [ map sprintf('%.0f', $_), @{ $collection1->paths->[0]->center } ]; + my $center1 = [ map sprintf('%.0f', $_), @{ $paths1[0]->center } ]; ok abs($center1->[X] - scale 10) < scaled_epsilon && abs($center1->[Y] - scale 10) < scaled_epsilon, 'center was correctly detected'; - my $center2 = [ map sprintf('%.0f', $_), @{ $collection2->paths->[0]->center } ]; + my $center2 = [ map sprintf('%.0f', $_), @{ $paths2[0]->center } ]; ok abs($center2->[X] - scale 10) < scaled_epsilon && abs($center1->[Y] - scale 10) < scaled_epsilon, 'center was correctly detected'; } diff --git a/t/fill.t b/t/fill.t index ed0505c89..690b0ba25 100644 --- a/t/fill.t +++ b/t/fill.t @@ -71,11 +71,11 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } } { - my $collection = Slic3r::ExtrusionPath::Collection->new(paths => [ + my $collection = Slic3r::ExtrusionPath::Collection->new( map Slic3r::ExtrusionPath->new(polyline => $_, role => 0), Slic3r::Polyline->new([0,15], [0,18], [0,20]), Slic3r::Polyline->new([0,10], [0,8], [0,5]), - ]); + ); is_deeply [ map $_->[Y], map @{$_->polyline}, $collection->chained_path(Slic3r::Point->new(0,30)) ], [20, 18, 15, 10, 8, 5], @@ -83,11 +83,11 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } } { - my $collection = Slic3r::ExtrusionPath::Collection->new(paths => [ + my $collection = Slic3r::ExtrusionPath::Collection->new( map Slic3r::ExtrusionPath->new(polyline => $_, role => 0), Slic3r::Polyline->new([15,0], [10,0], [4,0]), Slic3r::Polyline->new([10,5], [15,5], [20,5]), - ]); + ); is_deeply [ map $_->[X], map @{$_->polyline}, $collection->chained_path(Slic3r::Point->new(30,0)) ], [reverse 4, 10, 15, 10, 15, 20], diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 174e72e44..ebe2b59fb 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -43,6 +43,14 @@ use overload '@{}' => sub { $_[0]->arrayref }, 'fallback' => 1; +sub new { + my ($class, @paths) = @_; + + my $self = $class->_new; + $self->append(@paths); + return $self; +} + package Slic3r::ExtrusionLoop; use overload '@{}' => sub { $_[0]->arrayref }, diff --git a/xs/src/ExtrusionEntityCollection.hpp b/xs/src/ExtrusionEntityCollection.hpp index ef36cd136..7ffe8a454 100644 --- a/xs/src/ExtrusionEntityCollection.hpp +++ b/xs/src/ExtrusionEntityCollection.hpp @@ -6,7 +6,7 @@ namespace Slic3r { -class ExtrusionEntityCollection +class ExtrusionEntityCollection : public ExtrusionEntity { public: ExtrusionEntitiesPtr entities; diff --git a/xs/t/12_extrusionpathcollection.t b/xs/t/12_extrusionpathcollection.t index 97be65772..53d315856 100644 --- a/xs/t/12_extrusionpathcollection.t +++ b/xs/t/12_extrusionpathcollection.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 5; +use Test::More tests => 8; my $points = [ [100, 100], @@ -22,16 +22,23 @@ my $loop = Slic3r::ExtrusionLoop->new( role => Slic3r::ExtrusionPath::EXTR_ROLE_FILL, ); -my $collection = Slic3r::ExtrusionPath::Collection->new; -isa_ok $collection, 'Slic3r::ExtrusionPath::Collection', 'collection object'; +my $collection = Slic3r::ExtrusionPath::Collection->new($path); +isa_ok $collection, 'Slic3r::ExtrusionPath::Collection', 'collection object with items in constructor'; + +$collection->append($collection); +is scalar(@$collection), 2, 'append ExtrusionPath::Collection'; $collection->append($path); -is scalar(@$collection), 1, 'append ExtrusionPath'; +is scalar(@$collection), 3, 'append ExtrusionPath'; $collection->append($loop); -is scalar(@$collection), 2, 'append ExtrusionLoop'; +is scalar(@$collection), 4, 'append ExtrusionLoop'; + +isa_ok $collection->[1], 'Slic3r::ExtrusionPath::Collection', 'correct object returned for collection'; +isa_ok $collection->[2], 'Slic3r::ExtrusionPath', 'correct object returned for path'; +isa_ok $collection->[3], 'Slic3r::ExtrusionLoop', 'correct object returned for loop'; + +is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated'; -isa_ok $collection->[0], 'Slic3r::ExtrusionPath', 'correct object returned for path'; -isa_ok $collection->[1], 'Slic3r::ExtrusionLoop', 'correct object returned for loop'; __END__ diff --git a/xs/xsp/ExtrusionEntityCollection.xsp b/xs/xsp/ExtrusionEntityCollection.xsp index 5715f1899..89c84f57f 100644 --- a/xs/xsp/ExtrusionEntityCollection.xsp +++ b/xs/xsp/ExtrusionEntityCollection.xsp @@ -6,7 +6,7 @@ %} %name{Slic3r::ExtrusionPath::Collection} class ExtrusionEntityCollection { - ExtrusionEntityCollection(); + %name{_new} ExtrusionEntityCollection(); ~ExtrusionEntityCollection(); void clear() %code{% THIS->entities.clear(); %}; @@ -23,8 +23,10 @@ ExtrusionEntityCollection::arrayref() // return COPIES if (ExtrusionPath* path = dynamic_cast(*it)) { sv_setref_pv( sv, "Slic3r::ExtrusionPath", new ExtrusionPath(*(ExtrusionPath*)*it) ); - } else { + } else if (ExtrusionLoop* path = dynamic_cast(*it)) { sv_setref_pv( sv, "Slic3r::ExtrusionLoop", new ExtrusionLoop(*(ExtrusionLoop*)*it) ); + } else { + sv_setref_pv( sv, "Slic3r::ExtrusionPath::Collection", new ExtrusionEntityCollection(*(ExtrusionEntityCollection*)*it) ); } av_store(av, i++, sv); } @@ -40,8 +42,10 @@ ExtrusionEntityCollection::append(...) // append COPIES if (ExtrusionPath* path = dynamic_cast(entity)) { THIS->entities.push_back( new ExtrusionPath(*path) ); + } else if (ExtrusionLoop* loop = dynamic_cast(entity)) { + THIS->entities.push_back( new ExtrusionLoop(*loop) ); } else { - THIS->entities.push_back( new ExtrusionLoop(*(ExtrusionLoop*)entity) ); + THIS->entities.push_back( new ExtrusionEntityCollection(*(ExtrusionEntityCollection*)entity) ); } }