mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge remote-tracking branch 'origin/newplater'
This commit is contained in:
		
						commit
						d1511f4a00
					
				
					 3 changed files with 306 additions and 249 deletions
				
			
		|  | @ -8,6 +8,7 @@ use FindBin; | |||
| use Slic3r::GUI::AboutDialog; | ||||
| use Slic3r::GUI::ConfigWizard; | ||||
| use Slic3r::GUI::Plater; | ||||
| use Slic3r::GUI::Plater::2D; | ||||
| use Slic3r::GUI::Plater::ObjectPartsPanel; | ||||
| use Slic3r::GUI::Plater::ObjectCutDialog; | ||||
| use Slic3r::GUI::Plater::ObjectPreviewDialog; | ||||
|  |  | |||
|  | @ -4,11 +4,10 @@ use warnings; | |||
| use utf8; | ||||
| 
 | ||||
| use File::Basename qw(basename dirname); | ||||
| use List::Util qw(max sum first); | ||||
| use Slic3r::Geometry::Clipper qw(offset JT_ROUND); | ||||
| use Slic3r::Geometry qw(X Y Z MIN MAX convex_hull scale unscale); | ||||
| use List::Util qw(sum first); | ||||
| use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale); | ||||
| use threads::shared qw(shared_clone); | ||||
| use Wx qw(:bitmap :brush :button :cursor :dialog :filedialog :font :keycode :icon :id :listctrl :misc :panel :pen :sizer :toolbar :window); | ||||
| use Wx qw(:button :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc :panel :sizer :toolbar :window); | ||||
| 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); | ||||
| use base 'Wx::Panel'; | ||||
| 
 | ||||
|  | @ -36,9 +35,6 @@ our $EXPORT_COMPLETED_EVENT  : shared = Wx::NewEventType; | |||
| our $EXPORT_FAILED_EVENT     : shared = Wx::NewEventType; | ||||
| 
 | ||||
| use constant CANVAS_SIZE => [335,335]; | ||||
| use constant CANVAS_TEXT => join('-', +(localtime)[3,4]) eq '13-8' | ||||
|     ? 'What do you want to print today? ™' # Sept. 13, 2006. The first part ever printed by a RepRap to make another RepRap. | ||||
|     : 'Drag your objects here'; | ||||
| use constant FILAMENT_CHOOSERS_SPACING => 3; | ||||
| 
 | ||||
