Merge branch 'master' into updating

This commit is contained in:
Vojtech Kral 2018-04-24 18:11:34 +02:00
commit a50bde4267
14 changed files with 280 additions and 174 deletions

View File

@ -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
}

View File

@ -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);

View File

@ -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};
}
}

View File

@ -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';
}
}

View File

@ -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

View File

@ -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));

View File

@ -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");

View File

@ -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);

View File

@ -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]);

View File

@ -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"

View File

@ -1288,7 +1288,6 @@ void TabFilament::build()
optgroup->append_single_option_line("filament_loading_speed");
optgroup->append_single_option_line("filament_unloading_speed");
optgroup->append_single_option_line("filament_toolchange_delay");
optgroup->append_single_option_line("filament_cooling_time");
line = { _(L("Ramming")), "" };
line.widget = [this](wxWindow* parent){
auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);

View File

@ -85,8 +85,12 @@ namespace Slic3r {
template<class T>
struct ClassTraits {
// Name of a Perl alias of a C++ class type, owned by Perl, reference counted.
static const char* name;
static const char* name_ref;
// Name of a Perl alias of a C++ class type, owned by the C++ code.
// The references shall be enumerated at the end of XS.pm, where the desctructor is undefined with sub DESTROY {},
// so Perl will never delete the object instance.
static const char* name_ref;
};
// use this for typedefs for which the forward prototype
@ -99,11 +103,16 @@ struct ClassTraits {
class cname; \
__REGISTER_CLASS(cname, perlname);
// Return Perl alias to a C++ class name.
template<class T>
const char* perl_class_name(const T*) { return ClassTraits<T>::name; }
// Return Perl alias to a C++ class name, suffixed with ::Ref.
// Such a C++ class instance will not be destroyed by Perl, the instance destruction is left to the C++ code.
template<class T>
const char* perl_class_name_ref(const T*) { return ClassTraits<T>::name_ref; }
// Mark the Perl SV (Scalar Value) as owning a "blessed" pointer to an object reference.
// Perl will never release the C++ instance.
template<class T>
SV* perl_to_SV_ref(T &t) {
SV* sv = newSV(0);
@ -111,6 +120,8 @@ SV* perl_to_SV_ref(T &t) {
return sv;
}
// Mark the Perl SV (Scalar Value) as owning a "blessed" pointer to an object instance.
// Perl will own the C++ instance, therefore it will also release it.
template<class T>
SV* perl_to_SV_clone_ref(const T &t) {
SV* sv = newSV(0);
@ -118,6 +129,8 @@ SV* perl_to_SV_clone_ref(const T &t) {
return sv;
}
// Reference wrapper to provide a C++ instance to Perl while keeping Perl from destroying the instance.
// The instance is created temporarily by XS.cpp just to provide Perl with a CLASS name and a object instance pointer.
template <class T>
class Ref {
T* val;
@ -125,10 +138,15 @@ public:
Ref() : val(NULL) {}
Ref(T* t) : val(t) {}
Ref(const T* t) : val(const_cast<T*>(t)) {}
// Called by XS.cpp to convert the referenced object instance to a Perl SV, before it is blessed with the name
// returned by CLASS()
operator T*() const { return val; }
// Name to bless the Perl SV with. The name ends with a "::Ref" suffix to keep Perl from destroying the object instance.
static const char* CLASS() { return ClassTraits<T>::name_ref; }
};
// Wrapper to clone a C++ object instance before passing it to Perl for ownership.
// This wrapper instance is created temporarily by XS.cpp to provide Perl with a CLASS name and a object instance pointer.
template <class T>
class Clone {
T* val;
@ -136,7 +154,11 @@ public:
Clone() : val(NULL) {}
Clone(T* t) : val(new T(*t)) {}
Clone(const T& t) : val(new T(t)) {}
// Called by XS.cpp to convert the cloned object instance to a Perl SV, before it is blessed with the name
// returned by CLASS()
operator T*() const { return val; }
// Name to bless the Perl SV with. If there is a destructor registered in the XSP file for this class, then Perl will
// call this destructor when the reference counter of this SV drops to zero.
static const char* CLASS() { return ClassTraits<T>::name; }
};

View File

@ -42,7 +42,7 @@ void add_config_menu(SV *ui, int event_preferences_changed, int event_language_c
void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed)
%code%{ Slic3r::GUI::create_preset_tabs(no_controller, event_value_change, event_presets_changed); %};
Ref<TabIface> get_preset_tab(char *name)
TabIface* get_preset_tab(char *name)
%code%{ RETVAL=Slic3r::GUI::get_preset_tab_iface(name); %};
bool load_language()

View File

@ -213,7 +213,6 @@
%typemap{PresetHints*};
%typemap{Ref<PresetHints>}{simple};
%typemap{TabIface*};
%typemap{Ref<TabIface>}{simple};
%typemap{PrintRegionPtrs*};
%typemap{PrintObjectPtrs*};