diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index dd5929ad..0b850ac6 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1270,7 +1270,7 @@ sub _trigger_model_object { my $mesh = $model_object->mesh; $mesh->repair; - $self->convex_hull(Slic3r::Polygon->new(@{Math::ConvexHull::MonotoneChain::convex_hull($mesh->used_vertices)})); + $self->convex_hull(Slic3r::Polygon->new(@{Math::ConvexHull::MonotoneChain::convex_hull($mesh->vertices)})); $self->facets(scalar @{$mesh->facets}); $self->vertices(scalar @{$mesh->vertices}); diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index abe00f20..6e77e9b4 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -5,7 +5,7 @@ use warnings; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw( - PI X Y Z A B X1 Y1 X2 Y2 MIN MAX epsilon slope line_atan lines_parallel + PI X Y Z A B X1 Y1 X2 Y2 Z1 Z2 MIN MAX epsilon slope line_atan lines_parallel line_point_belongs_to_segment points_coincide distance_between_points chained_path_items chained_path_points normalize tan move_points_3D line_length midpoint point_in_polygon point_in_segment segment_in_segment @@ -35,6 +35,8 @@ use constant X1 => 0; use constant Y1 => 1; use constant X2 => 2; use constant Y2 => 3; +use constant Z1 => 4; +use constant Z2 => 5; use constant MIN => 0; use constant MAX => 1; our $parallel_degrees_limit = abs(deg2rad(0.1)); diff --git a/lib/Slic3r/Geometry/BoundingBox.pm b/lib/Slic3r/Geometry/BoundingBox.pm index 67b77da8..27d6fd27 100644 --- a/lib/Slic3r/Geometry/BoundingBox.pm +++ b/lib/Slic3r/Geometry/BoundingBox.pm @@ -1,6 +1,8 @@ package Slic3r::Geometry::BoundingBox; use Moo; -use Slic3r::Geometry qw(X Y Z MIN MAX X1 Y1 X2 Y2); + +use List::Util qw(min max); +use Slic3r::Geometry qw(X Y Z MIN MAX X1 Y1 X2 Y2 Z1 Z2); use Storable qw(); has 'extents' => (is => 'ro', required => 1); @@ -19,6 +21,18 @@ sub new_from_points { ]); } +# 2D/3D +sub new_from_bb { + my $class = shift; + my ($bb) = @_; + + return $class->new(extents => [ + [ $bb->[X1], $bb->[X2] ], + [ $bb->[Y1], $bb->[Y2] ], + (@$bb == 6) ? [ $bb->[Z1], $bb->[Z2] ] : (), + ]); +} + # 3D sub new_from_points_3D { my $class = shift; @@ -27,6 +41,24 @@ sub new_from_points_3D { return $class->new(extents => [ Slic3r::Geometry::bounding_box_3D($points) ]); } +sub merge { + my $class = shift; + my (@bounding_boxes) = @_; + + my $self = ref($class) + ? $class + : shift @bounding_boxes; + + foreach my $bounding_box (@bounding_boxes) { + for my $axis (X .. $#{$self->extents}) { + $self->extents->[$axis][MIN] = min($self->extents->[$axis][MIN], $bounding_box->extents->[$axis][MIN]); + $self->extents->[$axis][MAX] = max($self->extents->[$axis][MAX], $bounding_box->extents->[$axis][MAX]); + } + } + + return $self; +} + # four-arguments 2D bb sub bb { my $self = shift; diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 2052df8b..2be84e22 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -159,16 +159,6 @@ sub _arrange { } } -sub vertices { - my $self = shift; - return [ map @{$_->vertices}, @{$self->objects} ]; -} - -sub used_vertices { - my $self = shift; - return [ map @{$_->used_vertices}, @{$self->objects} ]; -} - sub size { my $self = shift; return $self->bounding_box->size; @@ -178,7 +168,7 @@ sub bounding_box { my $self = shift; if (!defined $self->_bounding_box) { - $self->_bounding_box(Slic3r::Geometry::BoundingBox->new_from_points_3D($self->used_vertices)); + $self->_bounding_box(Slic3r::Geometry::BoundingBox->merge(map $_->bounding_box, @{$self->objects})); } return $self->_bounding_box; } @@ -352,11 +342,6 @@ sub mesh { return $mesh; } -sub used_vertices { - my $self = shift; - return [ map $_->mesh->used_vertices, @{$self->volumes} ]; -} - sub size { my $self = shift; return $self->bounding_box->size; @@ -376,8 +361,10 @@ sub bounding_box { my $self = shift; if (!defined $self->_bounding_box) { - # TODO: calculate bb in XS - $self->_bounding_box(Slic3r::Geometry::BoundingBox->new_from_points_3D(map $_->mesh->vertices, @{$self->volumes})); + my @meshes = map $_->mesh, @{$self->volumes}; + my $bounding_box = Slic3r::Geometry::BoundingBox->new_from_bb((shift @meshes)->bb3); + $bounding_box->merge(Slic3r::Geometry::BoundingBox->new_from_bb($_->bb3)) for @meshes; + $self->_bounding_box($bounding_box); } return $self->_bounding_box; } diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index dd43a7b3..a8235478 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -144,7 +144,7 @@ sub add_model { # we also align object after transformations so that we only work with positive coordinates # and the assumption that bounding_box === size works - my $bb = Slic3r::Geometry::BoundingBox->new_from_points_3D([ map @{$_->used_vertices}, grep $_, @meshes ]); + my $bb = Slic3r::Geometry::BoundingBox->merge(map $_->bounding_box, grep $_, @meshes); my @align2 = map -$bb->extents->[$_][MIN], (X,Y,Z); $_->translate(@align2) for grep $_, @meshes; diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 7d1575d6..2519aa8a 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -144,15 +144,13 @@ sub slice { # process facets for my $region_id (0 .. $#{$self->meshes}) { my $mesh = $self->meshes->[$region_id] // next; # ignore undef meshes + $mesh->repair; { - my $m = Slic3r::TriangleMesh->new; - $m->ReadFromPerl($mesh->vertices, $mesh->facets); - $m->repair; - my $lines = $m->slice([ map $_->slice_z, @{$self->layers} ]); - for my $layer_id (0..$#$lines) { + my $loops = $mesh->slice([ map $_->slice_z, @{$self->layers} ]); + for my $layer_id (0..$#$loops) { my $layerm = $self->layers->[$layer_id]->regions->[$region_id]; - $layerm->make_surfaces($lines->[$layer_id]); + $layerm->make_surfaces($loops->[$layer_id]); } # TODO: read slicing_errors } diff --git a/lib/Slic3r/TriangleMesh.pm b/lib/Slic3r/TriangleMesh.pm index 434b5ada..c0f37137 100644 --- a/lib/Slic3r/TriangleMesh.pm +++ b/lib/Slic3r/TriangleMesh.pm @@ -19,11 +19,6 @@ sub center { return $self->bounding_box->center; } -sub used_vertices { - my $self = shift; - return $self->vertices; -} - sub facets_count { my $self = shift; return $self->stats->{number_of_facets}; @@ -31,7 +26,7 @@ sub facets_count { sub bounding_box { my $self = shift; - return Slic3r::Geometry::BoundingBox->new_from_points_3D($self->used_vertices); + return Slic3r::Geometry::BoundingBox->new_from_bb($self->bb3); } # this will return *scaled* expolygons, so it is expected to be run diff --git a/t/print.t b/t/print.t index 485ad12b..743c06dc 100644 --- a/t/print.t +++ b/t/print.t @@ -13,7 +13,7 @@ use Slic3r::Test; { my $print = Slic3r::Test::init_print('20mm_cube', rotation => 45); - ok !(first { $_ < 0 } map @$_, map @{$_->used_vertices}, grep $_, map @{$_->meshes}, @{$print->objects}), + ok !(first { $_ < 0 } map @$_, map @{$_->vertices}, grep $_, map @{$_->meshes}, @{$print->objects}), "object is still in positive coordinate space even after rotation"; } diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index df0b827b..b05c9b0f 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -126,6 +126,18 @@ TriangleMesh::slice(z) OUTPUT: RETVAL +std::vector +TriangleMesh::bb3() + CODE: + RETVAL.push_back(THIS->stl.stats.min.x); + RETVAL.push_back(THIS->stl.stats.min.y); + RETVAL.push_back(THIS->stl.stats.max.x); + RETVAL.push_back(THIS->stl.stats.max.y); + RETVAL.push_back(THIS->stl.stats.min.z); + RETVAL.push_back(THIS->stl.stats.max.z); + OUTPUT: + RETVAL + %} };