diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 8e2f51e0a..95bd8e5af 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -13,7 +13,7 @@ use Slic3r::Fill::PlanePath; use Slic3r::Fill::Rectilinear; use Slic3r::ExtrusionPath ':roles'; use Slic3r::Geometry qw(X Y PI scale chained_path); -use Slic3r::Geometry::Clipper qw(union_ex diff diff_ex intersection_ex offset offset2); +use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2); use Slic3r::Surface ':types'; @@ -58,28 +58,26 @@ sub make_fill { # in case of bridge surfaces, the ones with defined angle will be attached to the ones # without any angle (shouldn't this logic be moved to process_external_surfaces()?) { - my @fill_surfaces = @{$layerm->fill_surfaces}; - my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @fill_surfaces; + my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layerm->fill_surfaces}; # give priority to bridges - my @groups = Slic3r::Surface->group({merge_solid => 1}, @fill_surfaces); - @groups = sort { defined $a->[0]->bridge_angle ? -1 : 0 } @groups; + my @groups = sort { defined $a->[0]->bridge_angle ? -1 : 0 } @{$layerm->fill_surfaces->group(1)}; foreach my $group (@groups) { - my $union = union_ex([ map $_->p, @$group ], 1); + my $union_p = union([ map $_->p, @$group ], 1); # subtract surfaces having a defined bridge_angle from any other if (@surfaces_with_bridge_angle && !defined $group->[0]->bridge_angle) { - $union = diff_ex( - [ map @$_, @$union ], + $union_p = diff( + $union_p, [ map $_->p, @surfaces_with_bridge_angle ], 1, ); } # subtract any other surface already processed - $union = diff_ex( - [ map @$_, @$union ], + my $union = diff_ex( + $union_p, [ map $_->p, @surfaces ], 1, ); diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index 4f95f6518..e264bfe5f 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -458,7 +458,7 @@ sub process_external_surfaces { # intersect the grown surfaces with the actual fill boundaries my @new_surfaces = (); - foreach my $group (Slic3r::Surface->group(@top, @bottom)) { + foreach my $group (@{Slic3r::Surface::Collection->new(@top, @bottom)->group}) { push @new_surfaces, map $group->[0]->clone(expolygon => $_), @{intersection_ex( @@ -470,7 +470,7 @@ sub process_external_surfaces { # subtract the new top surfaces from the other non-top surfaces and re-add them my @other = grep $_->surface_type != S_TYPE_TOP && $_->surface_type != S_TYPE_BOTTOM, @surfaces; - foreach my $group (Slic3r::Surface->group(@other)) { + foreach my $group (@{Slic3r::Surface::Collection->new(@other)->group}) { push @new_surfaces, map $group->[0]->clone(expolygon => $_), @{diff_ex( [ map $_->p, @$group ], [ map $_->p, @new_surfaces ], diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 17504d7b9..dcca3c5b2 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -487,7 +487,7 @@ sub bridge_over_infill { foreach my $lower_layerm (@{$self->layers->[$i]->regions}) { my @new_surfaces = (); # subtract the area from all types of surfaces - foreach my $group (Slic3r::Surface->group(@{$lower_layerm->fill_surfaces})) { + foreach my $group (@{$lower_layerm->fill_surfaces->group}) { push @new_surfaces, map $group->[0]->clone(expolygon => $_), @{diff_ex( [ map $_->p, @$group ], @@ -647,7 +647,7 @@ sub discover_horizontal_shells { (expolygon => $_, surface_type => S_TYPE_INTERNALSOLID), @$internal_solid); # assign top and bottom surfaces to layer - foreach my $s (Slic3r::Surface->group(grep { ($_->surface_type == S_TYPE_TOP) || ($_->surface_type == S_TYPE_BOTTOM) } @neighbor_fill_surfaces)) { + foreach my $s (@{Slic3r::Surface::Collection->new(grep { ($_->surface_type == S_TYPE_TOP) || ($_->surface_type == S_TYPE_BOTTOM) } @neighbor_fill_surfaces)->group}) { my $solid_surfaces = diff_ex( [ map $_->p, @$s ], [ map @$_, @$internal_solid, @$internal ], diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm index e1b84ad5a..998645a10 100644 --- a/lib/Slic3r/Surface.pm +++ b/lib/Slic3r/Surface.pm @@ -7,26 +7,6 @@ our @ISA = qw(Exporter); our @EXPORT_OK = qw(S_TYPE_TOP S_TYPE_BOTTOM S_TYPE_INTERNAL S_TYPE_INTERNALSOLID S_TYPE_INTERNALBRIDGE S_TYPE_INTERNALVOID); our %EXPORT_TAGS = (types => \@EXPORT_OK); -# static method to group surfaces having same surface_type, bridge_angle and thickness* -sub group { - my $class = shift; - my $params = ref $_[0] eq 'HASH' ? shift(@_) : {}; - my (@surfaces) = @_; - - my %unique_types = (); - foreach my $surface (@surfaces) { - my $type = join '_', - ($params->{merge_solid} && $surface->is_solid) ? 'solid' : $surface->surface_type, - $surface->bridge_angle // '', - $surface->thickness // '', - $surface->thickness_layers; - $unique_types{$type} ||= []; - push @{ $unique_types{$type} }, $surface; - } - - return values %unique_types; -} - sub offset { my $self = shift; return [ map $self->clone(expolygon => $_), @{$self->expolygon->offset_ex(@_)} ]; diff --git a/xs/MANIFEST b/xs/MANIFEST index 9d2e3699e..5256bba42 100644 --- a/xs/MANIFEST +++ b/xs/MANIFEST @@ -20,6 +20,8 @@ src/ExtrusionEntity.cpp src/ExtrusionEntity.hpp src/ExtrusionEntityCollection.cpp src/ExtrusionEntityCollection.hpp +src/Geometry.cpp +src/Geometry.hpp src/Line.cpp src/Line.hpp src/MultiPoint.cpp @@ -55,12 +57,14 @@ t/10_line.t t/11_clipper.t t/12_extrusionpathcollection.t t/13_polylinecollection.t +t/14_geometry.t xsp/Clipper.xsp xsp/ExPolygon.xsp xsp/ExPolygonCollection.xsp xsp/ExtrusionEntityCollection.xsp xsp/ExtrusionLoop.xsp xsp/ExtrusionPath.xsp +xsp/Geometry.xsp xsp/Line.xsp xsp/my.map xsp/mytype.map diff --git a/xs/src/Surface.cpp b/xs/src/Surface.cpp index fadb47213..085756b86 100644 --- a/xs/src/Surface.cpp +++ b/xs/src/Surface.cpp @@ -30,6 +30,13 @@ Surface::to_SV_ref() { sv_setref_pv( sv, "Slic3r::Surface::Ref", (void*)this ); return sv; } + +SV* +Surface::to_SV_clone_ref() const { + SV* sv = newSV(0); + sv_setref_pv( sv, "Slic3r::Surface", new Surface(*this) ); + return sv; +} #endif } diff --git a/xs/src/Surface.hpp b/xs/src/Surface.hpp index 5c4d65ef2..304cc4572 100644 --- a/xs/src/Surface.hpp +++ b/xs/src/Surface.hpp @@ -22,10 +22,12 @@ class Surface #ifdef SLIC3RXS SV* to_SV_ref(); + SV* to_SV_clone_ref() const; #endif }; typedef std::vector Surfaces; +typedef std::vector SurfacesPtr; } diff --git a/xs/src/SurfaceCollection.cpp b/xs/src/SurfaceCollection.cpp index 898db92e1..ce4995eae 100644 --- a/xs/src/SurfaceCollection.cpp +++ b/xs/src/SurfaceCollection.cpp @@ -21,12 +21,12 @@ SurfaceCollection::simplify(double tolerance) /* group surfaces by common properties */ void -SurfaceCollection::group(std::vector &retval, bool merge_solid) const +SurfaceCollection::group(std::vector &retval, bool merge_solid) { - typedef std::map t_unique_map; + typedef std::map t_unique_map; t_unique_map unique_map; - for (Surfaces::const_iterator it = this->surfaces.begin(); it != this->surfaces.end(); ++it) { + for (Surfaces::iterator it = this->surfaces.begin(); it != this->surfaces.end(); ++it) { // build the t_surface_group_key struct with this surface's properties t_surface_group_key key; if (merge_solid && it->is_solid()) { @@ -41,9 +41,9 @@ SurfaceCollection::group(std::vector &retval, bool merge_solid) const // check whether we already have a group for these properties if (unique_map.find(key) == unique_map.end()) { // no group exists, add it - unique_map[key] = Surfaces(); + unique_map[key] = SurfacesPtr(); } - unique_map[key].push_back(*it); + unique_map[key].push_back(&*it); } retval.reserve(unique_map.size()); diff --git a/xs/src/SurfaceCollection.hpp b/xs/src/SurfaceCollection.hpp index e941cee21..32bd6c042 100644 --- a/xs/src/SurfaceCollection.hpp +++ b/xs/src/SurfaceCollection.hpp @@ -25,7 +25,7 @@ class SurfaceCollection public: Surfaces surfaces; void simplify(double tolerance); - void group(std::vector &retval, bool merge_solid = false) const; + void group(std::vector &retval, bool merge_solid = false); }; } diff --git a/xs/t/05_surface.t b/xs/t/05_surface.t index 4a3689bee..493a74b52 100644 --- a/xs/t/05_surface.t +++ b/xs/t/05_surface.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 14; +use Test::More tests => 16; my $square = [ # ccw [100, 100], @@ -63,4 +63,15 @@ is $surface->extra_perimeters, 2, 'extra_perimeters'; is $item->surface_type, $collection->[0]->surface_type, 'collection returns items by reference'; } +{ + my @surfaces = ( + Slic3r::Surface->new(expolygon => $expolygon, surface_type => Slic3r::Surface::S_TYPE_BOTTOM), + Slic3r::Surface->new(expolygon => $expolygon, surface_type => Slic3r::Surface::S_TYPE_BOTTOM), + Slic3r::Surface->new(expolygon => $expolygon, surface_type => Slic3r::Surface::S_TYPE_TOP), + ); + my $collection = Slic3r::Surface::Collection->new(@surfaces); + is scalar(@{$collection->group}), 2, 'group() returns correct number of groups'; + is scalar(@{$collection->group(1)}), 1, 'group() returns correct number of solid groups'; +} + __END__ diff --git a/xs/xsp/SurfaceCollection.xsp b/xs/xsp/SurfaceCollection.xsp index e8ecd0028..d880ebcdb 100644 --- a/xs/xsp/SurfaceCollection.xsp +++ b/xs/xsp/SurfaceCollection.xsp @@ -74,5 +74,30 @@ SurfaceCollection::set_surface_type(index, surface_type) CODE: THIS->surfaces[index].surface_type = surface_type; +SV* +SurfaceCollection::group(merge_solid = false) + bool merge_solid + CODE: + // perform grouping + std::vector groups; + THIS->group(groups, merge_solid); + + // build return arrayref + AV* av = newAV(); + av_fill(av, groups.size()-1); + size_t i = 0; + for (std::vector::iterator it = groups.begin(); it != groups.end(); ++it) { + AV* innerav = newAV(); + av_fill(innerav, it->size()-1); + size_t j = 0; + for (SurfacesPtr::iterator it_s = it->begin(); it_s != it->end(); ++it_s) { + av_store(innerav, j++, (*it_s)->to_SV_clone_ref()); + } + av_store(av, i++, newRV_noinc((SV*)innerav)); + } + RETVAL = newRV_noinc((SV*)av); + OUTPUT: + RETVAL + %} };