diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 36aa84db9..4ec4847d3 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -6,7 +6,7 @@ use utf8; use File::Basename qw(basename dirname); use List::Util qw(max sum first); use Slic3r::Geometry::Clipper qw(offset JT_ROUND); -use Slic3r::Geometry qw(X Y Z MIN MAX convex_hull); +use Slic3r::Geometry qw(X Y Z MIN MAX convex_hull scale unscale); use threads::shared qw(shared_clone); use Wx qw(:bitmap :brush :button :cursor :dialog :filedialog :font :keycode :icon :id :listctrl :misc :panel :pen :sizer :toolbar :window); use Wx::Event qw(EVT_BUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL EVT_CHOICE); @@ -395,7 +395,7 @@ sub load_file { instances => [ $model->objects->[$i]->instances ? (map $_->offset, @{$model->objects->[$i]->instances}) - : [0,0], + : Slic3r::Point->new(0,0), ], ); @@ -466,7 +466,8 @@ sub increase { my ($obj_idx, $object) = $self->selected_object; my $instances = $object->instances; - push @$instances, [ $instances->[-1]->[X] + 10, $instances->[-1]->[Y] + 10 ]; + push @$instances, my $new_instance = $instances->[-1]->clone; + $new_instance->translate(scale(10), scale(10)); $self->{list}->SetItem($obj_idx, 1, $object->instances_count); $self->arrange; } @@ -865,18 +866,19 @@ sub recenter { return unless @{$self->{objects}}; # calculate displacement needed to center the print - my $print_bb = Slic3r::Geometry::BoundingBox->new_from_points([ - map { - my $obj = $_; - my $bb = $obj->transformed_bounding_box; - my @points = ($bb->min_point, $bb->max_point); - map Slic3r::Geometry::move_points($_, @points), @{$obj->instances}; - } @{$self->{objects}}, - ]); + my @bbs = (); + foreach my $plobj (@{$self->{objects}}) { + my $bb = $plobj->transformed_bounding_box; # in scaled coordinates + foreach my $inst (@{$plobj->instances}) { + push @bbs, my $inst_bb = $bb->clone; + $inst_bb->translate(@$inst, 0); + } + } + my $print_bb = Slic3r::Geometry::BoundingBox->merge(@bbs); + my $print_size = $print_bb->size; # $self->{shift} contains the offset in pixels to add to object instances in order to center them # it is expressed in upwards Y - my $print_size = $print_bb->size; $self->{shift} = [ $self->to_pixel(-$print_bb->x_min) + ($self->{canvas}->GetSize->GetWidth - $self->to_pixel($print_size->[X])) / 2, $self->to_pixel(-$print_bb->y_min) + ($self->{canvas}->GetSize->GetHeight - $self->to_pixel($print_size->[Y])) / 2, @@ -915,6 +917,7 @@ sub _update_bed_size { # supposing the preview canvas is square, calculate the scaling factor # to constrain print bed area inside preview # when the canvas is not rendered yet, its GetSize() method returns 0,0 + # scaling_factor is expressed in pixel / mm $self->{scaling_factor} = CANVAS_SIZE->[X] / max(@{ $self->{config}->bed_size }); $_->thumbnail_scaling_factor($self->{scaling_factor}) for @{ $self->{objects} }; $self->recenter; @@ -974,9 +977,9 @@ sub repaint { my $instance = $object->instances->[$instance_idx]; my $thumbnail = $object->transformed_thumbnail->clone; - $thumbnail->translate(map $parent->to_pixel($instance->[$_]) + $parent->{shift}[$_], (X,Y)); - - push @{$parent->{object_previews}}, [ $obj_idx, $instance_idx, $thumbnail ]; + $thumbnail->translate(map $_ * $parent->{scaling_factor}, @$instance); + $thumbnail->translate(map scale($parent->{shift}[$_]), (X,Y)); + push @{$parent->{object_previews}}, [ $obj_idx, $instance_idx, $thumbnail ]; # $thumbnail has scaled coordinates my $drag_object = $self->{drag_object}; if (defined $drag_object && $obj_idx == $drag_object->[0] && $instance_idx == $drag_object->[1]) { @@ -986,26 +989,39 @@ sub repaint { } else { $dc->SetBrush($parent->{objects_brush}); } - $dc->DrawPolygon($parent->_y($_), 0, 0) for map $_->contour->pp, @{ $parent->{object_previews}->[-1][2] }; + foreach my $expolygon (@$thumbnail) { + my $points = $expolygon->contour->pp; + foreach my $point (@$points) { + $point->[X] *= &Slic3r::SCALING_FACTOR; + $point->[Y] *= &Slic3r::SCALING_FACTOR; + } + $dc->DrawPolygon($parent->_y($points), 0, 0); + } # if sequential printing is enabled and we have more than one object if ($parent->{config}->complete_objects && (map @{$_->instances}, @{$parent->{objects}}) > 1) { - my $convex_hull = convex_hull([ map @{$_->contour}, @{$parent->{object_previews}->[-1][2]} ]); - my ($clearance) = @{offset([$convex_hull], $parent->{config}->extruder_clearance_radius / 2 * $parent->{scaling_factor}, 100, JT_ROUND)}; - $dc->SetPen($parent->{clearance_pen}); - $dc->SetBrush($parent->{transparent_brush}); - $dc->DrawPolygon($parent->_y($clearance), 0, 0); + my @points = map @{$_->contour}, @{$parent->{object_previews}->[-1][2]}; + if (@points >= 3) { + my ($clearance) = @{offset([convex_hull(\@points)], scale($parent->{config}->extruder_clearance_radius / 2) * $parent->{scaling_factor}, 100, JT_ROUND)}; + $clearance->scale(&Slic3r::SCALING_FACTOR); + $dc->SetPen($parent->{clearance_pen}); + $dc->SetBrush($parent->{transparent_brush}); + $dc->DrawPolygon($parent->_y($clearance), 0, 0); + } } } } # draw skirt if (@{$parent->{object_previews}} && $parent->{config}->skirts) { - my $convex_hull = convex_hull([ map @{$_->contour}, map @{$_->[2]}, @{$parent->{object_previews}} ]); - ($convex_hull) = @{offset([$convex_hull], $parent->{config}->skirt_distance * $parent->{scaling_factor}, 100, JT_ROUND)}; - $dc->SetPen($parent->{skirt_pen}); - $dc->SetBrush($parent->{transparent_brush}); - $dc->DrawPolygon($parent->_y($convex_hull), 0, 0) if $convex_hull; + my @points = map @{$_->contour}, map @{$_->[2]}, @{$parent->{object_previews}}; + if (@points >= 3) { + my ($convex_hull) = @{offset([convex_hull(\@points)], scale($parent->{config}->skirt_distance) * $parent->{scaling_factor}, 1, JT_ROUND)}; + $convex_hull->scale(&Slic3r::SCALING_FACTOR); + $dc->SetPen($parent->{skirt_pen}); + $dc->SetBrush($parent->{transparent_brush}); + $dc->DrawPolygon($parent->_y($convex_hull), 0, 0); + } } $event->Skip; @@ -1016,7 +1032,7 @@ sub mouse_event { my $parent = $self->GetParent; my $point = $event->GetPosition; - my $pos = Slic3r::Point->new(map @$_, map @$_, $parent->_y([[$point->x, $point->y]])); #]] + my $pos = Slic3r::Point->new_scale(@{$parent->_y([[$point->x, $point->y]])->[0]}); #]] in scaled pixels if ($event->ButtonDown(&Wx::wxMOUSE_BTN_LEFT)) { $parent->{selected_objects} = []; $parent->{list}->Select($parent->{list}->GetFirstSelected, 0); @@ -1028,7 +1044,7 @@ sub mouse_event { $parent->{list}->Select($obj_idx, 1); $parent->selection_changed(1); my $instance = $parent->{objects}[$obj_idx]->instances->[$instance_idx]; - $self->{drag_start_pos} = [ map $pos->[$_] - $parent->{shift}[$_] - $parent->to_pixel($instance->[$_]), X,Y ]; # displacement between the click and the instance origin + $self->{drag_start_pos} = [ map $pos->[$_] - scale($parent->{shift}[$_]) - scale($parent->to_pixel($instance->[$_])), X,Y ]; # displacement between the click and the instance origin $self->{drag_object} = $preview; } } @@ -1045,8 +1061,9 @@ sub mouse_event { return if !$self->{drag_start_pos}; # concurrency problems for my $preview ($self->{drag_object}) { my ($obj_idx, $instance_idx, $thumbnail) = @$preview; - my $instance = $parent->{objects}[$obj_idx]->instances->[$instance_idx]; - $instance->[$_] = $parent->to_units($pos->[$_] - $self->{drag_start_pos}[$_] - $parent->{shift}[$_]) for X,Y; + $parent->{objects}[$obj_idx]->instances->[$instance_idx] = Slic3r::Point->new( + map { $parent->to_units(unscale($pos->[$_] - $self->{drag_start_pos}[$_]) - $parent->{shift}[$_]) } (X,Y), + ); $parent->Refresh; } } elsif ($event->Moving) { @@ -1155,7 +1172,7 @@ sub selection_changed { if ($self->{object_info_size}) { # have we already loaded the info pane? if ($have_sel) { my ($obj_idx, $object) = $self->selected_object; - $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", @{$object->transformed_size})); + $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", map unscale($_), @{$object->transformed_size})); $self->{object_info_materials}->SetLabel($object->materials); if (my $stats = $object->mesh_stats) { @@ -1209,12 +1226,12 @@ sub statusbar { sub to_pixel { my $self = shift; - return $_[0] * $self->{scaling_factor}; + return $_[0] * $self->{scaling_factor} * &Slic3r::SCALING_FACTOR; } sub to_units { my $self = shift; - return $_[0] / $self->{scaling_factor}; + return $_[0] / $self->{scaling_factor} / &Slic3r::SCALING_FACTOR; } sub _y { @@ -1261,8 +1278,8 @@ has 'input_file' => (is => 'rw', required => 1); has 'input_file_object_id' => (is => 'rw'); # undef means keep model object has 'model' => (is => 'rw', required => 1, trigger => \&_trigger_model_object); has 'model_object_idx' => (is => 'rw', required => 1, trigger => \&_trigger_model_object); -has 'bounding_box' => (is => 'rw'); # 3D bb of original object (aligned to origin) with no rotation or scaling -has 'convex_hull' => (is => 'rw'); # 2D convex hull of original object (aligned to origin) with no rotation or scaling +has 'bounding_box' => (is => 'rw'); # scaled 3D bb of original object (aligned to origin) with no rotation or scaling +has 'convex_hull' => (is => 'rw'); # scaled 2D convex hull of original object (aligned to origin) with no rotation or scaling has 'scale' => (is => 'rw', default => sub { 1 }, trigger => \&_transform_thumbnail); has 'rotate' => (is => 'rw', default => sub { 0 }, trigger => \&_transform_thumbnail); # around object center point has 'instances' => (is => 'rw', default => sub { [] }); # upward Y axis @@ -1286,6 +1303,7 @@ sub _trigger_model_object { my $model_object = $self->model->objects->[$self->model_object_idx]; $model_object->align_to_origin; $self->bounding_box($model_object->bounding_box); + $self->bounding_box->scale(1 / &Slic3r::SCALING_FACTOR); my $mesh = $model_object->mesh; $mesh->repair; @@ -1363,13 +1381,10 @@ sub make_thumbnail { ); $self->thumbnail->simplify(0.5); } else { - my $convex_hull = Slic3r::ExPolygon->new($self->convex_hull)->clone; - $convex_hull->scale(1/&Slic3r::SCALING_FACTOR); + my $convex_hull = Slic3r::ExPolygon->new($self->convex_hull); $self->thumbnail->append($convex_hull); } - $self->thumbnail->scale(&Slic3r::SCALING_FACTOR); - return $self->thumbnail; } diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 3bddb6824..e6529ecdc 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -480,6 +480,6 @@ use Moo; has 'object' => (is => 'ro', weak_ref => 1, required => 1); has 'rotation' => (is => 'rw', default => sub { 0 }); # around mesh center point has 'scaling_factor' => (is => 'rw', default => sub { 1 }); -has 'offset' => (is => 'rw'); # must be Slic3r::Point object +has 'offset' => (is => 'rw'); # must be Slic3r::Point object in scaled coordinates 1; diff --git a/xs/src/Geometry.cpp b/xs/src/Geometry.cpp index 748340542..26ceeabd6 100644 --- a/xs/src/Geometry.cpp +++ b/xs/src/Geometry.cpp @@ -17,7 +17,7 @@ sort_points (Point a, Point b) void convex_hull(Points points, Polygon &hull) { - assert(points.size() >= 2); + assert(points.size() >= 3); // sort input points std::sort(points.begin(), points.end(), sort_points); diff --git a/xs/src/TriangleMesh.cpp b/xs/src/TriangleMesh.cpp index 689bb7407..b08e7cb5e 100644 --- a/xs/src/TriangleMesh.cpp +++ b/xs/src/TriangleMesh.cpp @@ -606,7 +606,7 @@ TriangleMesh::convex_hull(Polygon &hull) Points pp; pp.reserve(this->stl.stats.shared_vertices); for (int i = 0; i < this->stl.stats.shared_vertices; i++) { - stl_vertex* v = this->stl.v_shared; + stl_vertex* v = &this->stl.v_shared[i]; pp.push_back(Point(v->x / SCALING_FACTOR, v->y / SCALING_FACTOR)); } Slic3r::Geometry::convex_hull(pp, hull);