Refactor cutting logic, don't slice in 3DScene
This commit is contained in:
parent
025a508de2
commit
f7e97f7e9b
2 changed files with 89 additions and 71 deletions
|
@ -13,7 +13,6 @@ use Slic3r::Geometry::Clipper qw(offset_ex intersection_pl);
|
|||
use Wx::GLCanvas qw(:all);
|
||||
|
||||
__PACKAGE__->mk_accessors( qw(_quat _dirty init
|
||||
enable_cutting
|
||||
enable_picking
|
||||
enable_moving
|
||||
on_viewport_changed
|
||||
|
@ -319,7 +318,9 @@ sub bed_bounding_box {
|
|||
my ($self) = @_;
|
||||
|
||||
my $bb = Slic3r::Geometry::BoundingBoxf3->new;
|
||||
$bb->merge_point(Slic3r::Pointf3->new(@$_, 0)) for @{$self->bed_shape};
|
||||
if ($self->bed_shape) {
|
||||
$bb->merge_point(Slic3r::Pointf3->new(@$_, 0)) for @{$self->bed_shape};
|
||||
}
|
||||
return $bb;
|
||||
}
|
||||
|
||||
|
@ -402,25 +403,19 @@ sub select_volume {
|
|||
}
|
||||
|
||||
sub SetCuttingPlane {
|
||||
my ($self, $z) = @_;
|
||||
my ($self, $z, $expolygons) = @_;
|
||||
|
||||
$self->cutting_plane_z($z);
|
||||
|
||||
# perform cut and cache section lines
|
||||
# grow slices in order to display them better
|
||||
$expolygons = offset_ex([ map @$_, @$expolygons ], scale 0.1);
|
||||
|
||||
my @verts = ();
|
||||
foreach my $volume (@{$self->volumes}) {
|
||||
foreach my $volume (@{$self->volumes}) {
|
||||
next if !$volume->mesh;
|
||||
my $expolygons = $volume->mesh->slice([ $z - $volume->origin->z ])->[0];
|
||||
$expolygons = offset_ex([ map @$_, @$expolygons ], scale 0.1);
|
||||
|
||||
foreach my $line (map @{$_->lines}, map @$_, @$expolygons) {
|
||||
push @verts, (
|
||||
unscale($line->a->x), unscale($line->a->y), $z, #))
|
||||
unscale($line->b->x), unscale($line->b->y), $z, #))
|
||||
);
|
||||
}
|
||||
}
|
||||
foreach my $line (map @{$_->lines}, map @$_, @$expolygons) {
|
||||
push @verts, (
|
||||
unscale($line->a->x), unscale($line->a->y), $z, #))
|
||||
unscale($line->b->x), unscale($line->b->y), $z, #))
|
||||
);
|
||||
}
|
||||
$self->cut_lines_vertices(OpenGL::Array->new_list(GL_FLOAT, @verts));
|
||||
}
|
||||
|
@ -999,7 +994,6 @@ sub load_object {
|
|||
bounding_box => $mesh->bounding_box,
|
||||
color => $color,
|
||||
);
|
||||
$v->mesh($mesh) if $self->enable_cutting;
|
||||
if ($self->select_by eq 'object') {
|
||||
$v->select_group_id($obj_idx*1000000);
|
||||
} elsif ($self->select_by eq 'volume') {
|
||||
|
|
|
@ -4,7 +4,7 @@ use warnings;
|
|||
use utf8;
|
||||
|
||||
use Slic3r::Geometry qw(PI X);
|
||||
use Wx qw(:dialog :id :misc :sizer wxTAB_TRAVERSAL);
|
||||
use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL);
|
||||
use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
|
||||
use base 'Wx::Dialog';
|
||||
|
||||
|
@ -33,7 +33,9 @@ sub new {
|
|||
my ($opt_id) = @_;
|
||||
|
||||
$self->{cut_options}{$opt_id} = $optgroup->get_value($opt_id);
|
||||
$self->_update;
|
||||
wxTheApp->CallAfter(sub {
|
||||
$self->_update;
|
||||
});
|
||||
},
|
||||
label_width => 120,
|
||||
);
|
||||
|
@ -95,7 +97,6 @@ sub new {
|
|||
my $canvas;
|
||||
if ($Slic3r::GUI::have_OpenGL) {
|
||||
$canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self);
|
||||
$canvas->enable_cutting(1);
|
||||
$canvas->load_object($self->{model_object}, undef, [0]);
|
||||
$canvas->set_auto_bed_shape;
|
||||
$canvas->SetSize([500,500]);
|
||||
|
@ -112,7 +113,16 @@ sub new {
|
|||
$self->{sizer}->SetSizeHints($self);
|
||||
|
||||
EVT_BUTTON($self, $self->{btn_cut}, sub {
|
||||
$self->perform_cut(1);
|
||||
if ($self->{new_model_objects}{lower}) {
|
||||
if ($self->{cut_options}{rotate_lower}) {
|
||||
$self->{new_model_objects}{lower}->rotate(PI, X);
|
||||
$self->{new_model_objects}{lower}->center_around_origin; # align to Z = 0
|
||||
}
|
||||
}
|
||||
if ($self->{new_model_objects}{upper}) {
|
||||
$self->{new_model_objects}{upper}->center_around_origin; # align to Z = 0
|
||||
}
|
||||
|
||||
$self->EndModal(wxID_OK);
|
||||
$self->Close;
|
||||
});
|
||||
|
@ -125,66 +135,80 @@ sub new {
|
|||
sub _update {
|
||||
my ($self) = @_;
|
||||
|
||||
my $optgroup = $self->{optgroup};
|
||||
|
||||
# update canvas
|
||||
if ($self->{canvas}) {
|
||||
my @objects = ();
|
||||
if ($self->{cut_options}{preview}) {
|
||||
$self->perform_cut;
|
||||
push @objects, @{$self->{new_model_objects}};
|
||||
} else {
|
||||
push @objects, $self->{model_object};
|
||||
{
|
||||
# scale Z down to original size since we're using the transformed mesh for 3D preview
|
||||
# and cut dialog but ModelObject::cut() needs Z without any instance transformation
|
||||
my $z = $self->{cut_options}{z} / $self->{model_object}->instances->[0]->scaling_factor;
|
||||
|
||||
{
|
||||
my ($new_model) = $self->{model_object}->cut($z);
|
||||
my ($upper_object, $lower_object) = @{$new_model->objects};
|
||||
$self->{new_model} = $new_model;
|
||||
$self->{new_model_objects} = {};
|
||||
if ($self->{cut_options}{keep_upper} && $upper_object->volumes_count > 0) {
|
||||
$self->{new_model_objects}{upper} = $upper_object;
|
||||
}
|
||||
if ($self->{cut_options}{keep_lower} && $lower_object->volumes_count > 0) {
|
||||
$self->{new_model_objects}{lower} = $lower_object;
|
||||
}
|
||||
}
|
||||
|
||||
# update canvas
|
||||
if ($self->{canvas}) {
|
||||
# get volumes to render
|
||||
my @objects = ();
|
||||
if ($self->{cut_options}{preview}) {
|
||||
push @objects, values %{$self->{new_model_objects}};
|
||||
} else {
|
||||
push @objects, $self->{model_object};
|
||||
}
|
||||
|
||||
# get section contour
|
||||
my @expolygons = ();
|
||||
foreach my $volume (@{$self->{model_object}->volumes}) {
|
||||
next if !$volume->mesh;
|
||||
next if $volume->modifier;
|
||||
my $expp = $volume->mesh->slice([ $z + $volume->mesh->bounding_box->z_min ])->[0];
|
||||
push @expolygons, @$expp;
|
||||
}
|
||||
foreach my $expolygon (@expolygons) {
|
||||
$self->{model_object}->instances->[0]->transform_polygon($_)
|
||||
for @$expolygon;
|
||||
$expolygon->translate(map Slic3r::Geometry::scale($_), @{ $self->{model_object}->instances->[0]->offset });
|
||||
}
|
||||
|
||||
$self->{canvas}->reset_objects;
|
||||
$self->{canvas}->load_object($_, undef, [0]) for @objects;
|
||||
$self->{canvas}->SetCuttingPlane(
|
||||
$self->{cut_options}{z},
|
||||
[@expolygons],
|
||||
);
|
||||
$self->{canvas}->Render;
|
||||
}
|
||||
$self->{canvas}->reset_objects;
|
||||
$self->{canvas}->load_object($_, undef, [0]) for @objects;
|
||||
$self->{canvas}->SetCuttingPlane($self->{cut_options}{z});
|
||||
$self->{canvas}->Render;
|
||||
}
|
||||
|
||||
# update controls
|
||||
my $z = $self->{cut_options}{z};
|
||||
$optgroup->get_field('keep_upper')->toggle(my $have_upper = abs($z - $optgroup->get_option('z')->max) > 0.1);
|
||||
$optgroup->get_field('keep_lower')->toggle(my $have_lower = $z > 0.1);
|
||||
$optgroup->get_field('rotate_lower')->toggle($z > 0 && $self->{cut_options}{keep_lower});
|
||||
$optgroup->get_field('preview')->toggle($self->{cut_options}{keep_upper} != $self->{cut_options}{keep_lower});
|
||||
{
|
||||
my $z = $self->{cut_options}{z};
|
||||
my $optgroup = $self->{optgroup};
|
||||
$optgroup->get_field('keep_upper')->toggle(my $have_upper = abs($z - $optgroup->get_option('z')->max) > 0.1);
|
||||
$optgroup->get_field('keep_lower')->toggle(my $have_lower = $z > 0.1);
|
||||
$optgroup->get_field('rotate_lower')->toggle($z > 0 && $self->{cut_options}{keep_lower});
|
||||
$optgroup->get_field('preview')->toggle($self->{cut_options}{keep_upper} != $self->{cut_options}{keep_lower});
|
||||
|
||||
# update cut button
|
||||
if (($self->{cut_options}{keep_upper} && $have_upper)
|
||||
|| ($self->{cut_options}{keep_lower} && $have_lower)) {
|
||||
$self->{btn_cut}->Enable;
|
||||
} else {
|
||||
$self->{btn_cut}->Disable;
|
||||
}
|
||||
}
|
||||
|
||||
sub perform_cut {
|
||||
my ($self, $final) = @_;
|
||||
|
||||
# scale Z down to original size since we're using the transformed mesh for 3D preview
|
||||
# and cut dialog but ModelObject::cut() needs Z without any instance transformation
|
||||
my $z = $self->{cut_options}{z} / $self->{model_object}->instances->[0]->scaling_factor;
|
||||
|
||||
my ($new_model) = $self->{model_object}->cut($z);
|
||||
my ($upper_object, $lower_object) = @{$new_model->objects};
|
||||
$self->{new_model} = $new_model;
|
||||
$self->{new_model_objects} = [];
|
||||
if ($self->{cut_options}{keep_upper} && $upper_object->volumes_count > 0) {
|
||||
$upper_object->center_around_origin if $final; # align to Z = 0
|
||||
push @{$self->{new_model_objects}}, $upper_object;
|
||||
}
|
||||
if ($self->{cut_options}{keep_lower} && $lower_object->volumes_count > 0) {
|
||||
push @{$self->{new_model_objects}}, $lower_object;
|
||||
if ($self->{cut_options}{rotate_lower} && $final) {
|
||||
$lower_object->rotate(PI, X);
|
||||
$lower_object->center_around_origin; # align to Z = 0
|
||||
# update cut button
|
||||
if (($self->{cut_options}{keep_upper} && $have_upper)
|
||||
|| ($self->{cut_options}{keep_lower} && $have_lower)) {
|
||||
$self->{btn_cut}->Enable;
|
||||
} else {
|
||||
$self->{btn_cut}->Disable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub NewModelObjects {
|
||||
my ($self) = @_;
|
||||
return @{ $self->{new_model_objects} };
|
||||
return values %{ $self->{new_model_objects} };
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
Loading…
Reference in a new issue