Refactor cutting logic, don't slice in 3DScene

This commit is contained in:
Alessandro Ranellucci 2015-12-19 23:15:37 +01:00
parent 025a508de2
commit f7e97f7e9b
2 changed files with 89 additions and 71 deletions

View file

@ -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') {

View file

@ -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;