Initial work for a GUI for the cut feature
This commit is contained in:
parent
334bc4c581
commit
882a98ed44
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
126
lib/Slic3r/GUI/Plater/ObjectCutDialog.pm
Normal file
126
lib/Slic3r/GUI/Plater/ObjectCutDialog.pm
Normal 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;
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user