Browse Source

Merge branch 'master' into updating

Vojtech Kral 6 years ago
parent
commit
a50bde4267

+ 1 - 0
lib/Slic3r.pm

@@ -162,6 +162,7 @@ sub thread_cleanup {
     *Slic3r::TriangleMesh::DESTROY          = sub {};
     *Slic3r::GUI::AppConfig::DESTROY        = sub {};
     *Slic3r::GUI::PresetBundle::DESTROY     = sub {};
+    *Slic3r::GUI::Tab::DESTROY              = sub {};
     *Slic3r::PresetUpdater::DESTROY         = sub {};
     return undef;  # this prevents a "Scalars leaked" warning
 }

+ 127 - 57
lib/Slic3r/GUI/3DScene.pm

@@ -70,6 +70,7 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init
                               _legend_enabled
                               _warning_enabled
                               _apply_zoom_to_volumes_filter
+                              _mouse_dragging
                                                             
                               ) );
                               
@@ -146,6 +147,7 @@ sub new {
     $self->_warning_enabled(0);
     $self->use_plain_shader(0);
     $self->_apply_zoom_to_volumes_filter(0);
+    $self->_mouse_dragging(0);
 
     # Collection of GLVolume objects
     $self->volumes(Slic3r::GUI::_3DScene::GLVolume::Collection->new);
@@ -199,6 +201,10 @@ sub new {
                 $self->select_view('left');
             } elsif ($key == ord('6')) {
                 $self->select_view('right');
+            } elsif ($key == ord('z')) {
+                $self->zoom_to_volumes;
+            } elsif ($key == ord('b')) {
+                $self->zoom_to_bed;
             } else {
                 $event->Skip;
             }
@@ -381,6 +387,8 @@ sub mouse_event {
     my $pos = Slic3r::Pointf->new($e->GetPositionXY);
     my $object_idx_selected = $self->{layer_height_edit_last_object_id} = ($self->layer_editing_enabled && $self->{print}) ? $self->_first_selected_object_id_for_variable_layer_height_editing : -1;
 
+    $self->_mouse_dragging($e->Dragging);
+    
     if ($e->Entering && &Wx::wxMSW) {
         # wxMSW needs focus in order to catch mouse wheel events
         $self->SetFocus;
@@ -595,22 +603,23 @@ sub mouse_wheel_event {
     $zoom = $zoom_min if defined $zoom_min && $zoom < $zoom_min;
     $self->_zoom($zoom);
     
-    # In order to zoom around the mouse point we need to translate
-    # the camera target
-    my $size = Slic3r::Pointf->new($self->GetSizeWH);
-    my $pos = Slic3r::Pointf->new($e->GetX, $size->y - $e->GetY); #-
-    $self->_camera_target->translate(
-        # ($pos - $size/2) represents the vector from the viewport center
-        # to the mouse point. By multiplying it by $zoom we get the new,
-        # transformed, length of such vector.
-        # Since we want that point to stay fixed, we move our camera target
-        # in the opposite direction by the delta of the length of such vector
-        # ($zoom - 1). We then scale everything by 1/$self->_zoom since 
-        # $self->_camera_target is expressed in terms of model units.
-        -($pos->x - $size->x/2) * ($zoom) / $self->_zoom,
-        -($pos->y - $size->y/2) * ($zoom) / $self->_zoom,
-        0,
-    ) if 0;
+#    # In order to zoom around the mouse point we need to translate
+#    # the camera target
+#    my $size = Slic3r::Pointf->new($self->GetSizeWH);
+#    my $pos = Slic3r::Pointf->new($e->GetX, $size->y - $e->GetY); #-
+#    $self->_camera_target->translate(
+#        # ($pos - $size/2) represents the vector from the viewport center
+#        # to the mouse point. By multiplying it by $zoom we get the new,
+#        # transformed, length of such vector.
+#        # Since we want that point to stay fixed, we move our camera target
+#        # in the opposite direction by the delta of the length of such vector
+#        # ($zoom - 1). We then scale everything by 1/$self->_zoom since 
+#        # $self->_camera_target is expressed in terms of model units.
+#        -($pos->x - $size->x/2) * ($zoom) / $self->_zoom,
+#        -($pos->y - $size->y/2) * ($zoom) / $self->_zoom,
+#        0,
+#    ) if 0;
+
     $self->on_viewport_changed->() if $self->on_viewport_changed;
     $self->Resize($self->GetSizeWH) if $self->IsShownOnScreen;
     $self->Refresh;
@@ -679,9 +688,82 @@ sub select_view {
 
 sub get_zoom_to_bounding_box_factor {
     my ($self, $bb) = @_;
-    return undef if ($bb->empty);
-    my $max_size = max(@{$bb->size}) * 2;
-    return ($max_size == 0) ? undef : min($self->GetSizeWH) / $max_size;
+    my $max_bb_size = max(@{ $bb->size });
+    return undef if ($max_bb_size == 0);
+        
+    # project the bbox vertices on a plane perpendicular to the camera forward axis
+    # then calculates the vertices coordinate on this plane along the camera xy axes
+    
+    # we need the view matrix, we let opengl calculate it (same as done in render sub)
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    if (!TURNTABLE_MODE) {
+        # Shift the perspective camera.
+        my $camera_pos = Slic3r::Pointf3->new(0,0,-$self->_camera_distance);
+        glTranslatef(@$camera_pos);
+    }
+    
+    if (TURNTABLE_MODE) {
+        # Turntable mode is enabled by default.
+        glRotatef(-$self->_stheta, 1, 0, 0); # pitch
+        glRotatef($self->_sphi, 0, 0, 1);    # yaw
+    } else {
+        # Shift the perspective camera.
+        my $camera_pos = Slic3r::Pointf3->new(0,0,-$self->_camera_distance);
+        glTranslatef(@$camera_pos);
+        my @rotmat = quat_to_rotmatrix($self->quat);
+        glMultMatrixd_p(@rotmat[0..15]);
+    }    
+    glTranslatef(@{ $self->_camera_target->negative });
+    
+    # get the view matrix back from opengl
+    my @matrix = glGetFloatv_p(GL_MODELVIEW_MATRIX);
+
+    # camera axes
+    my $right = Slic3r::Pointf3->new($matrix[0], $matrix[4], $matrix[8]);
+    my $up = Slic3r::Pointf3->new($matrix[1], $matrix[5], $matrix[9]);
+    my $forward = Slic3r::Pointf3->new($matrix[2], $matrix[6], $matrix[10]);
+    
+    my $bb_min = $bb->min_point();
+    my $bb_max = $bb->max_point();
+    my $bb_center = $bb->center();
+    
+    # bbox vertices in world space
+    my @vertices = ();    
+    push(@vertices, $bb_min);
+    push(@vertices, Slic3r::Pointf3->new($bb_max->x(), $bb_min->y(), $bb_min->z()));
+    push(@vertices, Slic3r::Pointf3->new($bb_max->x(), $bb_max->y(), $bb_min->z()));
+    push(@vertices, Slic3r::Pointf3->new($bb_min->x(), $bb_max->y(), $bb_min->z()));
+    push(@vertices, Slic3r::Pointf3->new($bb_min->x(), $bb_min->y(), $bb_max->z()));
+    push(@vertices, Slic3r::Pointf3->new($bb_max->x(), $bb_min->y(), $bb_max->z()));
+    push(@vertices, $bb_max);
+    push(@vertices, Slic3r::Pointf3->new($bb_min->x(), $bb_max->y(), $bb_max->z()));
+    
+    my $max_x = 0.0;
+    my $max_y = 0.0;
+
+    # margin factor to give some empty space around the bbox
+    my $margin_factor = 1.25;
+    
+    foreach my $v (@vertices) {
+        # project vertex on the plane perpendicular to camera forward axis
+        my $pos = Slic3r::Pointf3->new($v->x() - $bb_center->x(), $v->y() - $bb_center->y(), $v->z() - $bb_center->z());
+        my $proj_on_normal = $pos->x() * $forward->x() + $pos->y() * $forward->y() + $pos->z() * $forward->z();
+        my $proj_on_plane = Slic3r::Pointf3->new($pos->x() - $proj_on_normal * $forward->x(), $pos->y() - $proj_on_normal * $forward->y(), $pos->z() - $proj_on_normal * $forward->z());
+        
+        # calculates vertex coordinate along camera xy axes
+        my $x_on_plane = $proj_on_plane->x() * $right->x() + $proj_on_plane->y() * $right->y() + $proj_on_plane->z() * $right->z();
+        my $y_on_plane = $proj_on_plane->x() * $up->x() + $proj_on_plane->y() * $up->y() + $proj_on_plane->z() * $up->z();
+    
+        $max_x = max($max_x, $margin_factor * 2 * abs($x_on_plane));
+        $max_y = max($max_y, $margin_factor * 2 * abs($y_on_plane));
+    }
+    
+    my ($cw, $ch) = $self->GetSizeWH;
+    my $min_ratio = min($cw / $max_x, $ch / $max_y);
+
+    return $min_ratio;
 }
 
 sub zoom_to_bounding_box {
@@ -693,6 +775,8 @@ sub zoom_to_bounding_box {
         # center view around bounding box center
         $self->_camera_target($bb->center);
         $self->on_viewport_changed->() if $self->on_viewport_changed;
+        $self->Resize($self->GetSizeWH) if $self->IsShownOnScreen;
+        $self->Refresh;
     }
 }
 
@@ -1027,8 +1111,8 @@ sub Resize {
         #FIXME setting the size of the box 10x larger than necessary
         # is only a workaround for an incorrectly set camera.
         # This workaround harms Z-buffer accuracy!
-#        my $depth = 1.05 * $self->max_bounding_box->radius(); 
-       my $depth = 10.0 * $self->max_bounding_box->radius();
+#        my $depth = 1.05 * $self->max_bounding_box->radius();
+       my $depth = max(@{ $self->max_bounding_box->size });
         glOrtho(
             -$x/2, $x/2, -$y/2, $y/2,
             -$depth, $depth,
@@ -1158,7 +1242,7 @@ sub Render {
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
 
-    {
+    if (!TURNTABLE_MODE) {
         # Shift the perspective camera.
         my $camera_pos = Slic3r::Pointf3->new(0,0,-$self->_camera_distance);
         glTranslatef(@$camera_pos);
@@ -1182,7 +1266,7 @@ sub Render {
     # Head light
     glLightfv_p(GL_LIGHT1, GL_POSITION, 1, 0, 1, 0);
     
-    if ($self->enable_picking) {
+    if ($self->enable_picking && !$self->_mouse_dragging) {
         if (my $pos = $self->_mouse_pos) {
             # Render the object for picking.
             # FIXME This cannot possibly work in a multi-sampled context as the color gets mangled by the anti-aliasing.
@@ -1281,10 +1365,7 @@ sub Render {
         # disable depth testing so that axes are not covered by ground
         glDisable(GL_DEPTH_TEST);
         my $origin = $self->origin;
-        my $axis_len = max(
-            0.3 * max(@{ $self->bed_bounding_box->size }),
-              2 * max(@{ $volumes_bb->size }),
-        );
+        my $axis_len = $self->use_plain_shader ? 0.3 * max(@{ $self->bed_bounding_box->size }) : 2 * max(@{ $volumes_bb->size });
         glLineWidth(2);
         glBegin(GL_LINES);
         # draw line for x axis
@@ -1330,8 +1411,8 @@ sub Render {
         glEnable(GL_CULL_FACE) if ($self->enable_picking);
     }
 
-    # draw cutting plane
     if (defined $self->cutting_plane_z) {
+        # draw cutting plane
         my $plane_z = $self->cutting_plane_z;
         my $bb = $volumes_bb;
         glDisable(GL_CULL_FACE);
@@ -1347,6 +1428,15 @@ sub Render {
         glEnd();
         glEnable(GL_CULL_FACE);
         glDisable(GL_BLEND);
+        
+        # draw cutting contours
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glLineWidth(2);
+        glColor3f(0, 0, 0);
+        glVertexPointer_c(3, GL_FLOAT, 0, $self->cut_lines_vertices->ptr());
+        glDrawArrays(GL_LINES, 0, $self->cut_lines_vertices->elements / 3);
+        glVertexPointer_c(3, GL_FLOAT, 0, 0);
+        glDisableClientState(GL_VERTEX_ARRAY);
     }
 
     # draw warning message
@@ -1393,18 +1483,10 @@ sub draw_volumes {
         $volume->render;
     }
     glDisableClientState(GL_NORMAL_ARRAY);
-    glDisable(GL_BLEND);
-
-    glEnable(GL_CULL_FACE);
-    
-    if (defined $self->cutting_plane_z) {
-        glLineWidth(2);
-        glColor3f(0, 0, 0);
-        glVertexPointer_c(3, GL_FLOAT, 0, $self->cut_lines_vertices->ptr());
-        glDrawArrays(GL_LINES, 0, $self->cut_lines_vertices->elements / 3);
-        glVertexPointer_c(3, GL_FLOAT, 0, 0);
-    }
     glDisableClientState(GL_VERTEX_ARRAY);
+    
+    glDisable(GL_BLEND);
+    glEnable(GL_CULL_FACE);    
 }
 
 sub mark_volumes_for_layer_height {
@@ -1753,8 +1835,8 @@ sub _vertex_shader_Gouraud {
 // normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
 const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
 #define LIGHT_TOP_DIFFUSE    (0.8 * INTENSITY_CORRECTION)
-#define LIGHT_TOP_SPECULAR   (0.25 * INTENSITY_CORRECTION)
-#define LIGHT_TOP_SHININESS  200.0
+#define LIGHT_TOP_SPECULAR   (0.125 * INTENSITY_CORRECTION)
+#define LIGHT_TOP_SHININESS  20.0
 
 // normalized values for (1./1.43, 0.2/1.43, 1./1.43)
 const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
@@ -1784,15 +1866,9 @@ varying vec3 delta_box_max;
 
 void main()
 {
-    vec3 eye = -normalize((gl_ModelViewMatrix * gl_Vertex).xyz);
-
     // First transform the normal into camera space and normalize the result.
     vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
     
-    // Now normalize the light's direction. Note that according to the OpenGL specification, the light is stored in eye space. 
-    // Also since we're talking about a directional light, the position field is actually direction.
-    vec3 halfVector = normalize(LIGHT_TOP_DIR + eye);
-    
     // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
     // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
     float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
@@ -1801,7 +1877,7 @@ void main()
     intensity.y = 0.0;
 
     if (NdotL > 0.0)
-        intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, halfVector), 0.0), LIGHT_TOP_SHININESS);
+        intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
 
     // Perform the same lighting calculation for the 2nd light source (no specular applied).
     NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0);
@@ -1926,8 +2002,8 @@ sub _vertex_shader_variable_layer_height {
 
 const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
 #define LIGHT_TOP_DIFFUSE    (0.8 * INTENSITY_CORRECTION)
-#define LIGHT_TOP_SPECULAR   (0.25 * INTENSITY_CORRECTION)
-#define LIGHT_TOP_SHININESS  200.0
+#define LIGHT_TOP_SPECULAR   (0.125 * INTENSITY_CORRECTION)
+#define LIGHT_TOP_SHININESS  20.0
 
 const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
 #define LIGHT_FRONT_DIFFUSE  (0.3 * INTENSITY_CORRECTION)
@@ -1943,15 +2019,9 @@ varying float object_z;
 
 void main()
 {
-    vec3 eye = -normalize((gl_ModelViewMatrix * gl_Vertex).xyz);
-
     // First transform the normal into camera space and normalize the result.
     vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
     
-    // Now normalize the light's direction. Note that according to the OpenGL specification, the light is stored in eye space. 
-    // Also since we're talking about a directional light, the position field is actually direction.
-    vec3 halfVector = normalize(LIGHT_TOP_DIR + eye);
-    
     // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
     // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
     float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
@@ -1960,7 +2030,7 @@ void main()
     intensity.y = 0.0;
 
     if (NdotL > 0.0)
-        intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, halfVector), 0.0), LIGHT_TOP_SHININESS);
+        intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
 
     // Perform the same lighting calculation for the 2nd light source (no specular)
     NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0);

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

@@ -1677,6 +1677,7 @@ sub update {
 
     $self->{canvas}->reload_scene if $self->{canvas};
     $self->{canvas3D}->reload_scene if $self->{canvas3D};
+    $self->{preview3D}->reset_gcode_preview_data if $self->{preview3D};
     $self->{preview3D}->reload_print if $self->{preview3D};
 }
 
@@ -1856,6 +1857,7 @@ sub object_cut_dialog {
 	    $self->remove($obj_idx);
 	    $self->load_model_objects(grep defined($_), @new_objects);
 	    $self->arrange;
+        $self->{canvas3D}->zoom_to_volumes if $self->{canvas3D};
 	}
 }
 

+ 16 - 24
lib/Slic3r/GUI/Plater/3DPreview.pm

@@ -10,7 +10,7 @@ use base qw(Wx::Panel Class::Accessor);
 
 use Wx::Locale gettext => 'L';
 
-__PACKAGE__->mk_accessors(qw(print gcode_preview_data enabled _loaded canvas slider_low slider_high single_layer auto_zoom));
+__PACKAGE__->mk_accessors(qw(print gcode_preview_data enabled _loaded canvas slider_low slider_high single_layer));
 
 sub new {
     my $class = shift;
@@ -21,7 +21,6 @@ sub new {
     $self->{number_extruders} = 1;
     # Show by feature type by default.
     $self->{preferred_color_mode} = 'feature';
-    $self->auto_zoom(1);
 
     # init GUI elements
     my $canvas = Slic3r::GUI::3DScene->new($self);
@@ -73,6 +72,9 @@ sub new {
     $choice_view_type->Append(L("Tool"));
     $choice_view_type->SetSelection(0);
 
+    # the following value needs to be changed if new items are added into $choice_view_type before "Tool"
+    $self->{tool_idx} = 5;
+    
     my $label_show_features = $self->{label_show_features} = Wx::StaticText->new($self, -1, L("Show"));
     
     my $combochecklist_features = $self->{combochecklist_features} = Wx::ComboCtrl->new();
@@ -205,43 +207,31 @@ sub new {
     });
     EVT_CHOICE($self, $choice_view_type, sub {
         my $selection = $choice_view_type->GetCurrentSelection();
-        $self->{preferred_color_mode} = ($selection == 4) ? 'tool' : 'feature';
+        $self->{preferred_color_mode} = ($selection == $self->{tool_idx}) ? 'tool' : 'feature';
         $self->gcode_preview_data->set_type($selection);
-        $self->auto_zoom(0);
         $self->reload_print;
-        $self->auto_zoom(1);
     });
     EVT_CHECKLISTBOX($self, $combochecklist_features, sub {
         my $flags = Slic3r::GUI::combochecklist_get_flags($combochecklist_features);
         
         $self->gcode_preview_data->set_extrusion_flags($flags);
-        $self->auto_zoom(0);
         $self->refresh_print;
-        $self->auto_zoom(1);
     });    
     EVT_CHECKBOX($self, $checkbox_travel, sub {
         $self->gcode_preview_data->set_travel_visible($checkbox_travel->IsChecked());
-        $self->auto_zoom(0);
         $self->refresh_print;
-        $self->auto_zoom(1);
     });    
     EVT_CHECKBOX($self, $checkbox_retractions, sub {
         $self->gcode_preview_data->set_retractions_visible($checkbox_retractions->IsChecked());
-        $self->auto_zoom(0);
         $self->refresh_print;
-        $self->auto_zoom(1);
     });
     EVT_CHECKBOX($self, $checkbox_unretractions, sub {
         $self->gcode_preview_data->set_unretractions_visible($checkbox_unretractions->IsChecked());
-        $self->auto_zoom(0);
         $self->refresh_print;
-        $self->auto_zoom(1);
     });
     EVT_CHECKBOX($self, $checkbox_shells, sub {
         $self->gcode_preview_data->set_shells_visible($checkbox_shells->IsChecked());
-        $self->auto_zoom(0);
         $self->refresh_print;
-        $self->auto_zoom(1);
     });
     
     $self->SetSizer($main_sizer);
@@ -302,6 +292,12 @@ sub refresh_print {
     $self->load_print;
 }
 
+sub reset_gcode_preview_data {
+    my ($self) = @_;
+    $self->gcode_preview_data->reset;
+    $self->canvas->reset_legend_texture();
+}
+
 sub load_print {
     my ($self) = @_;
     
@@ -341,7 +337,7 @@ sub load_print {
         # It is left to Slic3r to decide whether the print shall be colored by the tool or by the feature.
         # Color by feature if it is a single extruder print.
         my $extruders = $self->{print}->extruders;
-        my $type = (scalar(@{$extruders}) > 1) ? 4 : 0;
+        my $type = (scalar(@{$extruders}) > 1) ? $self->{tool_idx} : 0;
         $self->gcode_preview_data->set_type($type);
         $self->{choice_view_type}->SetSelection($type);
         # If the ->SetSelection changed the following line, revert it to "decide yourself".
@@ -350,7 +346,7 @@ sub load_print {
 
     # Collect colors per extruder.
     my @colors = ();
-    if (! $self->gcode_preview_data->empty() || $self->gcode_preview_data->type == 4) {
+    if (! $self->gcode_preview_data->empty() || $self->gcode_preview_data->type == $self->{tool_idx}) {
         my @extruder_colors = @{$self->{config}->extruder_colour};
         my @filament_colors = @{$self->{config}->filament_colour};
         for (my $i = 0; $i <= $#extruder_colors; $i += 1) {
@@ -374,7 +370,7 @@ sub load_print {
             }
             $self->show_hide_ui_elements('simple');
         } else {
-            $self->{force_sliders_full_range} = (scalar(@{$self->canvas->volumes}) == 0) && $self->auto_zoom;
+            $self->{force_sliders_full_range} = (scalar(@{$self->canvas->volumes}) == 0);
             $self->canvas->load_gcode_preview($self->print, $self->gcode_preview_data, \@colors);
             $self->show_hide_ui_elements('full');
 
@@ -384,10 +380,6 @@ sub load_print {
         }
 
         $self->update_sliders($n_layers);
-                
-        if ($self->auto_zoom) {
-            $self->canvas->zoom_to_volumes;
-        }
         $self->_loaded(1);
     }
 }
@@ -475,11 +467,11 @@ sub set_number_extruders {
     if ($self->{number_extruders} != $number_extruders) {
         $self->{number_extruders} = $number_extruders;
         my $type = ($number_extruders > 1) ?
-              4  # color by a tool number
+              $self->{tool_idx}  # color by a tool number
             : 0; # color by a feature type
         $self->{choice_view_type}->SetSelection($type);
         $self->gcode_preview_data->set_type($type);
-        $self->{preferred_color_mode} = ($type == 4) ? 'tool_or_feature' : 'feature';
+        $self->{preferred_color_mode} = ($type == $self->{tool_idx}) ? 'tool_or_feature' : 'feature';
     }
 }
 

+ 2 - 2
xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp

@@ -67,7 +67,7 @@ public:
 
 	// Set the extruder properties.
 	void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp, float loading_speed,
-                      float unloading_speed, float delay, float cooling_time, std::string ramming_parameters, float nozzle_diameter)
+                      float unloading_speed, float delay, std::string ramming_parameters, float nozzle_diameter)
 	{
         //while (m_filpar.size() < idx+1)   // makes sure the required element is in the vector
         m_filpar.push_back(FilamentParameters());
@@ -78,7 +78,7 @@ public:
         m_filpar[idx].loading_speed = loading_speed;
         m_filpar[idx].unloading_speed = unloading_speed;
         m_filpar[idx].delay = delay;
-        m_filpar[idx].cooling_time = cooling_time;
+        m_filpar[idx].cooling_time = 14.f; // let's fix it for now, cooling moves will be reworked for 1.41 anyway
         m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
 
         m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter

+ 0 - 2
xs/src/libslic3r/Print.cpp

@@ -186,7 +186,6 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
             || opt_key == "filament_loading_speed"
             || opt_key == "filament_unloading_speed"
             || opt_key == "filament_toolchange_delay"
-            || opt_key == "filament_cooling_time"
             || opt_key == "filament_ramming_parameters"
             || opt_key == "gcode_flavor"
             || opt_key == "single_extruder_multi_material"
@@ -1091,7 +1090,6 @@ void Print::_make_wipe_tower()
             this->config.filament_loading_speed.get_at(i),
             this->config.filament_unloading_speed.get_at(i),
             this->config.filament_toolchange_delay.get_at(i),
-            this->config.filament_cooling_time.get_at(i),
             this->config.filament_ramming_parameters.get_at(i),
             this->config.nozzle_diameter.get_at(i));
 

+ 0 - 9
xs/src/libslic3r/PrintConfig.cpp

@@ -481,15 +481,6 @@ PrintConfigDef::PrintConfigDef()
     def->cli = "filament-toolchange-delay=f@";
     def->min = 0;
     def->default_value = new ConfigOptionFloats { 0. };
-    
-    def = this->add("filament_cooling_time", coFloats);
-    def->label = L("Cooling time");
-    def->tooltip = L("The filament is slowly moved back and forth after retraction into the cooling tube "
-                   "for this amount of time.");
-    def->cli = "filament_cooling_time=i@";
-    def->sidetext = L("s");
-    def->min = 0;
-    def->default_value = new ConfigOptionFloats { 14.f };
 
     def = this->add("filament_ramming_parameters", coStrings);
     def->label = L("Ramming parameters");

+ 0 - 2
xs/src/libslic3r/PrintConfig.hpp

@@ -476,7 +476,6 @@ public:
     ConfigOptionFloats              filament_loading_speed;
     ConfigOptionFloats              filament_unloading_speed;
     ConfigOptionFloats              filament_toolchange_delay;
-    ConfigOptionFloats              filament_cooling_time;
     ConfigOptionStrings             filament_ramming_parameters;
     ConfigOptionBool                gcode_comments;
     ConfigOptionEnum<GCodeFlavor>   gcode_flavor;
@@ -534,7 +533,6 @@ protected:
         OPT_PTR(filament_loading_speed);
         OPT_PTR(filament_unloading_speed);
         OPT_PTR(filament_toolchange_delay);
-        OPT_PTR(filament_cooling_time);
         OPT_PTR(filament_ramming_parameters);
         OPT_PTR(gcode_comments);
         OPT_PTR(gcode_flavor);

+ 106 - 72
xs/src/slic3r/GUI/3DScene.cpp

@@ -788,15 +788,14 @@ static void thick_lines_to_indexed_vertex_array(
 #define TOP     2
 #define BOTTOM  3
 
-    Line prev_line;
     // right, left, top, bottom
     int     idx_prev[4]      = { -1, -1, -1, -1 };
     double  bottom_z_prev    = 0.;
     Pointf  b1_prev;
-    Pointf  b2_prev;
     Vectorf v_prev;
     int     idx_initial[4]   = { -1, -1, -1, -1 };
     double  width_initial    = 0.;
+    double  bottom_z_initial = 0.0;
 
     // loop once more in case of closed loops
     size_t lines_end = closed ? (lines.size() + 1) : lines.size();
@@ -804,13 +803,18 @@ static void thick_lines_to_indexed_vertex_array(
         size_t i = (ii == lines.size()) ? 0 : ii;
         const Line &line = lines[i];
         double len = unscale(line.length());
+        double inv_len = 1.0 / len;
         double bottom_z = top_z - heights[i];
-        double middle_z = (top_z + bottom_z) / 2.;
+        double middle_z = 0.5 * (top_z + bottom_z);
         double width = widths[i];
-        
+
+        bool is_first = (ii == 0);
+        bool is_last = (ii == lines_end - 1);
+        bool is_closing = closed && is_last;
+
         Vectorf v = Vectorf::new_unscale(line.vector());
-        v.scale(1. / len);
-        
+        v.scale(inv_len);
+
         Pointf a = Pointf::new_unscale(line.a);
         Pointf b = Pointf::new_unscale(line.b);
         Pointf a1 = a;
@@ -818,17 +822,19 @@ static void thick_lines_to_indexed_vertex_array(
         Pointf b1 = b;
         Pointf b2 = b;
         {
-            double dist = width / 2.;  // scaled
-            a1.translate(+dist*v.y, -dist*v.x);
-            a2.translate(-dist*v.y, +dist*v.x);
-            b1.translate(+dist*v.y, -dist*v.x);
-            b2.translate(-dist*v.y, +dist*v.x);
+            double dist = 0.5 * width;  // scaled
+            double dx = dist * v.x;
+            double dy = dist * v.y;
+            a1.translate(+dy, -dx);
+            a2.translate(-dy, +dx);
+            b1.translate(+dy, -dx);
+            b2.translate(-dy, +dx);
         }
 
         // calculate new XY normals
         Vector n = line.normal();
         Vectorf3 xy_right_normal = Vectorf3::new_unscale(n.x, n.y, 0);
-        xy_right_normal.scale(1.f / len);
+        xy_right_normal.scale(inv_len);
 
         int idx_a[4];
         int idx_b[4];
@@ -837,14 +843,21 @@ static void thick_lines_to_indexed_vertex_array(
         bool bottom_z_different = bottom_z_prev != bottom_z;
         bottom_z_prev = bottom_z;
 
+        if (!is_first && bottom_z_different)
+        {
+            // Found a change of the layer thickness -> Add a cap at the end of the previous segment.
+            volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]);
+        }
+
         // Share top / bottom vertices if possible.
-        if (ii == 0) {
-            idx_a[TOP] = idx_last ++;
+        if (is_first) {
+            idx_a[TOP] = idx_last++;
             volume.push_geometry(a.x, a.y, top_z   , 0., 0.,  1.); 
         } else {
             idx_a[TOP] = idx_prev[TOP];
         }
-        if (ii == 0 || bottom_z_different) {
+
+        if (is_first || bottom_z_different) {
             // Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
             idx_a[BOTTOM] = idx_last ++;
             volume.push_geometry(a.x, a.y, bottom_z, 0., 0., -1.);
@@ -852,13 +865,15 @@ static void thick_lines_to_indexed_vertex_array(
             volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
             idx_a[RIGHT] = idx_last ++;
             volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
-        } else {
+        }
+        else {
             idx_a[BOTTOM] = idx_prev[BOTTOM];
         }
 
-        if (ii == 0) {
+        if (is_first) {
             // Start of the 1st line segment.
             width_initial    = width;
+            bottom_z_initial = bottom_z;
             memcpy(idx_initial, idx_a, sizeof(int) * 4);
         } else {
             // Continuing a previous segment.
@@ -866,43 +881,54 @@ static void thick_lines_to_indexed_vertex_array(
 			double v_dot    = dot(v_prev, v);
             bool   sharp    = v_dot < 0.707; // sin(45 degrees)
             if (sharp) {
-                // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
-                idx_a[RIGHT] = idx_last ++;
-                volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
-                idx_a[LEFT ] = idx_last ++;
-                volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
+                if (!bottom_z_different)
+                {
+                    // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
+                    idx_a[RIGHT] = idx_last++;
+                    volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
+                    idx_a[LEFT] = idx_last++;
+                    volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
+                }
             }
             if (v_dot > 0.9) {
-                // The two successive segments are nearly collinear.
-                idx_a[LEFT ] = idx_prev[LEFT];
-                idx_a[RIGHT] = idx_prev[RIGHT];
-            } else if (! sharp) {
-                // Create a sharp corner with an overshot and average the left / right normals.
-                // At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc.
-                Pointf intersection;
-                Geometry::ray_ray_intersection(b1_prev, v_prev, a1, v, intersection);
-                a1 = intersection;
-                a2 = 2. * a - intersection;
-                assert(length(a1.vector_to(a)) < width);
-                assert(length(a2.vector_to(a)) < width);
-                float *n_left_prev  = volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6;
-                float *p_left_prev  = n_left_prev  + 3;
-                float *n_right_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6;
-                float *p_right_prev = n_right_prev + 3;
-                p_left_prev [0] = float(a2.x);
-                p_left_prev [1] = float(a2.y);
-                p_right_prev[0] = float(a1.x);
-                p_right_prev[1] = float(a1.y);
-                xy_right_normal.x += n_right_prev[0];
-                xy_right_normal.y += n_right_prev[1];
-                xy_right_normal.scale(1. / length(xy_right_normal));
-                n_left_prev [0] = float(-xy_right_normal.x);
-                n_left_prev [1] = float(-xy_right_normal.y);
-                n_right_prev[0] = float( xy_right_normal.x);
-                n_right_prev[1] = float( xy_right_normal.y);
-                idx_a[LEFT ] = idx_prev[LEFT ];
-                idx_a[RIGHT] = idx_prev[RIGHT];
-            } else if (cross(v_prev, v) > 0.) {
+                if (!bottom_z_different)
+                {
+                    // The two successive segments are nearly collinear.
+                    idx_a[LEFT ] = idx_prev[LEFT];
+                    idx_a[RIGHT] = idx_prev[RIGHT];
+                }
+            }
+            else if (!sharp) {
+                if (!bottom_z_different)
+                {
+                    // Create a sharp corner with an overshot and average the left / right normals.
+                    // At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc.
+                    Pointf intersection;
+                    Geometry::ray_ray_intersection(b1_prev, v_prev, a1, v, intersection);
+                    a1 = intersection;
+                    a2 = 2. * a - intersection;
+                    assert(length(a1.vector_to(a)) < width);
+                    assert(length(a2.vector_to(a)) < width);
+                    float *n_left_prev  = volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6;
+                    float *p_left_prev  = n_left_prev  + 3;
+                    float *n_right_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6;
+                    float *p_right_prev = n_right_prev + 3;
+                    p_left_prev [0] = float(a2.x);
+                    p_left_prev [1] = float(a2.y);
+                    p_right_prev[0] = float(a1.x);
+                    p_right_prev[1] = float(a1.y);
+                    xy_right_normal.x += n_right_prev[0];
+                    xy_right_normal.y += n_right_prev[1];
+                    xy_right_normal.scale(1. / length(xy_right_normal));
+                    n_left_prev [0] = float(-xy_right_normal.x);
+                    n_left_prev [1] = float(-xy_right_normal.y);
+                    n_right_prev[0] = float( xy_right_normal.x);
+                    n_right_prev[1] = float( xy_right_normal.y);
+                    idx_a[LEFT ] = idx_prev[LEFT ];
+                    idx_a[RIGHT] = idx_prev[RIGHT];
+                }
+            }
+            else if (cross(v_prev, v) > 0.) {
                 // Right turn. Fill in the right turn wedge.
                 volume.push_triangle(idx_prev[RIGHT], idx_a   [RIGHT],  idx_prev[TOP]   );
                 volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a   [RIGHT] );
@@ -911,18 +937,21 @@ static void thick_lines_to_indexed_vertex_array(
                 volume.push_triangle(idx_prev[LEFT],  idx_prev[TOP],    idx_a   [LEFT]  );
                 volume.push_triangle(idx_prev[LEFT],  idx_a   [LEFT],   idx_prev[BOTTOM]);
             }
-            if (ii == lines.size()) {
-                if (! sharp) {
-                    // Closing a loop with smooth transition. Unify the closing left / right vertices.
-                    memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT ] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6, sizeof(float) * 6);
-                    memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6);
-                    volume.vertices_and_normals_interleaved.erase(volume.vertices_and_normals_interleaved.end() - 12, volume.vertices_and_normals_interleaved.end());
-                    // Replace the left / right vertex indices to point to the start of the loop. 
-                    for (size_t u = volume.quad_indices.size() - 16; u < volume.quad_indices.size(); ++ u) {
-                        if (volume.quad_indices[u] == idx_prev[LEFT])
-                            volume.quad_indices[u] = idx_initial[LEFT];
-                        else if (volume.quad_indices[u] == idx_prev[RIGHT])
-                            volume.quad_indices[u] = idx_initial[RIGHT];
+            if (is_closing) {
+                if (!sharp) {
+                    if (!bottom_z_different)
+                    {
+                        // Closing a loop with smooth transition. Unify the closing left / right vertices.
+                        memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT ] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6, sizeof(float) * 6);
+                        memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6);
+                        volume.vertices_and_normals_interleaved.erase(volume.vertices_and_normals_interleaved.end() - 12, volume.vertices_and_normals_interleaved.end());
+                        // Replace the left / right vertex indices to point to the start of the loop. 
+                        for (size_t u = volume.quad_indices.size() - 16; u < volume.quad_indices.size(); ++ u) {
+                            if (volume.quad_indices[u] == idx_prev[LEFT])
+                                volume.quad_indices[u] = idx_initial[LEFT];
+                            else if (volume.quad_indices[u] == idx_prev[RIGHT])
+                                volume.quad_indices[u] = idx_initial[RIGHT];
+                        }
                     }
                 }
                 // This is the last iteration, only required to solve the transition.
@@ -931,13 +960,14 @@ static void thick_lines_to_indexed_vertex_array(
         }
 
         // Only new allocate top / bottom vertices, if not closing a loop.
-        if (closed && ii + 1 == lines.size()) {
+        if (is_closing) {
             idx_b[TOP] = idx_initial[TOP];
         } else {
             idx_b[TOP] = idx_last ++;
             volume.push_geometry(b.x, b.y, top_z   , 0., 0.,  1.);
         }
-        if (closed && ii + 1 == lines.size() && width == width_initial) {
+
+        if (is_closing && (width == width_initial) && (bottom_z == bottom_z_initial)) {
             idx_b[BOTTOM] = idx_initial[BOTTOM];
         } else {
             idx_b[BOTTOM] = idx_last ++;
@@ -949,22 +979,26 @@ static void thick_lines_to_indexed_vertex_array(
         idx_b[RIGHT ] = idx_last ++;
         volume.push_geometry(b1.x, b1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
 
-        prev_line = line;
         memcpy(idx_prev, idx_b, 4 * sizeof(int));
         bottom_z_prev = bottom_z;
         b1_prev = b1;
-        b2_prev = b2;
-        v_prev  = v;
+        v_prev = v;
+
+        if (bottom_z_different)
+        {
+            // Found a change of the layer thickness -> Add a cap at the beginning of this segment.
+            volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]);
+        }
 
         if (! closed) {
             // Terminate open paths with caps.
-            if (i == 0)
+            if (is_first && !bottom_z_different)
                 volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]);
             // We don't use 'else' because both cases are true if we have only one line.
-            if (i + 1 == lines.size())
+            if (is_last && !bottom_z_different)
                 volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]);
         }
-        
+
         // Add quads for a straight hollow tube-like segment.
         // bottom-right face
         volume.push_quad(idx_a[BOTTOM], idx_b[BOTTOM], idx_b[RIGHT], idx_a[RIGHT]);

+ 1 - 1
xs/src/slic3r/GUI/Preset.cpp

@@ -297,7 +297,7 @@ const std::vector<std::string>& Preset::filament_options()
     static std::vector<std::string> s_opts {
         "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
         "extrusion_multiplier", "filament_density", "filament_cost", "filament_loading_speed", "filament_unloading_speed", "filament_toolchange_delay",
-        "filament_cooling_time", "filament_ramming_parameters", "temperature", "first_layer_temperature", "bed_temperature",
+        "filament_ramming_parameters", "temperature", "first_layer_temperature", "bed_temperature",
         "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers",
         "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", "start_filament_gcode", "end_filament_gcode","compatible_printers",
         "compatible_printers_condition", "inherits"

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