3D preview of plater

This commit is contained in:
Alessandro Ranellucci 2014-07-13 12:10:34 +02:00
parent 670ffcf4be
commit da4d6cbabb
10 changed files with 130 additions and 44 deletions

View file

@ -13,6 +13,7 @@ use Slic3r::GUI::Notifier;
use Slic3r::GUI::Plater; use Slic3r::GUI::Plater;
use Slic3r::GUI::Plater::2D; use Slic3r::GUI::Plater::2D;
use Slic3r::GUI::Plater::2DToolpaths; use Slic3r::GUI::Plater::2DToolpaths;
use Slic3r::GUI::Plater::3D;
use Slic3r::GUI::Plater::ObjectPartsPanel; use Slic3r::GUI::Plater::ObjectPartsPanel;
use Slic3r::GUI::Plater::ObjectCutDialog; use Slic3r::GUI::Plater::ObjectCutDialog;
use Slic3r::GUI::Plater::ObjectPreviewDialog; use Slic3r::GUI::Plater::ObjectPreviewDialog;

View file

@ -8,7 +8,7 @@ use List::Util qw(sum first);
use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale deg2rad); use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale deg2rad);
use threads::shared qw(shared_clone); use threads::shared qw(shared_clone);
use Wx qw(:button :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc use Wx qw(:button :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc
:panel :sizer :toolbar :window wxTheApp); :panel :sizer :toolbar :window wxTheApp :notebook);
use Wx::Event qw(EVT_BUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED 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_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL
EVT_CHOICE EVT_TIMER); EVT_CHOICE EVT_TIMER);
@ -65,7 +65,12 @@ sub new {
} }
}); });
$self->{canvas} = Slic3r::GUI::Plater::2D->new($self, [335,335], $self->{objects}, $self->{model}, $self->{config}); # Initialize preview notebook
$self->{preview_notebook} = Wx::Notebook->new($self, -1, wxDefaultPosition, [335,335], wxNB_BOTTOM);
# Initialize 2D preview canvas
$self->{canvas} = Slic3r::GUI::Plater::2D->new($self->{preview_notebook}, wxDefaultSize, $self->{objects}, $self->{model}, $self->{config});
$self->{preview_notebook}->AddPage($self->{canvas}, '2D');
$self->{canvas}->on_select_object(sub { $self->{canvas}->on_select_object(sub {
my ($obj_idx) = @_; my ($obj_idx) = @_;
$self->select_object($obj_idx); $self->select_object($obj_idx);
@ -87,6 +92,12 @@ sub new {
$self->update; $self->update;
}); });
# Initialize 3D preview canvas
if ($Slic3r::GUI::have_OpenGL) {
$self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{config});
$self->{preview_notebook}->AddPage($self->{canvas3D}, '3D');
}
# toolbar for object manipulation # toolbar for object manipulation
if (!&Wx::wxMSW) { if (!&Wx::wxMSW) {
Wx::ToolTip::Enable(1); Wx::ToolTip::Enable(1);
@ -103,8 +114,8 @@ sub new {
$self->{htoolbar}->AddTool(TB_45CW, "45° cw", Wx::Bitmap->new("$Slic3r::var/arrow_rotate_clockwise.png", wxBITMAP_TYPE_PNG), ''); $self->{htoolbar}->AddTool(TB_45CW, "45° cw", Wx::Bitmap->new("$Slic3r::var/arrow_rotate_clockwise.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_SCALE, "Scale…", Wx::Bitmap->new("$Slic3r::var/arrow_out.png", wxBITMAP_TYPE_PNG), ''); $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}->AddTool(TB_SPLIT, "Split", Wx::Bitmap->new("$Slic3r::var/shape_ungroup.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_VIEW, "Cut…", Wx::Bitmap->new("$Slic3r::var/package.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddSeparator; $self->{htoolbar}->AddSeparator;
$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), ''); $self->{htoolbar}->AddTool(TB_SETTINGS, "Settings…", Wx::Bitmap->new("$Slic3r::var/cog.png", wxBITMAP_TYPE_PNG), '');
} else { } else {
my %tbar_buttons = ( my %tbar_buttons = (
@ -337,7 +348,7 @@ sub new {
$right_sizer->Add($object_info_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); $right_sizer->Add($object_info_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
$hsizer->Add($self->{canvas}, 1, wxEXPAND | wxTOP, 1); $hsizer->Add($self->{preview_notebook}, 1, wxEXPAND | wxTOP, 1);
$hsizer->Add($right_sizer, 0, wxEXPAND | wxBOTTOM, 0); $hsizer->Add($right_sizer, 0, wxEXPAND | wxBOTTOM, 0);
my $sizer = Wx::BoxSizer->new(wxVERTICAL); my $sizer = Wx::BoxSizer->new(wxVERTICAL);
@ -558,7 +569,7 @@ sub increase {
if ($Slic3r::GUI::Settings->{_}{autocenter}) { if ($Slic3r::GUI::Settings->{_}{autocenter}) {
$self->arrange; $self->arrange;
} else { } else {
$self->{canvas}->Refresh; $self->update;
} }
} }
@ -580,7 +591,6 @@ sub decrease {
$self->{list}->Select($obj_idx, 1); $self->{list}->Select($obj_idx, 1);
} }
$self->update; $self->update;
$self->{canvas}->Refresh;
} }
sub rotate { sub rotate {
@ -1151,6 +1161,7 @@ sub update {
} }
$self->{canvas}->Refresh; $self->{canvas}->Refresh;
$self->{canvas3D}->update if $self->{canvas3D};
} }
sub on_extruders_change { sub on_extruders_change {
@ -1466,7 +1477,7 @@ sub object_menu {
$frame->_append_menu_item($menu, "Split", 'Split the selected object into individual parts', sub { $frame->_append_menu_item($menu, "Split", 'Split the selected object into individual parts', sub {
$self->split_object; $self->split_object;
}); });
$frame->_append_menu_item($menu, "View/Cut…", 'Open the 3D cutting tool', sub { $frame->_append_menu_item($menu, "Cut…", 'Open the 3D cutting tool', sub {
$self->object_cut_dialog; $self->object_cut_dialog;
}); });
$menu->AppendSeparator(); $menu->AppendSeparator();

View file

@ -0,0 +1,45 @@
package Slic3r::GUI::Plater::3D;
use strict;
use warnings;
use utf8;
use List::Util qw();
use Slic3r::Geometry qw();
use Slic3r::Geometry::Clipper qw();
use Wx qw(:misc :pen :brush :sizer :font :cursor wxTAB_TRAVERSAL);
use Wx::Event qw();
use base 'Slic3r::GUI::PreviewCanvas';
sub new {
my $class = shift;
my ($parent, $objects, $model, $config) = @_;
my $self = $class->SUPER::new($parent);
$self->{objects} = $objects;
$self->{model} = $model;
$self->{config} = $config;
$self->{on_select_object} = sub {};
$self->{on_double_click} = sub {};
$self->{on_right_click} = sub {};
$self->{on_instance_moved} = sub {};
return $self;
}
sub update {
my ($self) = @_;
$self->reset_objects;
return if $self->{model}->objects_count == 0;
$self->set_bounding_box($self->{model}->bounding_box);
foreach my $model_object (@{$self->{model}->objects}) {
$self->load_object($model_object, 1);
}
}
1;

View file

@ -86,7 +86,8 @@ sub new {
# right pane with preview canvas # right pane with preview canvas
my $canvas; my $canvas;
if ($Slic3r::GUI::have_OpenGL) { if ($Slic3r::GUI::have_OpenGL) {
$canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self, $self->{model_object}); $canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self);
$canvas->load_object($self->{model_object});
$canvas->SetSize([500,500]); $canvas->SetSize([500,500]);
$canvas->SetMinSize($canvas->GetSize); $canvas->SetMinSize($canvas->GetSize);
} }

View file

@ -68,7 +68,8 @@ sub new {
# right pane with preview canvas # right pane with preview canvas
my $canvas; my $canvas;
if ($Slic3r::GUI::have_OpenGL) { if ($Slic3r::GUI::have_OpenGL) {
$canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self, $self->{model_object}); $canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self);
$canvas->load_object($self->{model_object});
$canvas->SetSize([500,500]); $canvas->SetSize([500,500]);
} }

View file

@ -13,8 +13,11 @@ sub new {
my $self = $class->SUPER::new($parent, -1, $params{object}->name, wxDefaultPosition, [500,500], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); my $self = $class->SUPER::new($parent, -1, $params{object}->name, wxDefaultPosition, [500,500], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
$self->{model_object} = $params{model_object}; $self->{model_object} = $params{model_object};
my $canvas = Slic3r::GUI::PreviewCanvas->new($self);
$canvas->load_object($self->{model_object});
my $sizer = Wx::BoxSizer->new(wxVERTICAL); my $sizer = Wx::BoxSizer->new(wxVERTICAL);
$sizer->Add(Slic3r::GUI::PreviewCanvas->new($self, $self->{model_object}), 1, wxEXPAND, 0); $sizer->Add($canvas, 1, wxEXPAND, 0);
$self->SetSizer($sizer); $self->SetSizer($sizer);
$self->SetMinSize($self->GetSize); $self->SetMinSize($self->GetSize);

View file

@ -32,23 +32,25 @@ use constant COLORS => [ [1,1,0], [1,0.5,0.5], [0.5,1,0.5], [0.5,0.5,1] ];
} }
sub new { sub new {
my ($class, $parent, $object) = @_; my ($class, $parent) = @_;
my $self = $class->SUPER::new($parent); my $self = $class->SUPER::new($parent);
$self->quat((0, 0, 0, 1)); $self->quat((0, 0, 0, 1));
$self->sphi(45); $self->sphi(45);
$self->stheta(-45); $self->stheta(-45);
$self->load_object($object); $self->reset_objects;
EVT_PAINT($self, sub { EVT_PAINT($self, sub {
my $dc = Wx::PaintDC->new($self); my $dc = Wx::PaintDC->new($self);
return if !@{$self->volumes};
$self->Render($dc); $self->Render($dc);
}); });
EVT_SIZE($self, sub { $self->dirty(1) }); EVT_SIZE($self, sub { $self->dirty(1) });
EVT_IDLE($self, sub { EVT_IDLE($self, sub {
return unless $self->dirty; return unless $self->dirty;
return if !$self->IsShownOnScreen; return if !$self->IsShownOnScreen;
return if !@{$self->volumes};
$self->Resize( $self->GetSizeWH ); $self->Resize( $self->GetSizeWH );
$self->Refresh; $self->Refresh;
}); });
@ -79,51 +81,69 @@ sub new {
return $self; return $self;
} }
sub load_object { sub reset_objects {
my ($self, $object) = @_; my ($self) = @_;
$self->volumes([]);
$self->dirty(1);
}
# this method accepts a Slic3r::BoudingBox3f object
sub set_bounding_box {
my ($self, $bb) = @_;
my $bb = $object->instance_bounding_box;
my $center = $bb->center; my $center = $bb->center;
$self->object_shift(Slic3r::Pointf3->new(-$center->x, -$center->y, -$bb->z_min)); #,, $self->object_shift(Slic3r::Pointf3->new(-$center->x, -$center->y, -$bb->z_min)); #,,
$bb->translate(@{ $self->object_shift }); $bb->translate(@{ $self->object_shift });
$self->object_bounding_box($bb); $self->object_bounding_box($bb);
$self->dirty(1);
}
sub load_object {
my ($self, $object, $all_instances) = @_;
$self->set_bounding_box($object->instance_bounding_box)
if !$all_instances;
# group mesh(es) by material # group mesh(es) by material
my @materials = (); my @materials = ();
$self->volumes([]);
# sort volumes: non-modifiers first # sort volumes: non-modifiers first
my @volumes = sort { ($a->modifier // 0) <=> ($b->modifier // 0) } @{$object->volumes}; my @volumes = sort { ($a->modifier // 0) <=> ($b->modifier // 0) } @{$object->volumes};
foreach my $volume (@volumes) { foreach my $volume (@volumes) {
my $mesh = $volume->mesh->clone; my @instances = $all_instances ? @{$object->instances} : $object->instances->[0];
$object->instances->[0]->transform_mesh($mesh); foreach my $instance (@instances) {
$mesh->translate(@{ $self->object_shift }); my $mesh = $volume->mesh->clone;
$instance->transform_mesh($mesh);
$mesh->translate(@{ $self->object_shift });
my $material_id = $volume->material_id // '_'; my $material_id = $volume->material_id // '_';
my $color_idx = first { $materials[$_] eq $material_id } 0..$#materials; my $color_idx = first { $materials[$_] eq $material_id } 0..$#materials;
if (!defined $color_idx) { if (!defined $color_idx) {
push @materials, $material_id; push @materials, $material_id;
$color_idx = $#materials; $color_idx = $#materials;
} }
my $color = [ @{COLORS->[ $color_idx % scalar(@{&COLORS}) ]} ]; my $color = [ @{COLORS->[ $color_idx % scalar(@{&COLORS}) ]} ];
push @$color, $volume->modifier ? 0.5 : 1; push @$color, $volume->modifier ? 0.5 : 1;
push @{$self->volumes}, my $v = { push @{$self->volumes}, my $v = {
mesh => $mesh, mesh => $mesh,
color => $color, color => $color,
}; };
{ {
my $vertices = $mesh->vertices; my $vertices = $mesh->vertices;
my @verts = map @{ $vertices->[$_] }, map @$_, @{$mesh->facets}; my @verts = map @{ $vertices->[$_] }, map @$_, @{$mesh->facets};
$v->{verts} = OpenGL::Array->new_list(GL_FLOAT, @verts); $v->{verts} = OpenGL::Array->new_list(GL_FLOAT, @verts);
} }
{ {
my @norms = map { @$_, @$_, @$_ } @{$mesh->normals}; my @norms = map { @$_, @$_, @$_ } @{$mesh->normals};
$v->{norms} = OpenGL::Array->new_list(GL_FLOAT, @norms); $v->{norms} = OpenGL::Array->new_list(GL_FLOAT, @norms);
}
} }
} }
$self->dirty(1);
} }
sub SetCuttingPlane { sub SetCuttingPlane {

View file

@ -446,6 +446,8 @@ sub bounding_box {
sub instance_bounding_box { sub instance_bounding_box {
my ($self, $instance_idx) = @_; my ($self, $instance_idx) = @_;
$instance_idx //= 0;
my $mesh = $self->raw_mesh; my $mesh = $self->raw_mesh;
$self->instances->[$instance_idx]->transform_mesh($mesh); $self->instances->[$instance_idx]->transform_mesh($mesh);
return $mesh->bounding_box; return $mesh->bounding_box;

View file

@ -31,8 +31,8 @@ my %opt = ();
# make sure all objects have at least one defined instance # make sure all objects have at least one defined instance
$model->add_default_instances; $model->add_default_instances;
$Slic3r::ViewMesh::object = $model->objects->[0];
my $app = Slic3r::ViewMesh->new; my $app = Slic3r::ViewMesh->new;
$app->{canvas}->load_object($model->objects->[0]);
$app->{canvas}->SetCuttingPlane($opt{cut}) if defined $opt{cut}; $app->{canvas}->SetCuttingPlane($opt{cut}) if defined $opt{cut};
$app->MainLoop; $app->MainLoop;
} }
@ -55,16 +55,16 @@ package Slic3r::ViewMesh;
use Wx qw(:sizer); use Wx qw(:sizer);
use base qw(Wx::App); use base qw(Wx::App);
our $object;
sub OnInit { sub OnInit {
my $self = shift; my $self = shift;
my $frame = Wx::Frame->new(undef, -1, 'Mesh Viewer', [-1, -1], [500, 400]); my $frame = Wx::Frame->new(undef, -1, 'Mesh Viewer', [-1, -1], [500, 400]);
my $panel = Wx::Panel->new($frame, -1); my $panel = Wx::Panel->new($frame, -1);
$self->{canvas} = Slic3r::GUI::PreviewCanvas->new($panel);
my $sizer = Wx::BoxSizer->new(wxVERTICAL); my $sizer = Wx::BoxSizer->new(wxVERTICAL);
$sizer->Add($self->{canvas} = Slic3r::GUI::PreviewCanvas->new($panel, $object), 1, wxEXPAND, 0); $sizer->Add($self->{canvas}, 1, wxEXPAND, 0);
$panel->SetSizer($sizer); $panel->SetSizer($sizer);
$sizer->SetSizeHints($panel); $sizer->SetSizeHints($panel);

View file

@ -18,6 +18,8 @@
%code%{ RETVAL = THIS->add_object(*other); %}; %code%{ RETVAL = THIS->add_object(*other); %};
void delete_object(size_t idx); void delete_object(size_t idx);
void clear_objects(); void clear_objects();
size_t objects_count()
%code%{ RETVAL = THIS->objects.size(); %};
Ref<ModelMaterial> get_material(t_model_material_id material_id) Ref<ModelMaterial> get_material(t_model_material_id material_id)
%code%{ %code%{