mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	3D preview of plater
This commit is contained in:
		
							parent
							
								
									670ffcf4be
								
							
						
					
					
						commit
						da4d6cbabb
					
				
					 10 changed files with 130 additions and 44 deletions
				
			
		|  | @ -13,6 +13,7 @@ use Slic3r::GUI::Notifier; | |||
| use Slic3r::GUI::Plater; | ||||
| use Slic3r::GUI::Plater::2D; | ||||
| use Slic3r::GUI::Plater::2DToolpaths; | ||||
| use Slic3r::GUI::Plater::3D; | ||||
| use Slic3r::GUI::Plater::ObjectPartsPanel; | ||||
| use Slic3r::GUI::Plater::ObjectCutDialog; | ||||
| use Slic3r::GUI::Plater::ObjectPreviewDialog; | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ use List::Util qw(sum first); | |||
| use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale deg2rad); | ||||
| use threads::shared qw(shared_clone); | ||||
| 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  | ||||
|     EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL  | ||||
|     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 { | ||||
|         my ($obj_idx) = @_; | ||||
|         $self->select_object($obj_idx); | ||||
|  | @ -87,6 +92,12 @@ sub new { | |||
|         $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 | ||||
|     if (!&Wx::wxMSW) { | ||||
|         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_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_VIEW, "Cut…", Wx::Bitmap->new("$Slic3r::var/package.png", wxBITMAP_TYPE_PNG), ''); | ||||
|         $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), ''); | ||||
|     } else { | ||||
|         my %tbar_buttons = ( | ||||
|  | @ -337,7 +348,7 @@ sub new { | |||
|         $right_sizer->Add($object_info_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); | ||||
|          | ||||
|         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); | ||||
|          | ||||
|         my $sizer = Wx::BoxSizer->new(wxVERTICAL); | ||||
|  | @ -558,7 +569,7 @@ sub increase { | |||
|     if ($Slic3r::GUI::Settings->{_}{autocenter}) { | ||||
|         $self->arrange; | ||||
|     } else { | ||||
|         $self->{canvas}->Refresh; | ||||
|         $self->update; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -580,7 +591,6 @@ sub decrease { | |||
|         $self->{list}->Select($obj_idx, 1); | ||||
|     } | ||||
|     $self->update; | ||||
|     $self->{canvas}->Refresh; | ||||
| } | ||||
| 
 | ||||
| sub rotate { | ||||
|  | @ -1151,6 +1161,7 @@ sub update { | |||
|     } | ||||
|      | ||||
|     $self->{canvas}->Refresh; | ||||
|     $self->{canvas3D}->update if $self->{canvas3D}; | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|         $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; | ||||
|     }); | ||||
|     $menu->AppendSeparator(); | ||||
|  |  | |||
							
								
								
									
										45
									
								
								lib/Slic3r/GUI/Plater/3D.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								lib/Slic3r/GUI/Plater/3D.pm
									
										
									
									
									
										Normal 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; | ||||
|  | @ -86,7 +86,8 @@ sub new { | |||
|     # right pane with preview canvas | ||||
|     my $canvas; | ||||
|     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->SetMinSize($canvas->GetSize); | ||||
|     } | ||||
|  |  | |||
|  | @ -68,7 +68,8 @@ sub new { | |||
|     # right pane with preview canvas | ||||
|     my $canvas; | ||||
|     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]); | ||||
|     } | ||||
|      | ||||
|  |  | |||
|  | @ -13,8 +13,11 @@ sub new { | |||
|     my $self = $class->SUPER::new($parent, -1, $params{object}->name, wxDefaultPosition, [500,500], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); | ||||
|     $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); | ||||
|     $sizer->Add(Slic3r::GUI::PreviewCanvas->new($self, $self->{model_object}), 1, wxEXPAND, 0); | ||||
|     $sizer->Add($canvas, 1, wxEXPAND, 0); | ||||
|     $self->SetSizer($sizer); | ||||
|     $self->SetMinSize($self->GetSize); | ||||
|      | ||||
|  |  | |||
|  | @ -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 { | ||||
|     my ($class, $parent, $object) = @_; | ||||
|     my ($class, $parent) = @_; | ||||
|     my $self = $class->SUPER::new($parent); | ||||
|     | ||||
|     $self->quat((0, 0, 0, 1)); | ||||
|     $self->sphi(45); | ||||
|     $self->stheta(-45); | ||||
| 
 | ||||
|     $self->load_object($object); | ||||
|      | ||||
|     $self->reset_objects; | ||||
|      | ||||
|     EVT_PAINT($self, sub { | ||||
|         my $dc = Wx::PaintDC->new($self); | ||||
|         return if !@{$self->volumes}; | ||||
|         $self->Render($dc); | ||||
|     }); | ||||
|     EVT_SIZE($self, sub { $self->dirty(1) }); | ||||
|     EVT_IDLE($self, sub { | ||||
|         return unless $self->dirty; | ||||
|         return if !$self->IsShownOnScreen; | ||||
|         return if !@{$self->volumes}; | ||||
|         $self->Resize( $self->GetSizeWH ); | ||||
|         $self->Refresh; | ||||
|     }); | ||||
|  | @ -79,51 +81,69 @@ sub new { | |||
|     return $self; | ||||
| } | ||||
| 
 | ||||
| sub load_object { | ||||
|     my ($self, $object) = @_; | ||||
| sub reset_objects { | ||||
|     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; | ||||
|     $self->object_shift(Slic3r::Pointf3->new(-$center->x, -$center->y, -$bb->z_min));  #,, | ||||
|     $bb->translate(@{ $self->object_shift }); | ||||
|     $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 | ||||
|     my @materials = (); | ||||
|     $self->volumes([]); | ||||
|      | ||||
|     # sort volumes: non-modifiers first | ||||
|     my @volumes = sort { ($a->modifier // 0) <=> ($b->modifier // 0) } @{$object->volumes}; | ||||
|     foreach my $volume (@volumes) { | ||||
|         my $mesh = $volume->mesh->clone; | ||||
|         $object->instances->[0]->transform_mesh($mesh); | ||||
|         $mesh->translate(@{ $self->object_shift });   | ||||
|         my @instances = $all_instances ? @{$object->instances} : $object->instances->[0]; | ||||
|         foreach my $instance (@instances) { | ||||
|             my $mesh = $volume->mesh->clone; | ||||
|             $instance->transform_mesh($mesh); | ||||
|             $mesh->translate(@{ $self->object_shift });   | ||||
|          | ||||
|         my $material_id = $volume->material_id // '_'; | ||||
|         my $color_idx = first { $materials[$_] eq $material_id } 0..$#materials; | ||||
|         if (!defined $color_idx) { | ||||
|             push @materials, $material_id; | ||||
|             $color_idx = $#materials; | ||||
|         } | ||||
|             my $material_id = $volume->material_id // '_'; | ||||
|             my $color_idx = first { $materials[$_] eq $material_id } 0..$#materials; | ||||
|             if (!defined $color_idx) { | ||||
|                 push @materials, $material_id; | ||||
|                 $color_idx = $#materials; | ||||
|             } | ||||
|          | ||||
|         my $color = [ @{COLORS->[ $color_idx % scalar(@{&COLORS}) ]} ]; | ||||
|         push @$color, $volume->modifier ? 0.5 : 1; | ||||
|         push @{$self->volumes}, my $v = { | ||||
|             mesh  => $mesh, | ||||
|             color => $color, | ||||
|         }; | ||||
|             my $color = [ @{COLORS->[ $color_idx % scalar(@{&COLORS}) ]} ]; | ||||
|             push @$color, $volume->modifier ? 0.5 : 1; | ||||
|             push @{$self->volumes}, my $v = { | ||||
|                 mesh  => $mesh, | ||||
|                 color => $color, | ||||
|             }; | ||||
|          | ||||
|         { | ||||
|             my $vertices = $mesh->vertices; | ||||
|             my @verts = map @{ $vertices->[$_] }, map @$_, @{$mesh->facets}; | ||||
|             $v->{verts} = OpenGL::Array->new_list(GL_FLOAT, @verts); | ||||
|         } | ||||
|             { | ||||
|                 my $vertices = $mesh->vertices; | ||||
|                 my @verts = map @{ $vertices->[$_] }, map @$_, @{$mesh->facets}; | ||||
|                 $v->{verts} = OpenGL::Array->new_list(GL_FLOAT, @verts); | ||||
|             } | ||||
|          | ||||
|         { | ||||
|             my @norms = map { @$_, @$_, @$_ } @{$mesh->normals}; | ||||
|             $v->{norms} = OpenGL::Array->new_list(GL_FLOAT, @norms); | ||||
|             { | ||||
|                 my @norms = map { @$_, @$_, @$_ } @{$mesh->normals}; | ||||
|                 $v->{norms} = OpenGL::Array->new_list(GL_FLOAT, @norms); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     $self->dirty(1); | ||||
| } | ||||
| 
 | ||||
| sub SetCuttingPlane { | ||||
|  |  | |||
|  | @ -446,6 +446,8 @@ sub bounding_box { | |||
| sub instance_bounding_box { | ||||
|     my ($self, $instance_idx) = @_; | ||||
|      | ||||
|     $instance_idx //= 0; | ||||
|      | ||||
|     my $mesh = $self->raw_mesh; | ||||
|     $self->instances->[$instance_idx]->transform_mesh($mesh); | ||||
|     return $mesh->bounding_box; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci