Initial work for a GUI for the cut feature

This commit is contained in:
Alessandro Ranellucci 2014-04-25 14:54:08 +02:00
parent 334bc4c581
commit 882a98ed44
6 changed files with 215 additions and 10 deletions

View File

@ -9,6 +9,7 @@ use Slic3r::GUI::AboutDialog;
use Slic3r::GUI::ConfigWizard;
use Slic3r::GUI::Plater;
use Slic3r::GUI::Plater::ObjectPartsPanel;
use Slic3r::GUI::Plater::ObjectCutDialog;
use Slic3r::GUI::Plater::ObjectPreviewDialog;
use Slic3r::GUI::Plater::ObjectSettingsDialog;
use Slic3r::GUI::Plater::OverrideSettingsPanel;

View File

@ -77,7 +77,9 @@ sub BUILD {
$self->sizer->Add($grid_sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 5);
foreach my $line (@{$self->lines}) {
if ($line->{widget}) {
if ($line->{sizer}) {
$self->sizer->Add($line->{sizer}, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15);
} elsif ($line->{widget}) {
my $window = $line->{widget}->GetWindow($self->parent);
$self->sizer->Add($window, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15);
} else {

View File

@ -86,7 +86,7 @@ sub new {
$self->{htoolbar}->AddTool(TB_SCALE, "Scale…", Wx::Bitmap->new("$Slic3r::var/arrow_out.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_SPLIT, "Split", Wx::Bitmap->new("$Slic3r::var/shape_ungroup.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddSeparator;
$self->{htoolbar}->AddTool(TB_VIEW, "View", Wx::Bitmap->new("$Slic3r::var/package.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_VIEW, "View/Cut…", Wx::Bitmap->new("$Slic3r::var/package.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_SETTINGS, "Settings…", Wx::Bitmap->new("$Slic3r::var/cog.png", wxBITMAP_TYPE_PNG), '');
} else {
my %tbar_buttons = (
@ -101,7 +101,7 @@ sub new {
rotate => "Rotate…",
changescale => "Scale…",
split => "Split",
view => "View",
view => "View/Cut…",
settings => "Settings…",
);
$self->{btoolbar} = Wx::BoxSizer->new(wxHORIZONTAL);
@ -173,7 +173,7 @@ sub new {
EVT_TOOL($self, TB_ROTATE, sub { $_[0]->rotate(undef) });
EVT_TOOL($self, TB_SCALE, \&changescale);
EVT_TOOL($self, TB_SPLIT, \&split_object);
EVT_TOOL($self, TB_VIEW, sub { $_[0]->object_preview_dialog });
EVT_TOOL($self, TB_VIEW, sub { $_[0]->object_cut_dialog });
EVT_TOOL($self, TB_SETTINGS, sub { $_[0]->object_settings_dialog });
} else {
EVT_BUTTON($self, $self->{btn_add}, \&add);
@ -187,7 +187,7 @@ sub new {
EVT_BUTTON($self, $self->{btn_changescale}, \&changescale);
EVT_BUTTON($self, $self->{btn_rotate}, sub { $_[0]->rotate(undef) });
EVT_BUTTON($self, $self->{btn_split}, \&split_object);
EVT_BUTTON($self, $self->{btn_view}, sub { $_[0]->object_preview_dialog });
EVT_BUTTON($self, $self->{btn_view}, sub { $_[0]->object_cut_dialog });
EVT_BUTTON($self, $self->{btn_settings}, sub { $_[0]->object_settings_dialog });
}
@ -1149,7 +1149,7 @@ sub list_item_activated {
$self->object_preview_dialog($obj_idx);
}
sub object_preview_dialog {
sub object_cut_dialog {
my $self = shift;
my ($obj_idx) = @_;
@ -1162,11 +1162,16 @@ sub object_preview_dialog {
return;
}
my $dlg = Slic3r::GUI::Plater::ObjectPreviewDialog->new($self,
object => $self->{objects}[$obj_idx],
model_object => $self->{model}->objects->[$obj_idx],
my $dlg = Slic3r::GUI::Plater::ObjectCutDialog->new($self,
object => $self->{objects}[$obj_idx],
model_object => $self->{model}->objects->[$obj_idx],
);
$dlg->ShowModal;
if (my @new_objects = $dlg->NewModelObjects) {
$self->remove($obj_idx);
$self->load_model_objects(@new_objects);
}
}
sub object_settings_dialog {

View File

@ -0,0 +1,126 @@
package Slic3r::GUI::Plater::ObjectCutDialog;
use strict;
use warnings;
use utf8;
use Wx qw(:dialog :id :misc :sizer wxTAB_TRAVERSAL);
use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
use base 'Wx::Dialog';
sub new {
my $class = shift;
my ($parent, %params) = @_;
my $self = $class->SUPER::new($parent, -1, $params{object}->name, wxDefaultPosition, [500,500], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
$self->{model_object_idx} = $params{model_object_idx};
$self->{model_object} = $params{model_object};
$self->{new_model_objects} = [];
# cut options
$self->{cut_options} = {
z => 0,
keep_upper => 1,
keep_lower => 1,
};
my $cut_button_sizer = Wx::BoxSizer->new(wxVERTICAL);
{
$self->{btn_cut} = Wx::Button->new($self, -1, "Perform cut", wxDefaultPosition, wxDefaultSize);
$cut_button_sizer->Add($self->{btn_cut}, 0, wxALIGN_RIGHT | wxALL, 10);
}
my $optgroup = Slic3r::GUI::OptionsGroup->new(
parent => $self,
title => 'Cut',
options => [
{
opt_key => 'z',
type => 'f',
label => 'Z',
default => $self->{cut_options}{z},
},
{
opt_key => 'keep_upper',
type => 'bool',
label => 'Upper part',
default => $self->{cut_options}{keep_upper},
},
{
opt_key => 'keep_lower',
type => 'bool',
label => 'Lower part',
default => $self->{cut_options}{keep_lower},
},
],
lines => [
{
label => 'Z',
options => [qw(z)],
},
{
label => 'Keep',
options => [qw(keep_upper keep_lower)],
},
{
sizer => $cut_button_sizer,
},
],
on_change => sub {
my ($opt_key, $value) = @_;
$self->{cut_options}{$opt_key} = $value;
if ($opt_key eq 'z') {
if ($self->{canvas}) {
$self->{canvas}->SetCuttingPlane($value);
$self->{canvas}->Render;
}
}
},
label_width => 50,
);
# left pane with tree
my $left_sizer = Wx::BoxSizer->new(wxVERTICAL);
$left_sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
# right pane with preview canvas
my $canvas;
if ($Slic3r::GUI::have_OpenGL) {
$canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self, $self->{model_object});
$canvas->SetSize([500,500]);
$canvas->SetMinSize($canvas->GetSize);
}
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
$self->{sizer}->Add($left_sizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
$self->{sizer}->Add($canvas, 1, wxEXPAND | wxALL, 0) if $canvas;
$self->SetSizer($self->{sizer});
$self->SetMinSize($self->GetSize);
$self->{sizer}->SetSizeHints($self);
# needed to actually free memory
EVT_CLOSE($self, sub {
$self->EndModal(wxID_OK);
$self->Destroy;
});
EVT_BUTTON($self, $self->{btn_cut}, sub { $self->perform_cut });
return $self;
}
sub perform_cut {
my ($self) = @_;
my ($upper_object, $lower_object) = $self->{model_object}->cut($self->{cut_options}{z});
$self->{new_model_objects} = [];
push @{$self->{new_model_objects}}, $upper_object
if $self->{cut_options}{keep_upper} && defined $upper_object;
push @{$self->{new_model_objects}}, $lower_object
if $self->{cut_options}{keep_lower} && defined $lower_object;
}
sub NewModelObjects {
my ($self) = @_;
return @{ $self->{new_model_objects} };
}
1;

View File

@ -14,7 +14,9 @@ use Wx::GLCanvas qw(:all);
__PACKAGE__->mk_accessors( qw(quat dirty init mview_init
object_bounding_box object_shift
volumes initpos
sphi stheta) );
sphi stheta
cutting_plane_z
) );
use constant TRACKBALLSIZE => 0.8;
use constant TURNTABLE_MODE => 1;
@ -114,6 +116,11 @@ sub load_object {
}
}
sub SetCuttingPlane {
my ($self, $z) = @_;
$self->cutting_plane_z($z);
}
# Given an axis and angle, compute quaternion.
sub axis_to_quat {
my ($ax, $phi) = @_;
@ -440,6 +447,23 @@ sub Render {
glVertex3f($axis_len, $y, $ground_z);
}
glEnd();
# draw cutting plane
if (defined $self->cutting_plane_z) {
my $plane_z = $z0 + $self->cutting_plane_z;
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUADS);
glColor4f(1, 0.8, 0.8, 0.5);
glVertex3f(-$axis_len, -$axis_len, $plane_z);
glVertex3f($axis_len, -$axis_len, $plane_z);
glVertex3f($axis_len, $axis_len, $plane_z);
glVertex3f(-$axis_len, $axis_len, $plane_z);
glEnd();
glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
}
}
glPopMatrix();

View File

@ -562,6 +562,53 @@ sub print_info {
}
}
sub cut {
my ($self, $z) = @_;
# clone this one
my $upper = Slic3r::Model::Object->new(
input_file => $self->input_file,
model => $self->model,
config => $self->config->clone,
layer_height_ranges => $self->layer_height_ranges,
);
my $lower = Slic3r::Model::Object->new(
input_file => $self->input_file,
model => $self->model,
config => $self->config->clone,
layer_height_ranges => $self->layer_height_ranges,
);
$upper->add_instance(offset => Slic3r::Point->new(0,0));
$lower->add_instance(offset => Slic3r::Point->new(0,0));
foreach my $volume (@{$self->volumes}) {
if ($volume->modifier) {
# don't cut modifiers
$upper->add_volume($volume);
$lower->add_volume($volume);
} else {
my $upper_mesh = Slic3r::TriangleMesh->new;
my $lower_mesh = Slic3r::TriangleMesh->new;
$volume->mesh->cut($z, $upper_mesh, $lower_mesh);
$upper_mesh->repair;
$lower_mesh->repair;
$upper->add_volume(
material_id => $volume->material_id,
mesh => $upper_mesh,
modifier => $volume->modifier,
);
$lower->add_volume(
material_id => $volume->material_id,
mesh => $lower_mesh,
modifier => $volume->modifier,
);
}
}
return ($upper, $lower);
}
package Slic3r::Model::Volume;
use Moo;