| my $PreventListEvents = 0; | ||||
|  | @ -54,19 +50,17 @@ sub new { | |||
|     $self->{print} = Slic3r::Print->new; | ||||
|     $self->{objects} = []; | ||||
|      | ||||
|     $self->{canvas} = Wx::Panel->new($self, -1, wxDefaultPosition, CANVAS_SIZE, wxTAB_TRAVERSAL); | ||||
|     $self->{canvas}->SetBackgroundColour(Wx::wxWHITE); | ||||
|     EVT_PAINT($self->{canvas}, \&repaint); | ||||
|     EVT_MOUSE_EVENTS($self->{canvas}, \&mouse_event); | ||||
|      | ||||
|     $self->{objects_brush} = Wx::Brush->new(Wx::Colour->new(210,210,210), wxSOLID); | ||||
|     $self->{selected_brush} = Wx::Brush->new(Wx::Colour->new(255,128,128), wxSOLID); | ||||
|     $self->{dragged_brush} = Wx::Brush->new(Wx::Colour->new(128,128,255), wxSOLID); | ||||
|     $self->{transparent_brush} = Wx::Brush->new(Wx::Colour->new(0,0,0), wxTRANSPARENT); | ||||
|     $self->{grid_pen} = Wx::Pen->new(Wx::Colour->new(230,230,230), 1, wxSOLID); | ||||
|     $self->{print_center_pen} = Wx::Pen->new(Wx::Colour->new(200,200,200), 1, wxSOLID); | ||||
|     $self->{clearance_pen} = Wx::Pen->new(Wx::Colour->new(0,0,200), 1, wxSOLID); | ||||
|     $self->{skirt_pen} = Wx::Pen->new(Wx::Colour->new(150,150,150), 1, wxSOLID); | ||||
|     $self->{canvas} = Slic3r::GUI::Plater::2D->new($self, CANVAS_SIZE, $self->{objects}, $self->{model}, $self->{config}); | ||||
|     $self->{canvas}->on_select_object(sub { | ||||
|         my ($obj_idx) = @_; | ||||
|         $self->select_object($obj_idx); | ||||
|     }); | ||||
|     $self->{canvas}->on_double_click(sub { | ||||
|         $self->object_cut_dialog if $self->selected_object; | ||||
|     }); | ||||
|     $self->{canvas}->on_instance_moved(sub { | ||||
|         $self->update; | ||||
|     }); | ||||
|      | ||||
|     # toolbar for object manipulation | ||||
|     if (!&Wx::wxMSW) { | ||||
|  | @ -224,7 +218,7 @@ sub new { | |||
|         $self->on_export_failed; | ||||
|     }); | ||||
|      | ||||
|     $self->_update_bed_size; | ||||
|     $self->{canvas}->update_bed_size; | ||||
|     $self->update; | ||||
|      | ||||
|     { | ||||
|  | @ -597,8 +591,8 @@ sub arrange { | |||
|      | ||||
|     # get the bounding box of the model area shown in the viewport | ||||
|     my $bb = Slic3r::Geometry::BoundingBox->new_from_points([ | ||||
|         Slic3r::Point->new(@{ $self->point_to_model_units([0,0]) }), | ||||
|         Slic3r::Point->new(@{ $self->point_to_model_units(CANVAS_SIZE) }), | ||||
|         Slic3r::Point->new(@{ $self->{canvas}->point_to_model_units([0,0]) }), | ||||
|         Slic3r::Point->new(@{ $self->{canvas}->point_to_model_units(CANVAS_SIZE) }), | ||||
|     ]); | ||||
|      | ||||
|     eval { | ||||
|  | @ -896,14 +890,6 @@ sub on_thumbnail_made { | |||
|     $self->{canvas}->Refresh; | ||||
| } | ||||
| 
 | ||||
| sub clean_instance_thumbnails { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     foreach my $object (@{ $self->{objects} }) { | ||||
|         @{ $object->instance_thumbnails } = (); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| # this method gets called whenever print center is changed or the objects' bounding box changes | ||||
| # (i.e. when an object is added/removed/moved/rotated/scaled) | ||||
| sub update { | ||||
|  | @ -947,184 +933,14 @@ sub on_config_change { | |||
|         $self->Layout; | ||||
|     } elsif ($self->{config}->has($opt_key)) { | ||||
|         $self->{config}->set($opt_key, $value); | ||||
|         $self->_update_bed_size if $opt_key eq 'bed_size'; | ||||
|         if ($opt_key eq 'bed_size') { | ||||
|             $self->{canvas}->update_bed_size; | ||||
|             $self->update; | ||||
|         } | ||||
|         $self->update if $opt_key eq 'print_center'; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| sub _update_bed_size { | ||||
|     my $self = shift; | ||||
|      | ||||
|     # supposing the preview canvas is square, calculate the scaling factor | ||||
|     # to constrain print bed area inside preview | ||||
|     # when the canvas is not rendered yet, its GetSize() method returns 0,0 | ||||
|     # scaling_factor is expressed in pixel / mm | ||||
|     $self->{scaling_factor} = CANVAS_SIZE->[X] / max(@{ $self->{config}->bed_size }); | ||||
|     $self->update; | ||||
| } | ||||
| 
 | ||||
| # this is called on the canvas | ||||
| sub repaint { | ||||
|     my ($self, $event) = @_; | ||||
|     my $parent = $self->GetParent; | ||||
|      | ||||
|     my $dc = Wx::PaintDC->new($self); | ||||
|     my $size = $self->GetSize; | ||||
|     my @size = ($size->GetWidth, $size->GetHeight); | ||||
|      | ||||
|     # draw grid | ||||
|     $dc->SetPen($parent->{grid_pen}); | ||||
|     my $step = 10 * $parent->{scaling_factor}; | ||||
|     for (my $x = $step; $x <= $size[X]; $x += $step) { | ||||
|         $dc->DrawLine($x, 0, $x, $size[Y]); | ||||
|     } | ||||
|     for (my $y = $step; $y <= $size[Y]; $y += $step) { | ||||
|         $dc->DrawLine(0, $y, $size[X], $y); | ||||
|     } | ||||
|      | ||||
|     # draw print center | ||||
|     if (@{$parent->{objects}}) { | ||||
|         $dc->SetPen($parent->{print_center_pen}); | ||||
|         $dc->DrawLine($size[X]/2, 0, $size[X]/2, $size[Y]); | ||||
|         $dc->DrawLine(0, $size[Y]/2, $size[X], $size[Y]/2); | ||||
|         $dc->SetTextForeground(Wx::Colour->new(0,0,0)); | ||||
|         $dc->SetFont(Wx::Font->new(10, wxDEFAULT, wxNORMAL, wxNORMAL)); | ||||
|         $dc->DrawLabel("X = " . $parent->{config}->print_center->[X], Wx::Rect->new(0, 0, $self->GetSize->GetWidth, $self->GetSize->GetHeight), wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM); | ||||
|         $dc->DrawRotatedText("Y = " . $parent->{config}->print_center->[Y], 0, $size[Y]/2+15, 90); | ||||
|     } | ||||
|      | ||||
|     # draw frame | ||||
|     if (0) { | ||||
|         $dc->SetPen(wxBLACK_PEN); | ||||
|         $dc->SetBrush($parent->{transparent_brush}); | ||||
|         $dc->DrawRectangle(0, 0, @size); | ||||
|     } | ||||
|      | ||||
|     # draw text if plate is empty | ||||
|     if (!@{$parent->{objects}}) { | ||||
|         $dc->SetTextForeground(Wx::Colour->new(150,50,50)); | ||||
|         $dc->SetFont(Wx::Font->new(14, wxDEFAULT, wxNORMAL, wxNORMAL)); | ||||
|         $dc->DrawLabel(CANVAS_TEXT, Wx::Rect->new(0, 0, $self->GetSize->GetWidth, $self->GetSize->GetHeight), wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL); | ||||
|     } | ||||
|      | ||||
|     # draw thumbnails | ||||
|     $dc->SetPen(wxBLACK_PEN); | ||||
|     $parent->clean_instance_thumbnails; | ||||
|     for my $obj_idx (0 .. $#{$parent->{objects}}) { | ||||
|         my $object = $parent->{objects}[$obj_idx]; | ||||
|         my $model_object = $parent->{model}->objects->[$obj_idx]; | ||||
|         next unless defined $object->thumbnail; | ||||
|         for my $instance_idx (0 .. $#{$model_object->instances}) { | ||||
|             my $instance = $model_object->instances->[$instance_idx]; | ||||
|             next if !defined $object->transformed_thumbnail; | ||||
|              | ||||
|             my $thumbnail = $object->transformed_thumbnail->clone;      # in scaled model coordinates | ||||
|             $thumbnail->translate(map scale($_), @{$instance->offset}); | ||||
|              | ||||
|             $object->instance_thumbnails->[$instance_idx] = $thumbnail; | ||||
|              | ||||
|             if (defined $self->{drag_object} && $self->{drag_object}[0] == $obj_idx && $self->{drag_object}[1] == $instance_idx) { | ||||
|                 $dc->SetBrush($parent->{dragged_brush}); | ||||
|             } elsif ($object->selected) { | ||||
|                 $dc->SetBrush($parent->{selected_brush}); | ||||
|             } else { | ||||
|                 $dc->SetBrush($parent->{objects_brush}); | ||||
|             } | ||||
|             foreach my $expolygon (@$thumbnail) { | ||||
|                 foreach my $points (@{$expolygon->pp}) { | ||||
|                     $dc->DrawPolygon($parent->points_to_pixel($points, 1), 0, 0); | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             if (0) { | ||||
|                 # draw bounding box for debugging purposes | ||||
|                 my $bb = $model_object->instance_bounding_box($instance_idx); | ||||
|                 $bb->scale($parent->{scaling_factor}); | ||||
|                 # no need to translate by instance offset because instance_bounding_box() does that | ||||
|                 my $points = $bb->polygon->pp; | ||||
|                 $dc->SetPen($parent->{clearance_pen}); | ||||
|                 $dc->SetBrush($parent->{transparent_brush}); | ||||
|                 $dc->DrawPolygon($parent->_y($points), 0, 0); | ||||
|             } | ||||
|              | ||||
|             # if sequential printing is enabled and we have more than one object, draw clearance area | ||||
|             if ($parent->{config}->complete_objects && (map @{$_->instances}, @{$parent->{model}->objects}) > 1) { | ||||
|                 my ($clearance) = @{offset([$thumbnail->convex_hull], (scale($parent->{config}->extruder_clearance_radius) / 2), 1, JT_ROUND, scale(0.1))}; | ||||
|                 $dc->SetPen($parent->{clearance_pen}); | ||||
|                 $dc->SetBrush($parent->{transparent_brush}); | ||||
|                 $dc->DrawPolygon($parent->points_to_pixel($clearance, 1), 0, 0); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     # draw skirt | ||||
|     if (@{$parent->{objects}} && $parent->{config}->skirts) { | ||||
|         my @points = map @{$_->contour}, map @$_, map @{$_->instance_thumbnails}, @{$parent->{objects}}; | ||||
|         if (@points >= 3) { | ||||
|             my ($convex_hull) = @{offset([convex_hull(\@points)], scale($parent->{config}->skirt_distance), 1, JT_ROUND, scale(0.1))}; | ||||
|             $dc->SetPen($parent->{skirt_pen}); | ||||
|             $dc->SetBrush($parent->{transparent_brush}); | ||||
|             $dc->DrawPolygon($parent->points_to_pixel($convex_hull, 1), 0, 0); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     $event->Skip; | ||||
| } | ||||
| 
 | ||||
| sub mouse_event { | ||||
|     my ($self, $event) = @_; | ||||
|     my $parent = $self->GetParent; | ||||
|      | ||||
|     my $point = $event->GetPosition; | ||||
|     my $pos = $parent->point_to_model_units([ $point->x, $point->y ]);  #]] | ||||
|     $pos = Slic3r::Point->new_scale(@$pos); | ||||
|     if ($event->ButtonDown(&Wx::wxMOUSE_BTN_LEFT)) { | ||||
|         $parent->select_object(undef); | ||||
|         for my $obj_idx (0 .. $#{$parent->{objects}}) { | ||||
|             my $object = $parent->{objects}->[$obj_idx]; | ||||
|             for my $instance_idx (0 .. $#{ $object->instance_thumbnails }) { | ||||
|                 my $thumbnail = $object->instance_thumbnails->[$instance_idx]; | ||||
|                 if (defined first { $_->contour->contains_point($pos) } @$thumbnail) { | ||||
|                     $parent->select_object($obj_idx); | ||||
|                     my $instance = $parent->{model}->objects->[$obj_idx]->instances->[$instance_idx]; | ||||
|                     my $instance_origin = [ map scale($_), @{$instance->offset} ]; | ||||
|                     $self->{drag_start_pos} = [   # displacement between the click and the instance origin in scaled model units | ||||
|                         $pos->x - $instance_origin->[X], | ||||
|                         $pos->y - $instance_origin->[Y],  #- | ||||
|                     ]; | ||||
|                     $self->{drag_object} = [ $obj_idx, $instance_idx ]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         $parent->Refresh; | ||||
|     } elsif ($event->ButtonUp(&Wx::wxMOUSE_BTN_LEFT)) { | ||||
|         $parent->update; | ||||
|         $parent->Refresh; | ||||
|         $self->{drag_start_pos} = undef; | ||||
|         $self->{drag_object} = undef; | ||||
|         $self->SetCursor(wxSTANDARD_CURSOR); | ||||
|     } elsif ($event->ButtonDClick) { | ||||
|     	$parent->object_cut_dialog if $parent->selected_object; | ||||
|     } elsif ($event->Dragging) { | ||||
|         return if !$self->{drag_start_pos}; # concurrency problems | ||||
|         my ($obj_idx, $instance_idx) = @{ $self->{drag_object} }; | ||||
|         my $model_object = $parent->{model}->objects->[$obj_idx]; | ||||
|         $model_object->instances->[$instance_idx]->set_offset( | ||||
|             Slic3r::Pointf->new( | ||||
|                 unscale($pos->[X] - $self->{drag_start_pos}[X]), | ||||
|                 unscale($pos->[Y] - $self->{drag_start_pos}[Y]), | ||||
|             )); | ||||
|         $model_object->update_bounding_box; | ||||
|         $parent->Refresh; | ||||
|     } elsif ($event->Moving) { | ||||
|         my $cursor = wxSTANDARD_CURSOR; | ||||
|         if (defined first { $_->contour->contains_point($pos) } map @$_, map @{$_->instance_thumbnails}, @{ $parent->{objects} }) { | ||||
|             $cursor = Wx::Cursor->new(wxCURSOR_HAND); | ||||
|         } | ||||
|         $self->SetCursor($cursor); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| sub list_item_deselected { | ||||
|     my ($self, $event) = @_; | ||||
|     return if $PreventListEvents; | ||||
|  | @ -1314,50 +1130,6 @@ sub statusbar { | |||
|     return $self->skeinpanel->GetParent->{statusbar}; | ||||
| } | ||||
| 
 | ||||
| # coordinates of the model origin (0,0) in pixels | ||||
| sub model_origin_to_pixel { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     return [ | ||||
|         CANVAS_SIZE->[X]/2 - ($self->{config}->print_center->[X] * $self->{scaling_factor}), | ||||
|         CANVAS_SIZE->[Y]/2 - ($self->{config}->print_center->[Y] * $self->{scaling_factor}), | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| # convert a model coordinate into a pixel coordinate, assuming preview has square shape | ||||
| sub point_to_pixel { | ||||
|     my ($self, $point) = @_; | ||||
|      | ||||
|     my $canvas_height = $self->{canvas}->GetSize->GetHeight; | ||||
|     my $zero = $self->model_origin_to_pixel; | ||||
|     return [ | ||||
|                           $point->[X] * $self->{scaling_factor} + $zero->[X], | ||||
|         $canvas_height - ($point->[Y] * $self->{scaling_factor} + $zero->[Y]), | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| sub points_to_pixel { | ||||
|     my ($self, $points, $unscale) = @_; | ||||
|      | ||||
|     my $result = []; | ||||
|     foreach my $point (@$points) { | ||||
|         $point = [ map unscale($_), @$point ] if $unscale; | ||||
|         push @$result, $self->point_to_pixel($point); | ||||
|     } | ||||
|     return $result; | ||||
| } | ||||
| 
 | ||||
| sub point_to_model_units { | ||||
|     my ($self, $point) = @_; | ||||
|      | ||||
|     my $canvas_height = $self->{canvas}->GetSize->GetHeight; | ||||
|     my $zero = $self->model_origin_to_pixel; | ||||
|     return [ | ||||
|                           ($point->[X] - $zero->[X]) / $self->{scaling_factor}, | ||||
|         (($canvas_height - $point->[Y] - $zero->[Y]) / $self->{scaling_factor}), | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| package Slic3r::GUI::Plater::DropTarget; | ||||
| use Wx::DND; | ||||
| use base 'Wx::FileDropTarget'; | ||||
|  |  | |||
							
								
								
									
										284
									
								
								lib/Slic3r/GUI/Plater/2D.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								lib/Slic3r/GUI/Plater/2D.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,284 @@ | |||
| package Slic3r::GUI::Plater::2D; | ||||
| use strict; | ||||
| use warnings; | ||||
| use utf8; | ||||
| 
 | ||||
| use List::Util qw(max first); | ||||
| use Slic3r::Geometry qw(X Y scale unscale convex_hull); | ||||
| use Slic3r::Geometry::Clipper qw(offset JT_ROUND); | ||||
| use Wx qw(:misc :pen :brush :sizer :font :cursor wxTAB_TRAVERSAL); | ||||
| use Wx::Event qw(EVT_MOUSE_EVENTS EVT_PAINT); | ||||
| use base 'Wx::Panel'; | ||||
| 
 | ||||
| use constant CANVAS_TEXT => join('-', +(localtime)[3,4]) eq '13-8' | ||||
|     ? 'What do you want to print today? ™' # Sept. 13, 2006. The first part ever printed by a RepRap to make another RepRap. | ||||
|     : 'Drag your objects here'; | ||||
| 
 | ||||
| sub new { | ||||
|     my $class = shift; | ||||
|     my ($parent, $size, $objects, $model, $config) = @_; | ||||
|      | ||||
|     my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, $size, wxTAB_TRAVERSAL); | ||||
|     $self->SetBackgroundColour(Wx::wxWHITE); | ||||
|      | ||||
|     $self->{objects}            = $objects; | ||||
|     $self->{model}              = $model; | ||||
|     $self->{config}             = $config; | ||||
|     $self->{on_select_object}   = sub {}; | ||||
|     $self->{on_double_click}    = sub {}; | ||||
|     $self->{on_instance_moved}  = sub {}; | ||||
|      | ||||
|     $self->{objects_brush}      = Wx::Brush->new(Wx::Colour->new(210,210,210), wxSOLID); | ||||
|     $self->{selected_brush}     = Wx::Brush->new(Wx::Colour->new(255,128,128), wxSOLID); | ||||
|     $self->{dragged_brush}      = Wx::Brush->new(Wx::Colour->new(128,128,255), wxSOLID); | ||||
|     $self->{transparent_brush}  = Wx::Brush->new(Wx::Colour->new(0,0,0), wxTRANSPARENT); | ||||
|     $self->{grid_pen}           = Wx::Pen->new(Wx::Colour->new(230,230,230), 1, wxSOLID); | ||||
|     $self->{print_center_pen}   = Wx::Pen->new(Wx::Colour->new(200,200,200), 1, wxSOLID); | ||||
|     $self->{clearance_pen}      = Wx::Pen->new(Wx::Colour->new(0,0,200), 1, wxSOLID); | ||||
|     $self->{skirt_pen}          = Wx::Pen->new(Wx::Colour->new(150,150,150), 1, wxSOLID); | ||||
|      | ||||
|     EVT_PAINT($self, \&repaint); | ||||
|     EVT_MOUSE_EVENTS($self, \&mouse_event); | ||||
|      | ||||
|     return $self; | ||||
| } | ||||
| 
 | ||||
| sub on_select_object { | ||||
|     my ($self, $cb) = @_; | ||||
|     $self->{on_select_object} = $cb; | ||||
| } | ||||
| 
 | ||||
| sub on_double_click { | ||||
|     my ($self, $cb) = @_; | ||||
|     $self->{on_double_click} = $cb; | ||||
| } | ||||
| 
 | ||||
| sub on_instance_moved { | ||||
|     my ($self, $cb) = @_; | ||||
|     $self->{on_instance_moved} = $cb; | ||||
| } | ||||
| 
 | ||||
| sub repaint { | ||||
|     my ($self, $event) = @_; | ||||
|      | ||||
|     my $dc = Wx::PaintDC->new($self); | ||||
|     my $size = $self->GetSize; | ||||
|     my @size = ($size->GetWidth, $size->GetHeight); | ||||
|      | ||||
|     # draw grid | ||||
|     $dc->SetPen($self->{grid_pen}); | ||||
|     my $step = 10 * $self->{scaling_factor}; | ||||
|     for (my $x = $step; $x <= $size[X]; $x += $step) { | ||||
|         $dc->DrawLine($x, 0, $x, $size[Y]); | ||||
|     } | ||||
|     for (my $y = $step; $y <= $size[Y]; $y += $step) { | ||||
|         $dc->DrawLine(0, $y, $size[X], $y); | ||||
|     } | ||||
|      | ||||
|     # draw print center | ||||
|     if (@{$self->{objects}}) { | ||||
|         $dc->SetPen($self->{print_center_pen}); | ||||
|         $dc->DrawLine($size[X]/2, 0, $size[X]/2, $size[Y]); | ||||
|         $dc->DrawLine(0, $size[Y]/2, $size[X], $size[Y]/2); | ||||
|         $dc->SetTextForeground(Wx::Colour->new(0,0,0)); | ||||
|         $dc->SetFont(Wx::Font->new(10, wxDEFAULT, wxNORMAL, wxNORMAL)); | ||||
|         $dc->DrawLabel("X = " . $self->{config}->print_center->[X], Wx::Rect->new(0, 0, $self->GetSize->GetWidth, $self->GetSize->GetHeight), wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM); | ||||
|         $dc->DrawRotatedText("Y = " . $self->{config}->print_center->[Y], 0, $size[Y]/2+15, 90); | ||||
|     } | ||||
|      | ||||
|     # draw frame | ||||
|     if (0) { | ||||
|         $dc->SetPen(wxBLACK_PEN); | ||||
|         $dc->SetBrush($self->{transparent_brush}); | ||||
|         $dc->DrawRectangle(0, 0, @size); | ||||
|     } | ||||
|      | ||||
|     # draw text if plate is empty | ||||
|     if (!@{$self->{objects}}) { | ||||
|         $dc->SetTextForeground(Wx::Colour->new(150,50,50)); | ||||
|         $dc->SetFont(Wx::Font->new(14, wxDEFAULT, wxNORMAL, wxNORMAL)); | ||||
|         $dc->DrawLabel(CANVAS_TEXT, Wx::Rect->new(0, 0, $self->GetSize->GetWidth, $self->GetSize->GetHeight), wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL); | ||||
|     } | ||||
|      | ||||
|     # draw thumbnails | ||||
|     $dc->SetPen(wxBLACK_PEN); | ||||
|     $self->clean_instance_thumbnails; | ||||
|     for my $obj_idx (0 .. $#{$self->{objects}}) { | ||||
|         my $object = $self->{objects}[$obj_idx]; | ||||
|         my $model_object = $self->{model}->objects->[$obj_idx]; | ||||
|         next unless defined $object->thumbnail; | ||||
|         for my $instance_idx (0 .. $#{$model_object->instances}) { | ||||
|             my $instance = $model_object->instances->[$instance_idx]; | ||||
|             next if !defined $object->transformed_thumbnail; | ||||
|              | ||||
|             my $thumbnail = $object->transformed_thumbnail->clone;      # in scaled model coordinates | ||||
|             $thumbnail->translate(map scale($_), @{$instance->offset}); | ||||
|              | ||||
|             $object->instance_thumbnails->[$instance_idx] = $thumbnail; | ||||
|              | ||||
|             if (defined $self->{drag_object} && $self->{drag_object}[0] == $obj_idx && $self->{drag_object}[1] == $instance_idx) { | ||||
|                 $dc->SetBrush($self->{dragged_brush}); | ||||
|             } elsif ($object->selected) { | ||||
|                 $dc->SetBrush($self->{selected_brush}); | ||||
|             } else { | ||||
|                 $dc->SetBrush($self->{objects_brush}); | ||||
|             } | ||||
|             foreach my $expolygon (@$thumbnail) { | ||||
|                 foreach my $points (@{$expolygon->pp}) { | ||||
|                     $dc->DrawPolygon($self->points_to_pixel($points, 1), 0, 0); | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             if (0) { | ||||
|                 # draw bounding box for debugging purposes | ||||
|                 my $bb = $model_object->instance_bounding_box($instance_idx); | ||||
|                 $bb->scale($self->{scaling_factor}); | ||||
|                 # no need to translate by instance offset because instance_bounding_box() does that | ||||
|                 my $points = $bb->polygon->pp; | ||||
|                 $dc->SetPen($self->{clearance_pen}); | ||||
|                 $dc->SetBrush($self->{transparent_brush}); | ||||
|                 $dc->DrawPolygon($self->_y($points), 0, 0); | ||||
|             } | ||||
|              | ||||
|             # if sequential printing is enabled and we have more than one object, draw clearance area | ||||
|             if ($self->{config}->complete_objects && (map @{$_->instances}, @{$self->{model}->objects}) > 1) { | ||||
|                 my ($clearance) = @{offset([$thumbnail->convex_hull], (scale($self->{config}->extruder_clearance_radius) / 2), 1, JT_ROUND, scale(0.1))}; | ||||
|                 $dc->SetPen($self->{clearance_pen}); | ||||
|                 $dc->SetBrush($self->{transparent_brush}); | ||||
|                 $dc->DrawPolygon($self->points_to_pixel($clearance, 1), 0, 0); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     # draw skirt | ||||
|     if (@{$self->{objects}} && $self->{config}->skirts) { | ||||
|         my @points = map @{$_->contour}, map @$_, map @{$_->instance_thumbnails}, @{$self->{objects}}; | ||||
|         if (@points >= 3) { | ||||
|             my ($convex_hull) = @{offset([convex_hull(\@points)], scale($self->{config}->skirt_distance), 1, JT_ROUND, scale(0.1))}; | ||||
|             $dc->SetPen($self->{skirt_pen}); | ||||
|             $dc->SetBrush($self->{transparent_brush}); | ||||
|             $dc->DrawPolygon($self->points_to_pixel($convex_hull, 1), 0, 0); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     $event->Skip; | ||||
| } | ||||
| 
 | ||||
| sub mouse_event { | ||||
|     my ($self, $event) = @_; | ||||
|      | ||||
|     my $point = $event->GetPosition; | ||||
|     my $pos = $self->point_to_model_units([ $point->x, $point->y ]);  #]] | ||||
|     $pos = Slic3r::Point->new_scale(@$pos); | ||||
|     if ($event->ButtonDown(&Wx::wxMOUSE_BTN_LEFT)) { | ||||
|         $self->{on_select_object}->(undef); | ||||
|         for my $obj_idx (0 .. $#{$self->{objects}}) { | ||||
|             my $object = $self->{objects}->[$obj_idx]; | ||||
|             for my $instance_idx (0 .. $#{ $object->instance_thumbnails }) { | ||||
|                 my $thumbnail = $object->instance_thumbnails->[$instance_idx]; | ||||
|                 if (defined first { $_->contour->contains_point($pos) } @$thumbnail) { | ||||
|                     $self->{on_select_object}->($obj_idx); | ||||
|                     my $instance = $self->{model}->objects->[$obj_idx]->instances->[$instance_idx]; | ||||
|                     my $instance_origin = [ map scale($_), @{$instance->offset} ]; | ||||
|                     $self->{drag_start_pos} = [   # displacement between the click and the instance origin in scaled model units | ||||
|                         $pos->x - $instance_origin->[X], | ||||
|                         $pos->y - $instance_origin->[Y],  #- | ||||
|                     ]; | ||||
|                     $self->{drag_object} = [ $obj_idx, $instance_idx ]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         $self->Refresh; | ||||
|     } elsif ($event->ButtonUp(&Wx::wxMOUSE_BTN_LEFT)) { | ||||
|         $self->{on_instance_moved}->(); | ||||
|         $self->Refresh; | ||||
|         $self->{drag_start_pos} = undef; | ||||
|         $self->{drag_object} = undef; | ||||
|         $self->SetCursor(wxSTANDARD_CURSOR); | ||||
|     } elsif ($event->ButtonDClick) { | ||||
|     	$self->{on_double_click}->(); | ||||
|     } elsif ($event->Dragging) { | ||||
|         return if !$self->{drag_start_pos}; # concurrency problems | ||||
|         my ($obj_idx, $instance_idx) = @{ $self->{drag_object} }; | ||||
|         my $model_object = $self->{model}->objects->[$obj_idx]; | ||||
|         $model_object->instances->[$instance_idx]->set_offset( | ||||
|             Slic3r::Pointf->new( | ||||
|                 unscale($pos->[X] - $self->{drag_start_pos}[X]), | ||||
|                 unscale($pos->[Y] - $self->{drag_start_pos}[Y]), | ||||
|             )); | ||||
|         $model_object->update_bounding_box; | ||||
|         $self->Refresh; | ||||
|     } elsif ($event->Moving) { | ||||
|         my $cursor = wxSTANDARD_CURSOR; | ||||
|         if (defined first { $_->contour->contains_point($pos) } map @$_, map @{$_->instance_thumbnails}, @{ $self->{objects} }) { | ||||
|             $cursor = Wx::Cursor->new(wxCURSOR_HAND); | ||||
|         } | ||||
|         $self->SetCursor($cursor); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| sub update_bed_size { | ||||
|     my $self = shift; | ||||
|      | ||||
|     # supposing the preview canvas is square, calculate the scaling factor | ||||
|     # to constrain print bed area inside preview | ||||
|     # when the canvas is not rendered yet, its GetSize() method returns 0,0 | ||||
|     # scaling_factor is expressed in pixel / mm | ||||
|     my $width = $self->GetSize->GetWidth; | ||||
|     $self->{scaling_factor} = $width / max(@{ $self->{config}->bed_size }) | ||||
|         if $width != 0; | ||||
| } | ||||
| 
 | ||||
| sub clean_instance_thumbnails { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     foreach my $object (@{ $self->{objects} }) { | ||||
|         @{ $object->instance_thumbnails } = (); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| # coordinates of the model origin (0,0) in pixels | ||||
| sub model_origin_to_pixel { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     return [ | ||||
|         $self->GetSize->GetWidth/2 - ($self->{config}->print_center->[X] * $self->{scaling_factor}), | ||||
|         $self->GetSize->GetHeight/2 - ($self->{config}->print_center->[Y] * $self->{scaling_factor}), | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| # convert a model coordinate into a pixel coordinate, assuming preview has square shape | ||||
| sub point_to_pixel { | ||||
|     my ($self, $point) = @_; | ||||
|      | ||||
|     my $canvas_height = $self->GetSize->GetHeight; | ||||
|     my $zero = $self->model_origin_to_pixel; | ||||
|     return [ | ||||
|                           $point->[X] * $self->{scaling_factor} + $zero->[X], | ||||
|         $canvas_height - ($point->[Y] * $self->{scaling_factor} + $zero->[Y]), | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| sub points_to_pixel { | ||||
|     my ($self, $points, $unscale) = @_; | ||||
|      | ||||
|     my $result = []; | ||||
|     foreach my $point (@$points) { | ||||
|         $point = [ map unscale($_), @$point ] if $unscale; | ||||
|         push @$result, $self->point_to_pixel($point); | ||||
|     } | ||||
|     return $result; | ||||
| } | ||||
| 
 | ||||
| sub point_to_model_units { | ||||
|     my ($self, $point) = @_; | ||||
|      | ||||
|     my $canvas_height = $self->GetSize->GetHeight; | ||||
|     my $zero = $self->model_origin_to_pixel; | ||||
|     return [ | ||||
|                           ($point->[X] - $zero->[X]) / $self->{scaling_factor}, | ||||
|         (($canvas_height - $point->[Y] - $zero->[Y]) / $self->{scaling_factor}), | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| 1; | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci