Browse Source

3D object positioning

Alessandro Ranellucci 10 years ago
parent
commit
fcfb3b98bc

+ 1 - 0
lib/Slic3r.pm

@@ -197,6 +197,7 @@ sub thread_cleanup {
     *Slic3r::Geometry::BoundingBoxf::DESTROY = sub {};
     *Slic3r::Geometry::BoundingBoxf::DESTROY = sub {};
     *Slic3r::Geometry::BoundingBoxf3::DESTROY = sub {};
     *Slic3r::Geometry::BoundingBoxf3::DESTROY = sub {};
     *Slic3r::Line::DESTROY                  = sub {};
     *Slic3r::Line::DESTROY                  = sub {};
+    *Slic3r::Linef3::DESTROY                = sub {};
     *Slic3r::Model::DESTROY                 = sub {};
     *Slic3r::Model::DESTROY                 = sub {};
     *Slic3r::Model::Object::DESTROY         = sub {};
     *Slic3r::Model::Object::DESTROY         = sub {};
     *Slic3r::Point::DESTROY                 = sub {};
     *Slic3r::Point::DESTROY                 = sub {};

+ 10 - 1
lib/Slic3r/GUI/Plater.pm

@@ -281,6 +281,10 @@ sub new {
     });
     });
     
     
     $self->{canvas}->update_bed_size;
     $self->{canvas}->update_bed_size;
+    if ($self->{canvas3D}) {
+        $self->{canvas3D}->update_bed_size;
+        $self->{canvas3D}->zoom_to_bed;
+    }
     $self->update;
     $self->update;
     
     
     {
     {
@@ -513,6 +517,11 @@ sub objects_loaded {
     }
     }
     $self->arrange unless $params{no_arrange};
     $self->arrange unless $params{no_arrange};
     $self->update;
     $self->update;
+    
+    # zoom to objects
+    $self->{canvas3D}->zoom_to_volumes
+        if $self->{canvas3D};
+    
     $self->{list}->Update;
     $self->{list}->Update;
     $self->{list}->Select($obj_idxs->[-1], 1);
     $self->{list}->Select($obj_idxs->[-1], 1);
     $self->object_list_changed;
     $self->object_list_changed;
@@ -665,7 +674,6 @@ sub rotate {
     
     
     $self->selection_changed;  # refresh info (size etc.)
     $self->selection_changed;  # refresh info (size etc.)
     $self->update;
     $self->update;
-    $self->refresh_canvases;
 }
 }
 
 
 sub flip {
 sub flip {
@@ -1200,6 +1208,7 @@ sub on_config_change {
         $self->{config}->set($opt_key, $config->get($opt_key));
         $self->{config}->set($opt_key, $config->get($opt_key));
         if ($opt_key eq 'bed_shape') {
         if ($opt_key eq 'bed_shape') {
             $self->{canvas}->update_bed_size;
             $self->{canvas}->update_bed_size;
+            $self->{canvas3D}->update_bed_size if $self->{canvas3D};
             $self->update;
             $self->update;
         }
         }
     }
     }

+ 0 - 1
lib/Slic3r/GUI/Plater/2D.pm

@@ -213,7 +213,6 @@ sub mouse_event {
     } elsif ($event->LeftUp) {
     } elsif ($event->LeftUp) {
         $self->{on_instance_moved}->(@{ $self->{drag_object} })
         $self->{on_instance_moved}->(@{ $self->{drag_object} })
             if $self->{drag_object};
             if $self->{drag_object};
-        $self->Refresh;
         $self->{drag_start_pos} = undef;
         $self->{drag_start_pos} = undef;
         $self->{drag_object} = undef;
         $self->{drag_object} = undef;
         $self->SetCursor(wxSTANDARD_CURSOR);
         $self->SetCursor(wxSTANDARD_CURSOR);

+ 24 - 9
lib/Slic3r/GUI/Plater/3D.pm

@@ -16,11 +16,13 @@ sub new {
     
     
     my $self = $class->SUPER::new($parent);
     my $self = $class->SUPER::new($parent);
     $self->enable_picking(1);
     $self->enable_picking(1);
+    $self->enable_moving(1);
     
     
     $self->{objects}            = $objects;
     $self->{objects}            = $objects;
     $self->{model}              = $model;
     $self->{model}              = $model;
     $self->{config}             = $config;
     $self->{config}             = $config;
     $self->{on_select_object}   = sub {};
     $self->{on_select_object}   = sub {};
+    $self->{on_instance_moved}  = sub {};
     
     
     $self->on_select(sub {
     $self->on_select(sub {
         my ($volume_idx) = @_;
         my ($volume_idx) = @_;
@@ -40,6 +42,21 @@ sub new {
         my $obj_idx = $self->{_volumes_inv}{$volume_idx};
         my $obj_idx = $self->{_volumes_inv}{$volume_idx};
         $self->volumes->[$_]->hover(1) for @{$self->{_volumes}{$obj_idx}};
         $self->volumes->[$_]->hover(1) for @{$self->{_volumes}{$obj_idx}};
     });
     });
+    $self->on_move(sub {
+        my ($volume_idx) = @_;
+        
+        my $volume = $self->volumes->[$volume_idx];
+        my $obj_idx = $self->{_volumes_inv}{$volume_idx};
+        my $model_object = $self->{model}->get_object($obj_idx);
+        $model_object
+            ->instances->[$volume->instance_idx]
+            ->offset
+            ->translate($volume->origin->x, $volume->origin->y); #))
+        $model_object->invalidate_bounding_box;
+        
+        $self->{on_instance_moved}->($obj_idx, $volume->instance_idx)
+            if $self->{on_instance_moved};
+    });
     
     
     return $self;
     return $self;
 }
 }
@@ -61,12 +78,7 @@ sub set_on_right_click {
 
 
 sub set_on_instance_moved {
 sub set_on_instance_moved {
     my ($self, $cb) = @_;
     my ($self, $cb) = @_;
-    $self->on_instance_moved(sub {
-        my ($volume_idx, $instance_idx) = @_;
-        
-        my $obj_idx = $self->{_volumes_inv}{$volume_idx};
-        return $cb->($obj_idx, $instance_idx);
-    });
+    $self->{on_instance_moved} = $cb;
 }
 }
 
 
 sub update {
 sub update {
@@ -75,10 +87,8 @@ sub update {
     $self->{_volumes} = {};     # obj_idx => [ volume_idx, volume_idx ]
     $self->{_volumes} = {};     # obj_idx => [ volume_idx, volume_idx ]
     $self->{_volumes_inv} = {}; # volume_idx => obj_idx
     $self->{_volumes_inv} = {}; # volume_idx => obj_idx
     $self->reset_objects;
     $self->reset_objects;
-    return if $self->{model}->objects_count == 0;
     
     
-    $self->set_bounding_box($self->{model}->bounding_box);
-    $self->set_bed_shape($self->{config}->bed_shape);
+    $self->update_bed_size;
     
     
     foreach my $obj_idx (0..$#{$self->{model}->objects}) {
     foreach my $obj_idx (0..$#{$self->{model}->objects}) {
         my $model_object = $self->{model}->get_object($obj_idx);
         my $model_object = $self->{model}->get_object($obj_idx);
@@ -94,4 +104,9 @@ sub update {
     }
     }
 }
 }
 
 
+sub update_bed_size {
+    my ($self) = @_;
+    $self->set_bed_shape($self->{config}->bed_shape);
+}
+
 1;
 1;

+ 1 - 1
lib/Slic3r/GUI/Plater/ObjectCutDialog.pm

@@ -88,10 +88,10 @@ sub new {
     if ($Slic3r::GUI::have_OpenGL) {
     if ($Slic3r::GUI::have_OpenGL) {
         $canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self);
         $canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self);
         $canvas->load_object($self->{model_object});
         $canvas->load_object($self->{model_object});
-        $canvas->set_bounding_box($self->{model_object}->bounding_box);
         $canvas->set_auto_bed_shape;
         $canvas->set_auto_bed_shape;
         $canvas->SetSize([500,500]);
         $canvas->SetSize([500,500]);
         $canvas->SetMinSize($canvas->GetSize);
         $canvas->SetMinSize($canvas->GetSize);
+        $canvas->zoom_to_volumes;
     }
     }
     
     
     $self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
     $self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);

+ 1 - 1
lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm

@@ -70,9 +70,9 @@ sub new {
     if ($Slic3r::GUI::have_OpenGL) {
     if ($Slic3r::GUI::have_OpenGL) {
         $canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self);
         $canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self);
         $canvas->load_object($self->{model_object});
         $canvas->load_object($self->{model_object});
-        $canvas->set_bounding_box($self->{model_object}->bounding_box);
         $canvas->set_auto_bed_shape;
         $canvas->set_auto_bed_shape;
         $canvas->SetSize([500,500]);
         $canvas->SetSize([500,500]);
+        $canvas->zoom_to_volumes;
     }
     }
     
     
     $self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
     $self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);

+ 124 - 77
lib/Slic3r/GUI/PreviewCanvas.pm

@@ -12,26 +12,28 @@ use Slic3r::Geometry qw(X Y Z MIN MAX triangle_normal normalize deg2rad tan scal
 use Slic3r::Geometry::Clipper qw(offset_ex intersection_pl);
 use Slic3r::Geometry::Clipper qw(offset_ex intersection_pl);
 use Wx::GLCanvas qw(:all);
 use Wx::GLCanvas qw(:all);
  
  
-__PACKAGE__->mk_accessors( qw(_quat _dirty init mview_init
-                              object_bounding_box
+__PACKAGE__->mk_accessors( qw(_quat _dirty init
                               enable_picking
                               enable_picking
                               enable_moving
                               enable_moving
                               on_hover
                               on_hover
                               on_select
                               on_select
                               on_double_click
                               on_double_click
                               on_right_click
                               on_right_click
-                              on_instance_moved
+                              on_move
                               volumes
                               volumes
                               print
                               print
                               _sphi _stheta
                               _sphi _stheta
                               cutting_plane_z
                               cutting_plane_z
                               cut_lines_vertices
                               cut_lines_vertices
+                              bed_shape
                               bed_triangles
                               bed_triangles
                               bed_grid_lines
                               bed_grid_lines
                               origin
                               origin
                               _mouse_pos
                               _mouse_pos
+                              _hover_volume_idx
                               _drag_volume_idx
                               _drag_volume_idx
                               _drag_start_pos
                               _drag_start_pos
+                              _drag_start_xy
                               _camera_target
                               _camera_target
                               _zoom
                               _zoom
                               ) );
                               ) );
@@ -61,20 +63,20 @@ sub new {
     $self->_stheta(45);
     $self->_stheta(45);
     $self->_sphi(45);
     $self->_sphi(45);
     $self->_zoom(1);
     $self->_zoom(1);
-    $self->_camera_target(Slic3r::Pointf->new(0,0));
+    
+    # 3D point in model space
+    $self->_camera_target(Slic3r::Pointf3->new(0,0,0));
     
     
     $self->reset_objects;
     $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->object_bounding_box;
         $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->object_bounding_box;
         $self->Resize( $self->GetSizeWH );
         $self->Resize( $self->GetSizeWH );
         $self->Refresh;
         $self->Refresh;
     });
     });
@@ -82,8 +84,10 @@ sub new {
         my ($self, $e) = @_;
         my ($self, $e) = @_;
         
         
         # Calculate the zoom delta and apply it to the current zoom factor
         # Calculate the zoom delta and apply it to the current zoom factor
-        my $zoom = 1 - ($e->GetWheelRotation() / $e->GetWheelDelta() / 10);
-        $self->_zoom($self->_zoom * $zoom);
+        my $zoom = $e->GetWheelRotation() / $e->GetWheelDelta();
+        $zoom = max(min($zoom, 4), -4);
+        $zoom /= 10;
+        $self->_zoom($self->_zoom * (1-$zoom));
         
         
         # In order to zoom around the mouse point we need to translate
         # In order to zoom around the mouse point we need to translate
         # the camera target
         # the camera target
@@ -97,9 +101,10 @@ sub new {
             # in the opposite direction by the delta of the length of such vector
             # in the opposite direction by the delta of the length of such vector
             # ($zoom - 1). We then scale everything by 1/$self->_zoom since 
             # ($zoom - 1). We then scale everything by 1/$self->_zoom since 
             # $self->_camera_target is expressed in terms of model units.
             # $self->_camera_target is expressed in terms of model units.
-            -($pos->x - $size->x/2) * ($zoom - 1) / $self->_zoom,
-            -($pos->y - $size->y/2) * ($zoom - 1) / $self->_zoom,
-        );
+            -($pos->x - $size->x/2) * ($zoom) / $self->_zoom,
+            -($pos->y - $size->y/2) * ($zoom) / $self->_zoom,
+            0,
+        ) if 0;
         $self->_dirty(1);
         $self->_dirty(1);
         $self->Refresh;
         $self->Refresh;
     });
     });
@@ -118,8 +123,7 @@ sub mouse_event {
     } elsif ($e->LeftDown || $e->RightDown) {
     } elsif ($e->LeftDown || $e->RightDown) {
         # If user pressed left or right button we first check whether this happened
         # If user pressed left or right button we first check whether this happened
         # on a volume or not.
         # on a volume or not.
-        my $volume_idx = first { $self->volumes->[$_]->hover } 0..$#{$self->volumes};
-        $volume_idx //= -1;
+        my $volume_idx = $self->_hover_volume_idx // -1;
         
         
         # select volume in this 3D canvas
         # select volume in this 3D canvas
         if ($self->enable_picking) {
         if ($self->enable_picking) {
@@ -146,25 +150,27 @@ sub mouse_event {
         # get volume being dragged
         # get volume being dragged
         my $volume = $self->volumes->[$self->_drag_volume_idx];
         my $volume = $self->volumes->[$self->_drag_volume_idx];
         
         
-        # get new position and calculate the move vector
-        my $cur_pos = $self->mouse_to_3d(@$pos);
+        # get new position at the same Z of the initial click point
+        my $mouse_ray = $self->mouse_ray($e->GetX, $e->GetY);
+        my $cur_pos = $mouse_ray->intersect_plane($self->_drag_start_pos->z);
+        
+        # calculate the translation vector
         my $vector = $self->_drag_start_pos->vector_to($cur_pos);
         my $vector = $self->_drag_start_pos->vector_to($cur_pos);
         
         
         # apply new temporary volume origin and ignore Z
         # apply new temporary volume origin and ignore Z
-        $volume->origin->set_x(-$vector->x);
-        $volume->origin->set_y(-$vector->y);  #))
+        $volume->origin->translate($vector->x, $vector->y, 0); #,,
+        $self->_drag_start_pos($cur_pos);
         $self->Refresh;
         $self->Refresh;
-    } elsif ($e->Dragging) {
-        my $volume_idx = first { $self->volumes->[$_]->hover } 0..$#{$self->volumes};
-        $volume_idx //= -1;
-        
-        if ($e->LeftIsDown && $volume_idx == -1) {
+    } elsif ($e->Dragging && !defined $self->_hover_volume_idx) {
+        if ($e->LeftIsDown) {
             # if dragging over blank area with left button, rotate
             # if dragging over blank area with left button, rotate
             if (defined $self->_drag_start_pos) {
             if (defined $self->_drag_start_pos) {
                 my $orig = $self->_drag_start_pos;
                 my $orig = $self->_drag_start_pos;
                 if (TURNTABLE_MODE) {
                 if (TURNTABLE_MODE) {
                     $self->_sphi($self->_sphi + ($pos->x - $orig->x) * TRACKBALLSIZE);
                     $self->_sphi($self->_sphi + ($pos->x - $orig->x) * TRACKBALLSIZE);
                     $self->_stheta($self->_stheta - ($pos->y - $orig->y) * TRACKBALLSIZE);        #-
                     $self->_stheta($self->_stheta - ($pos->y - $orig->y) * TRACKBALLSIZE);        #-
+                    $self->_stheta(150) if $self->_stheta > 150;
+                    $self->_stheta(0) if $self->_stheta < 0;
                 } else {
                 } else {
                     my $size = $self->GetClientSize;
                     my $size = $self->GetClientSize;
                     my @quat = trackball(
                     my @quat = trackball(
@@ -178,28 +184,27 @@ sub mouse_event {
                 $self->Refresh;
                 $self->Refresh;
             }
             }
             $self->_drag_start_pos($pos);
             $self->_drag_start_pos($pos);
-        } elsif ($e->RightIsDown && $volume_idx == -1) {
+        } elsif ($e->RightIsDown) {
             # if dragging over blank area with right button, translate
             # if dragging over blank area with right button, translate
-            if (defined $self->_drag_start_pos) {
-                my $orig = $self->_drag_start_pos;
-                glMatrixMode(GL_MODELVIEW);
+            
+            if (defined $self->_drag_start_xy) {
+                # get point in model space at Z = 0
+                my $cur_pos = $self->mouse_ray($e->GetX, $e->GetY)->intersect_plane(0);
+                my $orig    = $self->mouse_ray(@{$self->_drag_start_xy})->intersect_plane(0);
                 $self->_camera_target->translate(
                 $self->_camera_target->translate(
-                    ($pos->x - $orig->x) / $self->_zoom,
-                    ($orig->y - $pos->y) / $self->_zoom,  #- (converts to upwards Y)
+                    @{$orig->vector_to($cur_pos)->negative},
                 );
                 );
                 $self->Refresh;
                 $self->Refresh;
             }
             }
-            $self->_drag_start_pos($pos);
+            $self->_drag_start_xy($pos);
         }
         }
     } elsif ($e->LeftUp || $e->RightUp) {
     } elsif ($e->LeftUp || $e->RightUp) {
-        $self->_drag_start_pos(undef);
-        
-        if ($self->on_instance_moved && defined $self->_drag_volume_idx) {
-            my $volume = $self->volumes->[$self->_drag_volume_idx];
-            $self->on_instance_moved($self->_drag_volume_idx, $volume->instance_idx);
+        if ($self->on_move && defined $self->_drag_volume_idx) {
+            $self->on_move->($self->_drag_volume_idx);
         }
         }
         $self->_drag_volume_idx(undef);
         $self->_drag_volume_idx(undef);
         $self->_drag_start_pos(undef);
         $self->_drag_start_pos(undef);
+        $self->_drag_start_xy(undef);
     } elsif ($e->Moving) {
     } elsif ($e->Moving) {
         $self->_mouse_pos($pos);
         $self->_mouse_pos($pos);
         $self->Refresh;
         $self->Refresh;
@@ -215,35 +220,70 @@ sub reset_objects {
     $self->_dirty(1);
     $self->_dirty(1);
 }
 }
 
 
-# this method accepts a Slic3r::BoudingBox3f object
-sub set_bounding_box {
-    my ($self, $bb) = @_;
-    
-    $self->object_bounding_box($bb);
-    $self->zoom_to_bounding_box;
-    $self->_dirty(1);
-}
-
 sub zoom_to_bounding_box {
 sub zoom_to_bounding_box {
-    my ($self) = @_;
+    my ($self, $bb) = @_;
     
     
     # calculate the zoom factor needed to adjust viewport to
     # calculate the zoom factor needed to adjust viewport to
     # bounding box
     # bounding box
-    my $max_size = max(@{$self->object_bounding_box->size}) * sqrt(2);
+    my $max_size = max(@{$bb->size}) * 2;
     my $min_viewport_size = min($self->GetSizeWH);
     my $min_viewport_size = min($self->GetSizeWH);
-    $self->_zoom($min_viewport_size / $max_size / 1.3);
+    $self->_zoom($min_viewport_size / $max_size);
     
     
     # center view around bounding box center
     # center view around bounding box center
-    $self->_camera_target->set_x(0);
-    $self->_camera_target->set_y(0);
+    $self->_camera_target($bb->center);
+}
+
+sub zoom_to_bed {
+    my ($self) = @_;
+    
+    if ($self->bed_shape) {
+        $self->zoom_to_bounding_box($self->bed_bounding_box);
+    }
+}
+
+sub zoom_to_volume {
+    my ($self, $volume_idx) = @_;
+    
+    my $volume = $self->volumes->[$volume_idx];
+    my $bb = $volume->bounding_box;
+    $self->zoom_to_bounding_box($bb);
+}
+
+sub zoom_to_volumes {
+    my ($self) = @_;
+    $self->zoom_to_bounding_box($self->volumes_bounding_box);
+}
+
+sub volumes_bounding_box {
+    my ($self) = @_;
+    
+    my $bb = Slic3r::Geometry::BoundingBoxf3->new;
+    $bb->merge($_->bounding_box) for @{$self->volumes};
+    return $bb;
+}
+
+sub bed_bounding_box {
+    my ($self) = @_;
+    
+    my $bb = Slic3r::Geometry::BoundingBoxf3->new;
+    $bb->merge_point(Slic3r::Pointf3->new(@$_, 0)) for @{$self->bed_shape};
+    return $bb;
+}
+
+sub max_bounding_box {
+    my ($self) = @_;
+    
+    my $bb = $self->bed_bounding_box;
+    $bb->merge($self->volumes_bounding_box);
+    return $bb;
 }
 }
 
 
 sub set_auto_bed_shape {
 sub set_auto_bed_shape {
     my ($self, $bed_shape) = @_;
     my ($self, $bed_shape) = @_;
     
     
     # draw a default square bed around object center
     # draw a default square bed around object center
-    my $max_size = max(@{ $self->object_bounding_box->size });
-    my $center = $self->object_bounding_box->center;
+    my $max_size = max(@{ $self->volumes_bounding_box->size });
+    my $center = $self->volumes_bounding_box->center;
     $self->set_bed_shape([
     $self->set_bed_shape([
         [ $center->x - $max_size, $center->y - $max_size ],  #--
         [ $center->x - $max_size, $center->y - $max_size ],  #--
         [ $center->x + $max_size, $center->y - $max_size ],  #--
         [ $center->x + $max_size, $center->y - $max_size ],  #--
@@ -256,6 +296,8 @@ sub set_auto_bed_shape {
 sub set_bed_shape {
 sub set_bed_shape {
     my ($self, $bed_shape) = @_;
     my ($self, $bed_shape) = @_;
     
     
+    $self->bed_shape($bed_shape);
+    
     # triangulate bed
     # triangulate bed
     my $expolygon = Slic3r::ExPolygon->new([ map [map scale($_), @$_], @$bed_shape ]);
     my $expolygon = Slic3r::ExPolygon->new([ map [map scale($_), @$_], @$bed_shape ]);
     my $bed_bb = $expolygon->bounding_box;
     my $bed_bb = $expolygon->bounding_box;
@@ -318,7 +360,7 @@ sub load_object {
                 instance_idx    => $instance_idx,
                 instance_idx    => $instance_idx,
                 mesh            => $mesh,
                 mesh            => $mesh,
                 color           => $color,
                 color           => $color,
-                origin          => Slic3r::Pointf3->new(0,0,$z_min),
+                origin          => Slic3r::Pointf3->new(0,0,-$z_min),
             );
             );
             push @volumes_idx, $#{$self->volumes};
             push @volumes_idx, $#{$self->volumes};
         
         
@@ -481,18 +523,27 @@ sub mulquats {
 }
 }
 
 
 sub mouse_to_3d {
 sub mouse_to_3d {
-    my ($self, $x, $y) = @_;
+    my ($self, $x, $y, $z) = @_;
 
 
     my @viewport    = glGetIntegerv_p(GL_VIEWPORT);             # 4 items
     my @viewport    = glGetIntegerv_p(GL_VIEWPORT);             # 4 items
     my @mview       = glGetDoublev_p(GL_MODELVIEW_MATRIX);      # 16 items
     my @mview       = glGetDoublev_p(GL_MODELVIEW_MATRIX);      # 16 items
     my @proj        = glGetDoublev_p(GL_PROJECTION_MATRIX);     # 16 items
     my @proj        = glGetDoublev_p(GL_PROJECTION_MATRIX);     # 16 items
     
     
     $y = $viewport[3] - $y;
     $y = $viewport[3] - $y;
-    my $z = glReadPixels_p($x, $y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT);
+    $z //= glReadPixels_p($x, $y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT);
     my @projected = gluUnProject_p($x, $y, $z, @mview, @proj, @viewport);
     my @projected = gluUnProject_p($x, $y, $z, @mview, @proj, @viewport);
     return Slic3r::Pointf3->new(@projected);
     return Slic3r::Pointf3->new(@projected);
 }
 }
 
 
+sub mouse_ray {
+    my ($self, $x, $y) = @_;
+    
+    return Slic3r::Linef3->new(
+        $self->mouse_to_3d($x, $y, 0),
+        $self->mouse_to_3d($x, $y, 1),
+    );
+}
+
 sub GetContext {
 sub GetContext {
     my ($self) = @_;
     my ($self) = @_;
     
     
@@ -513,16 +564,6 @@ sub SetCurrent {
     }
     }
 }
 }
 
 
-sub ResetModelView {
-    my ($self, $factor) = @_;
-    
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-    my $win_size = $self->GetClientSize();
-    my $ratio = $factor * min($win_size->width, $win_size->height) / (2 * max(@{ $self->object_bounding_box->size }));
-    glScalef($ratio, $ratio, 1);
-}
-
 sub Resize {
 sub Resize {
     my ($self, $x, $y) = @_;
     my ($self, $x, $y) = @_;
  
  
@@ -539,14 +580,10 @@ sub Resize {
     glLoadIdentity();
     glLoadIdentity();
     glOrtho(
     glOrtho(
         -$x/2, $x/2, -$y/2, $y/2,
         -$x/2, $x/2, -$y/2, $y/2,
-        -200, 10 * max(@{ $self->object_bounding_box->size }),
+        -200, 10 * max(@{ $self->max_bounding_box->size }),
     );
     );
  
  
     glMatrixMode(GL_MODELVIEW);
     glMatrixMode(GL_MODELVIEW);
-    unless ($self->mview_init) {
-        $self->mview_init(1);
-        $self->ResetModelView(0.9);
-    }
 }
 }
  
  
 sub InitGL {
 sub InitGL {
@@ -614,9 +651,6 @@ sub Render {
     glMatrixMode(GL_MODELVIEW);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     glLoadIdentity();
     
     
-    my $bb = $self->object_bounding_box;
-    my $object_size = $bb->size;
-    glTranslatef(@{ $self->_camera_target }, 0);
     if (TURNTABLE_MODE) {
     if (TURNTABLE_MODE) {
         glRotatef(-$self->_stheta, 1, 0, 0); # pitch
         glRotatef(-$self->_stheta, 1, 0, 0); # pitch
         glRotatef($self->_sphi, 0, 0, 1);    # yaw
         glRotatef($self->_sphi, 0, 0, 1);    # yaw
@@ -624,10 +658,7 @@ sub Render {
         my @rotmat = quat_to_rotmatrix($self->quat);
         my @rotmat = quat_to_rotmatrix($self->quat);
         glMultMatrixd_p(@rotmat[0..15]);
         glMultMatrixd_p(@rotmat[0..15]);
     }
     }
-    
-    # center everything around 0,0 since that's where we're looking at (glOrtho())
-    my $center = $bb->center;
-    glTranslatef(-$center->x, -$center->y, 0); #,,
+    glTranslatef(@{ $self->_camera_target->negative });
     
     
     if ($self->enable_picking) {
     if ($self->enable_picking) {
         glDisable(GL_LIGHTING);
         glDisable(GL_LIGHTING);
@@ -638,8 +669,10 @@ sub Render {
         if (my $pos = $self->_mouse_pos) {
         if (my $pos = $self->_mouse_pos) {
             my $col = [ glReadPixels_p($pos->x, $self->GetSize->GetHeight - $pos->y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE) ];
             my $col = [ glReadPixels_p($pos->x, $self->GetSize->GetHeight - $pos->y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE) ];
             my $volume_idx = $col->[0] + $col->[1]*256 + $col->[2]*256*256;
             my $volume_idx = $col->[0] + $col->[1]*256 + $col->[2]*256*256;
+            $self->_hover_volume_idx(undef);
             $_->hover(0) for @{$self->volumes};
             $_->hover(0) for @{$self->volumes};
             if ($volume_idx <= $#{$self->volumes}) {
             if ($volume_idx <= $#{$self->volumes}) {
+                $self->_hover_volume_idx($volume_idx);
                 $self->volumes->[$volume_idx]->hover(1);
                 $self->volumes->[$volume_idx]->hover(1);
                 $self->on_hover->($volume_idx) if $self->on_hover;
                 $self->on_hover->($volume_idx) if $self->on_hover;
             }
             }
@@ -682,11 +715,16 @@ sub Render {
             glDisableClientState(GL_VERTEX_ARRAY);
             glDisableClientState(GL_VERTEX_ARRAY);
         }
         }
         
         
+        my $volumes_bb = $self->volumes_bounding_box;
+        
         {
         {
             # draw axes
             # draw axes
             $ground_z += 0.02;
             $ground_z += 0.02;
             my $origin = $self->origin;
             my $origin = $self->origin;
-            my $axis_len = 2 * max(@{ $object_size });
+            my $axis_len = max(
+                0.3 * max(@{ $self->bed_bounding_box->size }),
+                  2 * max(@{ $volumes_bb->size }),
+            );
             glLineWidth(2);
             glLineWidth(2);
             glBegin(GL_LINES);
             glBegin(GL_LINES);
             # draw line for x axis
             # draw line for x axis
@@ -707,6 +745,7 @@ sub Render {
         # draw cutting plane
         # draw cutting plane
         if (defined $self->cutting_plane_z) {
         if (defined $self->cutting_plane_z) {
             my $plane_z = $z0 + $self->cutting_plane_z;
             my $plane_z = $z0 + $self->cutting_plane_z;
+            my $bb = $volumes_bb;
             glDisable(GL_CULL_FACE);
             glDisable(GL_CULL_FACE);
             glEnable(GL_BLEND);
             glEnable(GL_BLEND);
             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -804,7 +843,7 @@ sub draw_volumes {
     foreach my $volume_idx (0..$#{$self->volumes}) {
     foreach my $volume_idx (0..$#{$self->volumes}) {
         my $volume = $self->volumes->[$volume_idx];
         my $volume = $self->volumes->[$volume_idx];
         glPushMatrix();
         glPushMatrix();
-        glTranslatef(@{$volume->origin->negative});
+        glTranslatef(@{$volume->origin});
         
         
         glVertexPointer_p(3, $volume->verts);
         glVertexPointer_p(3, $volume->verts);
         
         
@@ -850,4 +889,12 @@ has 'norms'         => (is => 'rw');
 has 'selected'      => (is => 'rw', default => sub { 0 });
 has 'selected'      => (is => 'rw', default => sub { 0 });
 has 'hover'         => (is => 'rw', default => sub { 0 });
 has 'hover'         => (is => 'rw', default => sub { 0 });
 
 
+sub bounding_box {
+    my ($self) = @_;
+    
+    my $bb = $self->mesh->bounding_box;
+    $bb->translate(@{$self->origin});
+    return $bb;
+}
+
 1;
 1;

+ 1 - 1
utils/view-mesh.pl

@@ -36,8 +36,8 @@ my %opt = ();
     $app->{canvas}->enable_picking(1);
     $app->{canvas}->enable_picking(1);
     $app->{canvas}->enable_moving($opt{enable_moving});
     $app->{canvas}->enable_moving($opt{enable_moving});
     $app->{canvas}->load_object($model->objects->[0]);
     $app->{canvas}->load_object($model->objects->[0]);
-    $app->{canvas}->set_bounding_box($model->objects->[0]->bounding_box);
     $app->{canvas}->set_auto_bed_shape;
     $app->{canvas}->set_auto_bed_shape;
+    $app->{canvas}->zoom_to_volumes;
     $app->{canvas}->SetCuttingPlane($opt{cut}) if defined $opt{cut};
     $app->{canvas}->SetCuttingPlane($opt{cut}) if defined $opt{cut};
     $app->MainLoop;
     $app->MainLoop;
 }
 }

+ 1 - 0
xs/lib/Slic3r/XS.pm

@@ -210,6 +210,7 @@ for my $class (qw(
         Slic3r::Layer::Region
         Slic3r::Layer::Region
         Slic3r::Layer::Support
         Slic3r::Layer::Support
         Slic3r::Line
         Slic3r::Line
+        Slic3r::Linef3
         Slic3r::Model
         Slic3r::Model
         Slic3r::Model::Instance
         Slic3r::Model::Instance
         Slic3r::Model::Material
         Slic3r::Model::Material

+ 14 - 0
xs/src/libslic3r/Line.cpp

@@ -184,4 +184,18 @@ Line::to_SV_pureperl() const {
 }
 }
 #endif
 #endif
 
 
+Pointf3
+Linef3::intersect_plane(double z) const
+{
+    return Pointf3(
+        this->a.x + (this->b.x - this->a.x) * (z - this->a.z) / (this->b.z - this->a.z),
+        this->a.y + (this->b.y - this->a.y) * (z - this->a.z) / (this->b.z - this->a.z),
+        z
+    );
+}
+
+#ifdef SLIC3RXS
+REGISTER_CLASS(Linef3, "Linef3");
+#endif
+
 }
 }

Some files were not shown because too many files changed in this diff