Store / retrieve layer height profile from the AMF file.
Reset the layer height profile when changing a print profile to an incompatible one. Reset button on the layer height bar. Fixed an update issue on zooming by a scroll wheel. Fixed an issue when loading an AMF file: Object names are now retained.
This commit is contained in:
parent
61c0ae4e94
commit
88e34ff5de
@ -61,8 +61,13 @@ sub write_file {
|
||||
if ($object->name) {
|
||||
printf $fh qq{ <metadata type=\"name\">%s</metadata>\n}, $object->name;
|
||||
}
|
||||
my $layer_height_profile = $object->layer_height_profile();
|
||||
my $layer_height_profile_pts = int(@{$layer_height_profile});
|
||||
if ($layer_height_profile_pts >= 4 && $layer_height_profile_pts % 2 == 0) {
|
||||
# Store the layer height profile as a single semicolon separated list.
|
||||
print $fh ' <metadata type="slic3r.layer_height_profile">', join(';', @{$layer_height_profile}), "</metadata>\n";
|
||||
}
|
||||
#FIXME Store the layer height ranges (ModelObject::layer_height_ranges)
|
||||
#FIXME Store the layer height profile.
|
||||
|
||||
printf $fh qq{ <mesh>\n};
|
||||
printf $fh qq{ <vertices>\n};
|
||||
|
@ -98,7 +98,10 @@ sub end_element {
|
||||
$self->{_material} = undef;
|
||||
} elsif ($data->{LocalName} eq 'metadata') {
|
||||
my $value = $self->{_metadata_value};
|
||||
if ($self->{_metadata_type} =~ /^slic3r\.(.+)/) {
|
||||
if ($self->{_metadata_type} eq 'slic3r.layer_height_profile') {
|
||||
my @layer_height_profile = split(';', $value);
|
||||
$self->{_object}->set_layer_height_profile(\@layer_height_profile) if ($self->{_object});
|
||||
} elsif ($self->{_metadata_type} =~ /^slic3r\.(.+)/) {
|
||||
my $opt_key = $1;
|
||||
if (exists $Slic3r::Config::Options->{$opt_key}) {
|
||||
my $config;
|
||||
@ -114,10 +117,9 @@ sub end_element {
|
||||
} elsif ($opt_key eq 'modifier' && $self->{_volume}) {
|
||||
$self->{_volume}->set_modifier($value);
|
||||
}
|
||||
} elsif ($self->{_metadata_type} eq 'name' && $self->{_volume}) {
|
||||
$self->{_volume}->set_name($value);
|
||||
} elsif ($self->{_metadata_type} eq 'name' && $self->{_object}) {
|
||||
$self->{_object}->set_name($value);
|
||||
} elsif ($self->{_metadata_type} eq 'name') {
|
||||
my $obj = $self->{_volume} // $self->{_object};
|
||||
$obj->set_name($value) if $obj;
|
||||
} elsif ($self->{_material}) {
|
||||
$self->{_material}->set_attribute($self->{_metadata_type}, $value);
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init
|
||||
on_double_click
|
||||
on_right_click
|
||||
on_move
|
||||
on_model_update
|
||||
volumes
|
||||
_sphi _stheta
|
||||
cutting_plane_z
|
||||
@ -94,6 +95,9 @@ use constant MANIPULATION_LAYER_HEIGHT => 2;
|
||||
|
||||
use constant GIMBALL_LOCK_THETA_MAX => 170;
|
||||
|
||||
use constant VARIABLE_LAYER_THICKNESS_BAR_WIDTH => 70;
|
||||
use constant VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT => 22;
|
||||
|
||||
# make OpenGL::Array thread-safe
|
||||
{
|
||||
no warnings 'redefine';
|
||||
@ -171,7 +175,7 @@ sub new {
|
||||
$self->{layer_height_edit_timer} = Wx::Timer->new($self, $self->{layer_height_edit_timer_id});
|
||||
EVT_TIMER($self, $self->{layer_height_edit_timer_id}, sub {
|
||||
my ($self, $event) = @_;
|
||||
return if ! $self->_layer_height_edited;
|
||||
return if $self->_layer_height_edited != 1;
|
||||
return if $self->{layer_height_edit_last_object_id} == -1;
|
||||
$self->_variable_layer_thickness_action(undef);
|
||||
});
|
||||
@ -197,25 +201,60 @@ sub _first_selected_object_id {
|
||||
}
|
||||
|
||||
# Returns an array with (left, top, right, bottom) of the variable layer thickness bar on the screen.
|
||||
sub _variable_layer_thickness_bar_rect {
|
||||
sub _variable_layer_thickness_bar_rect_screen {
|
||||
my ($self) = @_;
|
||||
my ($cw, $ch) = $self->GetSizeWH;
|
||||
my $bar_width = 70;
|
||||
return ($cw - $bar_width, 0, $cw, $ch);
|
||||
return ($cw - VARIABLE_LAYER_THICKNESS_BAR_WIDTH, 0, $cw, $ch - VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT);
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_bar_rect_viewport {
|
||||
my ($self) = @_;
|
||||
my ($cw, $ch) = $self->GetSizeWH;
|
||||
return ((0.5*$cw-VARIABLE_LAYER_THICKNESS_BAR_WIDTH)/$self->_zoom, (-0.5*$ch+VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT)/$self->_zoom, $cw/(2*$self->_zoom), $ch/(2*$self->_zoom));
|
||||
}
|
||||
|
||||
# Returns an array with (left, top, right, bottom) of the variable layer thickness bar on the screen.
|
||||
sub _variable_layer_thickness_reset_rect_screen {
|
||||
my ($self) = @_;
|
||||
my ($cw, $ch) = $self->GetSizeWH;
|
||||
return ($cw - VARIABLE_LAYER_THICKNESS_BAR_WIDTH, $ch - VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT, $cw, $ch);
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_reset_rect_viewport {
|
||||
my ($self) = @_;
|
||||
my ($cw, $ch) = $self->GetSizeWH;
|
||||
return ((0.5*$cw-VARIABLE_LAYER_THICKNESS_BAR_WIDTH)/$self->_zoom, -$ch/(2*$self->_zoom), $cw/(2*$self->_zoom), (-0.5*$ch+VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT)/$self->_zoom);
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_bar_rect_mouse_inside {
|
||||
my ($self, $mouse_evt) = @_;
|
||||
my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_bar_rect;
|
||||
my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_bar_rect_screen;
|
||||
return $mouse_evt->GetX >= $bar_left && $mouse_evt->GetX <= $bar_right && $mouse_evt->GetY >= $bar_top && $mouse_evt->GetY <= $bar_bottom;
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_reset_rect_mouse_inside {
|
||||
my ($self, $mouse_evt) = @_;
|
||||
my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_reset_rect_screen;
|
||||
return $mouse_evt->GetX >= $bar_left && $mouse_evt->GetX <= $bar_right && $mouse_evt->GetY >= $bar_top && $mouse_evt->GetY <= $bar_bottom;
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_bar_mouse_cursor_z {
|
||||
my ($self, $object_idx, $mouse_evt) = @_;
|
||||
my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_bar_rect;
|
||||
my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_bar_rect_screen;
|
||||
return unscale($self->{print}->get_object($object_idx)->size->z) * ($bar_bottom - $mouse_evt->GetY - 1.) / ($bar_bottom - $bar_top);
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_bar_mouse_cursor_z_relative {
|
||||
my ($self) = @_;
|
||||
my $mouse_pos = $self->ScreenToClientPoint(Wx::GetMousePosition());
|
||||
my ($bar_left, $bar_top, $bar_right, $bar_bottom) = $self->_variable_layer_thickness_bar_rect_screen;
|
||||
return ($mouse_pos->x >= $bar_left && $mouse_pos->x <= $bar_right && $mouse_pos->y >= $bar_top && $mouse_pos->y <= $bar_bottom) ?
|
||||
# Inside the bar.
|
||||
($bar_bottom - $mouse_pos->y - 1.) / ($bar_bottom - $bar_top - 1) :
|
||||
# Outside the bar.
|
||||
-1000.;
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_action {
|
||||
my ($self, $mouse_event, $do_modification) = @_;
|
||||
# A volume is selected. Test, whether hovering over a layer thickness bar.
|
||||
@ -224,6 +263,8 @@ sub _variable_layer_thickness_action {
|
||||
$self->{layer_height_edit_last_action} = $mouse_event->ShiftDown ? ($mouse_event->RightIsDown ? 3 : 2) : ($mouse_event->RightIsDown ? 0 : 1);
|
||||
}
|
||||
if ($self->{layer_height_edit_last_object_id} != -1) {
|
||||
# Mark the volume as modified, so Print will pick its layer height profile? Where to mark it?
|
||||
# Start a timer to refresh the print? schedule_background_process() ?
|
||||
$self->{print}->get_object($self->{layer_height_edit_last_object_id})->adjust_layer_height_profile(
|
||||
$self->{layer_height_edit_last_z},
|
||||
$self->{layer_height_edit_strength},
|
||||
@ -263,6 +304,11 @@ sub mouse_event {
|
||||
# Start editing the layer height.
|
||||
$self->_layer_height_edited(1);
|
||||
$self->_variable_layer_thickness_action($e);
|
||||
} elsif ($object_idx_selected != -1 && $self->_variable_layer_thickness_reset_rect_mouse_inside($e)) {
|
||||
$self->{print}->get_object($self->{layer_height_edit_last_object_id})->reset_layer_height_profile;
|
||||
# Index 2 means no editing, just wait for mouse up event.
|
||||
$self->_layer_height_edited(2);
|
||||
$self->Refresh;
|
||||
} else {
|
||||
# Select volume in this 3D canvas.
|
||||
# Don't deselect a volume if layer editing is enabled. We want the object to stay selected
|
||||
@ -325,7 +371,7 @@ sub mouse_event {
|
||||
$self->Refresh;
|
||||
} elsif ($e->Dragging) {
|
||||
if ($self->_layer_height_edited && $object_idx_selected != -1) {
|
||||
$self->_variable_layer_thickness_action($e);
|
||||
$self->_variable_layer_thickness_action($e) if ($self->_layer_height_edited == 1);
|
||||
} elsif ($e->LeftIsDown) {
|
||||
# if dragging over blank area with left button, rotate
|
||||
if (defined $self->_drag_start_pos) {
|
||||
@ -365,7 +411,12 @@ sub mouse_event {
|
||||
$self->_drag_start_xy($pos);
|
||||
}
|
||||
} elsif ($e->LeftUp || $e->MiddleUp || $e->RightUp) {
|
||||
if ($self->on_move && defined($self->_drag_volume_idx) && $self->_dragged) {
|
||||
if ($self->_layer_height_edited) {
|
||||
$self->_layer_height_edited(undef);
|
||||
$self->{layer_height_edit_timer}->Stop;
|
||||
$self->on_model_update->()
|
||||
if ($object_idx_selected != -1 && $self->on_model_update);
|
||||
} elsif ($self->on_move && defined($self->_drag_volume_idx) && $self->_dragged) {
|
||||
# get all volumes belonging to the same group, if any
|
||||
my @volume_idxs;
|
||||
my $group_id = $self->volumes->[$self->_drag_volume_idx]->drag_group_id;
|
||||
@ -381,8 +432,6 @@ sub mouse_event {
|
||||
$self->_drag_start_pos(undef);
|
||||
$self->_drag_start_xy(undef);
|
||||
$self->_dragged(undef);
|
||||
$self->_layer_height_edited(undef);
|
||||
$self->{layer_height_edit_timer}->Stop;
|
||||
} elsif ($e->Moving) {
|
||||
$self->_mouse_pos($pos);
|
||||
# Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor
|
||||
@ -432,7 +481,7 @@ sub mouse_wheel_event {
|
||||
0,
|
||||
) if 0;
|
||||
$self->on_viewport_changed->() if $self->on_viewport_changed;
|
||||
$self->_dirty(1);
|
||||
$self->Resize($self->GetSizeWH) if $self->IsShownOnScreen;
|
||||
$self->Refresh;
|
||||
}
|
||||
|
||||
@ -1111,29 +1160,21 @@ sub draw_volumes {
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
# The viewport and camera are set to complete view and glOrtho(-$x/2, $x/2, -$y/2, $y/2, -$depth, $depth),
|
||||
# where x, y is the window size divided by $self->_zoom.
|
||||
my ($cw, $ch) = $self->GetSizeWH;
|
||||
my $bar_width = 70;
|
||||
my ($bar_left, $bar_right) = ((0.5 * $cw - $bar_width)/$self->_zoom, $cw/(2*$self->_zoom));
|
||||
my ($bar_bottom, $bar_top) = (-$ch/(2*$self->_zoom), $ch/(2*$self->_zoom));
|
||||
my $mouse_pos = $self->ScreenToClientPoint(Wx::GetMousePosition());
|
||||
my $z_cursor_relative = ($mouse_pos->x < $cw - $bar_width) ? -1000. :
|
||||
($ch - $mouse_pos->y - 1.) / ($ch - 1);
|
||||
|
||||
my $z_cursor_relative = $self->_variable_layer_thickness_bar_mouse_cursor_z_relative;
|
||||
foreach my $volume_idx (0..$#{$self->volumes}) {
|
||||
my $volume = $self->volumes->[$volume_idx];
|
||||
|
||||
my $shader_active = 0;
|
||||
if ($self->layer_editing_enabled && ! $fakecolor && $volume->selected && $self->{shader} && $volume->{layer_height_texture_data}) {
|
||||
my $print_object = $self->{print}->get_object(int($volume->select_group_id / 1000000));
|
||||
if (! defined($volume->{layer_height_texture_cells}) || $print_object->update_layer_height_profile) {
|
||||
# Layer height profile was invalid before, now filled in with default data from layer height configuration
|
||||
# and possibly from the layer height modifiers. Update the height texture.
|
||||
$volume->{layer_height_texture_cells} = $print_object->generate_layer_height_texture(
|
||||
{
|
||||
# Update the height texture if the ModelObject::layer_height_texture is invalid.
|
||||
my $ncells = $print_object->generate_layer_height_texture(
|
||||
$volume->{layer_height_texture_data}->ptr,
|
||||
$self->{layer_preview_z_texture_height},
|
||||
$self->{layer_preview_z_texture_width});
|
||||
$self->{layer_preview_z_texture_width},
|
||||
!defined($volume->{layer_height_texture_cells}));
|
||||
$volume->{layer_height_texture_cells} = $ncells if $ncells > 0;
|
||||
}
|
||||
$self->{shader}->Enable;
|
||||
my $z_to_texture_row_id = $self->{shader}->Map('z_to_texture_row');
|
||||
@ -1272,16 +1313,15 @@ sub draw_volumes {
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_load_overlay_image {
|
||||
my ($self) = @_;
|
||||
|
||||
if (! $self->{layer_preview_annotation}->{loaded}) {
|
||||
sub _load_image_set_texture {
|
||||
my ($self, $file_name) = @_;
|
||||
# Load a PNG with an alpha channel.
|
||||
my $img = Wx::Image->new;
|
||||
$img->LoadFile($Slic3r::var->("variable_layer_height_tooltip.png"), wxBITMAP_TYPE_PNG);
|
||||
$img->LoadFile($Slic3r::var->($file_name), wxBITMAP_TYPE_PNG);
|
||||
# Get RGB & alpha raw data from wxImage, interleave them into a Perl array.
|
||||
my @rgb = unpack 'C*', $img->GetData();
|
||||
my @alpha = unpack 'C*', $img->GetAlpha();
|
||||
my @alpha = $img->HasAlpha ? unpack 'C*', $img->GetAlpha() : (255) x (int(@rgb) / 3);
|
||||
# my @alpha = unpack 'C*', $img->GetAlpha();
|
||||
my $n_pixels = int(@alpha);
|
||||
my @data = (0)x($n_pixels * 4);
|
||||
for (my $i = 0; $i < $n_pixels; $i += 1) {
|
||||
@ -1291,7 +1331,7 @@ sub _variable_layer_thickness_load_overlay_image {
|
||||
$data[$i*4+3] = $alpha[$i];
|
||||
}
|
||||
# Initialize a raw bitmap data.
|
||||
my $params = $self->{layer_preview_annotation} = {
|
||||
my $params = {
|
||||
loaded => 1,
|
||||
valid => $n_pixels > 0,
|
||||
width => $img->GetWidth,
|
||||
@ -1306,11 +1346,44 @@ sub _variable_layer_thickness_load_overlay_image {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
glTexImage2D_c(GL_TEXTURE_2D, 0, GL_RGBA8, $params->{width}, $params->{height}, 0, GL_RGBA, GL_UNSIGNED_BYTE, $params->{data}->ptr);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_load_overlay_image {
|
||||
my ($self) = @_;
|
||||
$self->{layer_preview_annotation} = $self->_load_image_set_texture('variable_layer_height_tooltip.png')
|
||||
if (! $self->{layer_preview_annotation}->{loaded});
|
||||
return $self->{layer_preview_annotation}->{valid};
|
||||
}
|
||||
|
||||
sub _variable_layer_thickness_load_reset_image {
|
||||
my ($self) = @_;
|
||||
$self->{layer_preview_reset_image} = $self->_load_image_set_texture('variable_layer_height_reset.png')
|
||||
if (! $self->{layer_preview_reset_image}->{loaded});
|
||||
return $self->{layer_preview_reset_image}->{valid};
|
||||
}
|
||||
|
||||
# Paint the tooltip.
|
||||
sub _render_image {
|
||||
my ($self, $image, $l, $r, $b, $t) = @_;
|
||||
glColor4f(1.,1.,1.,1.);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, $image->{texture_id});
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2d(0.,1.); glVertex3f($l, $b, 0);
|
||||
glTexCoord2d(1.,1.); glVertex3f($r, $b, 0);
|
||||
glTexCoord2d(1.,0.); glVertex3f($r, $t, 0);
|
||||
glTexCoord2d(0.,0.); glVertex3f($l, $t, 0);
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
sub draw_active_object_annotations {
|
||||
# $fakecolor is a boolean indicating, that the objects shall be rendered in a color coding the object index for picking.
|
||||
my ($self) = @_;
|
||||
@ -1329,13 +1402,9 @@ sub draw_active_object_annotations {
|
||||
|
||||
# The viewport and camera are set to complete view and glOrtho(-$x/2, $x/2, -$y/2, $y/2, -$depth, $depth),
|
||||
# where x, y is the window size divided by $self->_zoom.
|
||||
my ($cw, $ch) = $self->GetSizeWH;
|
||||
my $bar_width = 70;
|
||||
my ($bar_left, $bar_right) = ((0.5 * $cw - $bar_width)/$self->_zoom, $cw/(2*$self->_zoom));
|
||||
my ($bar_bottom, $bar_top) = (-$ch/(2*$self->_zoom), $ch/(2*$self->_zoom));
|
||||
my $mouse_pos = $self->ScreenToClientPoint(Wx::GetMousePosition());
|
||||
my $z_cursor_relative = ($mouse_pos->x < $cw - $bar_width) ? -1000. :
|
||||
($ch - $mouse_pos->y - 1.) / ($ch - 1);
|
||||
my ($bar_left, $bar_bottom, $bar_right, $bar_top) = $self->_variable_layer_thickness_bar_rect_viewport;
|
||||
my ($reset_left, $reset_bottom, $reset_right, $reset_top) = $self->_variable_layer_thickness_reset_rect_viewport;
|
||||
my $z_cursor_relative = $self->_variable_layer_thickness_bar_mouse_cursor_z_relative;
|
||||
|
||||
$self->{shader}->Enable;
|
||||
my $z_to_texture_row_id = $self->{shader}->Map('z_to_texture_row');
|
||||
@ -1374,31 +1443,23 @@ sub draw_active_object_annotations {
|
||||
|
||||
# Paint the tooltip.
|
||||
if ($self->_variable_layer_thickness_load_overlay_image) {
|
||||
glColor4f(1.,1.,1.,1.);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, $self->{layer_preview_annotation}->{texture_id});
|
||||
glBegin(GL_QUADS);
|
||||
my $gap = 10/$self->_zoom;
|
||||
my ($l, $r, $t, $b) = ($bar_left - $self->{layer_preview_annotation}->{width}/$self->_zoom - $gap, $bar_left - $gap, $bar_bottom + $self->{layer_preview_annotation}->{height}/$self->_zoom + $gap, $bar_bottom + $gap);
|
||||
glTexCoord2d(0.,1.); glVertex3f($l, $b, 0);
|
||||
glTexCoord2d(1.,1.); glVertex3f($r, $b, 0);
|
||||
glTexCoord2d(1.,0.); glVertex3f($r, $t, 0);
|
||||
glTexCoord2d(0.,0.); glVertex3f($l, $t, 0);
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_LIGHTING);
|
||||
my ($l, $r, $b, $t) = ($bar_left - $self->{layer_preview_annotation}->{width}/$self->_zoom - $gap, $bar_left - $gap, $reset_bottom + $self->{layer_preview_annotation}->{height}/$self->_zoom + $gap, $reset_bottom + $gap);
|
||||
$self->_render_image($self->{layer_preview_annotation}, $l, $r, $t, $b);
|
||||
}
|
||||
|
||||
# Paint the reset button.
|
||||
if ($self->_variable_layer_thickness_load_reset_image) {
|
||||
$self->_render_image($self->{layer_preview_reset_image}, $reset_left, $reset_right, $reset_bottom, $reset_top);
|
||||
}
|
||||
|
||||
# Paint the graph.
|
||||
#FIXME use the min / maximum layer height
|
||||
#FIXME show some kind of legend.
|
||||
my $object_idx = int($volume->select_group_id / 1000000);
|
||||
my $print_object = $self->{print}->get_object($object_idx);
|
||||
my $max_z = unscale($print_object->size->z);
|
||||
my $profile = $print_object->layer_height_profile;
|
||||
my $profile = $print_object->model_object->layer_height_profile;
|
||||
my $layer_height = $print_object->config->get('layer_height');
|
||||
# Baseline
|
||||
glColor3f(0., 0., 0.);
|
||||
@ -1686,7 +1747,6 @@ sub load_object {
|
||||
# not correspond to the color of the filament.
|
||||
my $color = [ @{COLORS->[ $color_idx % scalar(@{&COLORS}) ]} ];
|
||||
$color->[3] = $volume->modifier ? 0.5 : 1;
|
||||
print "Reloading object $volume_idx, $instance_idx\n";
|
||||
push @{$self->volumes}, my $v = Slic3r::GUI::3DScene::Volume->new(
|
||||
bounding_box => $mesh->bounding_box,
|
||||
color => $color,
|
||||
|
@ -104,6 +104,12 @@ sub new {
|
||||
$self->{canvas3D}->set_on_double_click($on_double_click);
|
||||
$self->{canvas3D}->set_on_right_click(sub { $on_right_click->($self->{canvas3D}, @_); });
|
||||
$self->{canvas3D}->set_on_instances_moved($on_instances_moved);
|
||||
$self->{canvas3D}->set_on_model_update(sub {
|
||||
if ($Slic3r::GUI::Settings->{_}{background_processing}) {
|
||||
$self->{apply_config_timer}->Stop if defined $self->{apply_config_timer};
|
||||
$self->async_apply_config();
|
||||
}
|
||||
});
|
||||
$self->{canvas3D}->on_viewport_changed(sub {
|
||||
$self->{preview3D}->canvas->set_viewport_from_scene($self->{canvas3D});
|
||||
});
|
||||
@ -651,10 +657,9 @@ sub load_model_objects {
|
||||
my @obj_idx = ();
|
||||
foreach my $model_object (@model_objects) {
|
||||
my $o = $self->{model}->add_object($model_object);
|
||||
|
||||
push @{ $self->{objects} }, Slic3r::GUI::Plater::Object->new(
|
||||
name => basename($model_object->input_file),
|
||||
);
|
||||
my $object_name = $model_object->name;
|
||||
$object_name = basename($model_object->input_file) if ($object_name eq '');
|
||||
push @{ $self->{objects} }, Slic3r::GUI::Plater::Object->new(name => $object_name);
|
||||
push @obj_idx, $#{ $self->{objects} };
|
||||
|
||||
if ($model_object->instances_count == 0) {
|
||||
@ -1089,6 +1094,9 @@ sub async_apply_config {
|
||||
# apply new config
|
||||
my $invalidated = $self->{print}->apply_config($self->GetFrame->config);
|
||||
|
||||
# $self->{canvas3D}->Refresh if ($invalidated && $self->{canvas3D}->layer_editing_enabled);
|
||||
$self->{canvas3D}->Refresh if ($self->{canvas3D}->layer_editing_enabled);
|
||||
|
||||
return if !$Slic3r::GUI::Settings->{_}{background_processing};
|
||||
|
||||
if ($invalidated) {
|
||||
@ -1200,7 +1208,10 @@ sub reslice {
|
||||
my ($self) = @_;
|
||||
# Don't reslice if export of G-code or sending to OctoPrint is running.
|
||||
if ($Slic3r::have_threads && ! defined($self->{export_gcode_output_file}) && ! defined($self->{send_gcode_file})) {
|
||||
# Stop the background processing threads, stop the async update timer.
|
||||
$self->stop_background_process;
|
||||
# Rather perform one additional unnecessary update of the print object instead of skipping a pending async update.
|
||||
$self->async_apply_config;
|
||||
$self->statusbar->SetCancelCallback(sub {
|
||||
$self->stop_background_process;
|
||||
$self->statusbar->SetStatusText("Slicing cancelled");
|
||||
@ -1534,8 +1545,6 @@ sub on_thumbnail_made {
|
||||
sub update {
|
||||
my ($self, $force_autocenter) = @_;
|
||||
|
||||
print "Platter - update\n";
|
||||
|
||||
if ($Slic3r::GUI::Settings->{_}{autocenter} || $force_autocenter) {
|
||||
$self->{model}->center_instances_around_point($self->bed_centerf);
|
||||
}
|
||||
|
@ -83,6 +83,11 @@ sub set_on_instances_moved {
|
||||
$self->{on_instances_moved} = $cb;
|
||||
}
|
||||
|
||||
sub set_on_model_update {
|
||||
my ($self, $cb) = @_;
|
||||
$self->on_model_update($cb);
|
||||
}
|
||||
|
||||
sub update {
|
||||
my ($self) = @_;
|
||||
|
||||
|
@ -329,8 +329,10 @@ ModelMaterial::apply(const t_model_material_attributes &attributes)
|
||||
}
|
||||
|
||||
|
||||
ModelObject::ModelObject(Model *model)
|
||||
: model(model), _bounding_box_valid(false)
|
||||
ModelObject::ModelObject(Model *model) :
|
||||
model(model),
|
||||
_bounding_box_valid(false),
|
||||
layer_height_profile_valid(false)
|
||||
{}
|
||||
|
||||
ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volumes)
|
||||
@ -340,6 +342,8 @@ ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volum
|
||||
volumes(),
|
||||
config(other.config),
|
||||
layer_height_ranges(other.layer_height_ranges),
|
||||
layer_height_profile(other.layer_height_profile),
|
||||
layer_height_profile_valid(other.layer_height_profile_valid),
|
||||
origin_translation(other.origin_translation),
|
||||
_bounding_box(other._bounding_box),
|
||||
_bounding_box_valid(other._bounding_box_valid),
|
||||
@ -356,7 +360,7 @@ ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volum
|
||||
this->add_instance(**i);
|
||||
}
|
||||
|
||||
ModelObject& ModelObject::operator= (ModelObject other)
|
||||
ModelObject& ModelObject::operator=(ModelObject other)
|
||||
{
|
||||
this->swap(other);
|
||||
return *this;
|
||||
@ -370,6 +374,8 @@ ModelObject::swap(ModelObject &other)
|
||||
std::swap(this->volumes, other.volumes);
|
||||
std::swap(this->config, other.config);
|
||||
std::swap(this->layer_height_ranges, other.layer_height_ranges);
|
||||
std::swap(this->layer_height_profile, other.layer_height_profile);
|
||||
std::swap(this->layer_height_profile_valid, other.layer_height_profile_valid);
|
||||
std::swap(this->origin_translation, other.origin_translation);
|
||||
std::swap(this->_bounding_box, other._bounding_box);
|
||||
std::swap(this->_bounding_box_valid, other._bounding_box_valid);
|
||||
|
@ -117,6 +117,10 @@ public:
|
||||
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
||||
// The pairs of <z, layer_height> are packed into a 1D array to simplify handling by the Perl XS.
|
||||
std::vector<coordf_t> layer_height_profile;
|
||||
// layer_height_profile is initialized when the layer editing mode is entered.
|
||||
// Only if the user really modified the layer height, layer_height_profile_valid is set
|
||||
// and used subsequently by the PrintObject.
|
||||
bool layer_height_profile_valid;
|
||||
|
||||
/* This vector accumulates the total translation applied to the object by the
|
||||
center_around_origin() method. Callers might want to apply the same translation
|
||||
|
@ -371,7 +371,7 @@ Print::add_model_object(ModelObject* model_object, int idx)
|
||||
this->objects[idx] = o = new PrintObject(this, model_object, bb);
|
||||
} else {
|
||||
o = new PrintObject(this, model_object, bb);
|
||||
objects.push_back(o);
|
||||
this->objects.push_back(o);
|
||||
|
||||
// invalidate steps
|
||||
this->invalidate_step(psSkirt);
|
||||
@ -528,8 +528,26 @@ Print::apply_config(DynamicPrintConfig config)
|
||||
this->clear_objects();
|
||||
for (ModelObjectPtrs::iterator it = model_objects.begin(); it != model_objects.end(); ++it) {
|
||||
this->add_model_object(*it);
|
||||
// Update layer_height_profile from the main thread as it may pull the data from the associated ModelObject.
|
||||
this->objects.back()->update_layer_height_profile();
|
||||
}
|
||||
invalidated = true;
|
||||
} else {
|
||||
// Check validity of the layer height profiles.
|
||||
FOREACH_OBJECT(this, o) {
|
||||
if (! (*o)->layer_height_profile_valid) {
|
||||
// The layer_height_profile is not valid for some reason (updated by the user or invalidated due to some option change).
|
||||
// Start slicing of this object from scratch.
|
||||
(*o)->invalidate_all_steps();
|
||||
// Following line sets the layer_height_profile_valid flag.
|
||||
(*o)->update_layer_height_profile();
|
||||
invalidated = true;
|
||||
} else if (! step_done(posSlice)) {
|
||||
// Update layer_height_profile from the main thread as it may pull the data from the associated ModelObject.
|
||||
// Only update if the slicing was not finished yet.
|
||||
(*o)->update_layer_height_profile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return invalidated;
|
||||
|
@ -85,7 +85,13 @@ public:
|
||||
|
||||
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
||||
// The pairs of <z, layer_height> are packed into a 1D array to simplify handling by the Perl XS.
|
||||
// layer_height_profile must not be set by the background thread.
|
||||
std::vector<coordf_t> layer_height_profile;
|
||||
// There is a layer_height_profile at both PrintObject and ModelObject. The layer_height_profile at the ModelObject
|
||||
// is used for interactive editing and for loading / storing into a project file (AMF file as of today).
|
||||
// This flag indicates that the layer_height_profile at the UI has been updated, therefore the backend needs to get it.
|
||||
// This flag is necessary as we cannot safely clear the layer_height_profile if the background calculation is running.
|
||||
bool layer_height_profile_valid;
|
||||
|
||||
// this is set to true when LayerRegion->slices is split in top/internal/bottom
|
||||
// so that next call to make_perimeters() performs a union() before computing loops
|
||||
@ -145,10 +151,16 @@ public:
|
||||
bool invalidate_step(PrintObjectStep step);
|
||||
bool invalidate_all_steps();
|
||||
|
||||
// To be used over the layer_height_profile of both the PrintObject and ModelObject
|
||||
// to initialize the height profile with the height ranges.
|
||||
bool update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const;
|
||||
|
||||
// Process layer_height_ranges, the raft layers and first layer thickness into layer_height_profile.
|
||||
// The layer_height_profile may be later modified interactively by the user to refine layers at sloping surfaces.
|
||||
bool update_layer_height_profile();
|
||||
|
||||
void reset_layer_height_profile();
|
||||
|
||||
// Collect the slicing parameters, to be used by variable layer thickness algorithm,
|
||||
// by the interactive layer height editor and by the printing process itself.
|
||||
// The slicing parameters are dependent on various configuration values
|
||||
|
@ -29,7 +29,8 @@ namespace Slic3r {
|
||||
PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox)
|
||||
: typed_slices(false),
|
||||
_print(print),
|
||||
_model_object(model_object)
|
||||
_model_object(model_object),
|
||||
layer_height_profile_valid(false)
|
||||
{
|
||||
// Compute the translation to be applied to our meshes so that we work with smaller coordinates
|
||||
{
|
||||
@ -216,8 +217,11 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
|
||||
steps.insert(posPerimeters);
|
||||
} else if (*opt_key == "layer_height"
|
||||
|| *opt_key == "first_layer_height"
|
||||
|| *opt_key == "xy_size_compensation"
|
||||
|| *opt_key == "raft_layers") {
|
||||
steps.insert(posSlice);
|
||||
this->reset_layer_height_profile();
|
||||
}
|
||||
else if (*opt_key == "xy_size_compensation") {
|
||||
steps.insert(posSlice);
|
||||
} else if (*opt_key == "support_material"
|
||||
|| *opt_key == "support_material_angle"
|
||||
@ -283,6 +287,7 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
|
||||
// these options only affect G-code export, so nothing to invalidate
|
||||
} else {
|
||||
// for legacy, if we can't handle this option let's invalidate all steps
|
||||
this->reset_layer_height_profile();
|
||||
return this->invalidate_all_steps();
|
||||
}
|
||||
}
|
||||
@ -950,21 +955,49 @@ SlicingParameters PrintObject::slicing_parameters() const
|
||||
unscale(this->size.z), this->print()->object_extruders());
|
||||
}
|
||||
|
||||
bool PrintObject::update_layer_height_profile()
|
||||
bool PrintObject::update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const
|
||||
{
|
||||
bool updated = false;
|
||||
if (this->layer_height_profile.empty()) {
|
||||
|
||||
// If the layer height profile is not set, try to use the one stored at the ModelObject.
|
||||
if (layer_height_profile.empty() && layer_height_profile.data() != this->model_object()->layer_height_profile.data()) {
|
||||
layer_height_profile = this->model_object()->layer_height_profile;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// Verify the layer_height_profile.
|
||||
SlicingParameters slicing_params = this->slicing_parameters();
|
||||
if (! layer_height_profile.empty() &&
|
||||
// Must not be of even length.
|
||||
((layer_height_profile.size() & 1) != 0 ||
|
||||
// Last entry must be at the top of the object.
|
||||
std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_params.object_print_z_height()) > 1e-3))
|
||||
layer_height_profile.clear();
|
||||
|
||||
if (layer_height_profile.empty()) {
|
||||
if (0)
|
||||
// if (this->layer_height_profile.empty())
|
||||
this->layer_height_profile = layer_height_profile_adaptive(this->slicing_parameters(), this->layer_height_ranges,
|
||||
layer_height_profile = layer_height_profile_adaptive(slicing_params, this->layer_height_ranges,
|
||||
this->model_object()->volumes);
|
||||
else
|
||||
this->layer_height_profile = layer_height_profile_from_ranges(this->slicing_parameters(), this->layer_height_ranges);
|
||||
layer_height_profile = layer_height_profile_from_ranges(slicing_params, this->layer_height_ranges);
|
||||
updated = true;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
// This must be called from the main thread as it modifies the layer_height_profile.
|
||||
bool PrintObject::update_layer_height_profile()
|
||||
{
|
||||
// If the layer height profile has been marked as invalid for some reason (modified at the UI level
|
||||
// or invalidated due to the slicing parameters), clear it now.
|
||||
if (! this->layer_height_profile_valid) {
|
||||
this->layer_height_profile.clear();
|
||||
this->layer_height_profile_valid = true;
|
||||
}
|
||||
return this->update_layer_height_profile(this->layer_height_profile);
|
||||
}
|
||||
|
||||
// 1) Decides Z positions of the layers,
|
||||
// 2) Initializes layers and their regions
|
||||
// 3) Slices the object meshes
|
||||
@ -1267,4 +1300,13 @@ void PrintObject::_generate_support_material()
|
||||
support_material.generate(*this);
|
||||
}
|
||||
|
||||
void PrintObject::reset_layer_height_profile()
|
||||
{
|
||||
// Reset the layer_heigth_profile.
|
||||
this->layer_height_profile.clear();
|
||||
// Reset the source layer_height_profile if it exists at the ModelObject.
|
||||
this->model_object()->layer_height_profile.clear();
|
||||
this->model_object()->layer_height_profile_valid = false;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -18,6 +18,26 @@
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
static const coordf_t MIN_LAYER_HEIGHT = 0.01;
|
||||
static const coordf_t MIN_LAYER_HEIGHT_DEFAULT = 0.05;
|
||||
|
||||
// Minimum layer height for the variable layer height algorithm.
|
||||
inline coordf_t min_layer_height_from_nozzle(const PrintConfig &print_config, int idx_nozzle)
|
||||
{
|
||||
coordf_t min_layer_height = print_config.min_layer_height.get_at(idx_nozzle - 1);
|
||||
return (min_layer_height == 0.) ? MIN_LAYER_HEIGHT_DEFAULT : std::max(MIN_LAYER_HEIGHT, min_layer_height);
|
||||
}
|
||||
|
||||
// Maximum layer height for the variable layer height algorithm, 3/4 of a nozzle dimaeter by default,
|
||||
// it should not be smaller than the minimum layer height.
|
||||
inline coordf_t max_layer_height_from_nozzle(const PrintConfig &print_config, int idx_nozzle)
|
||||
{
|
||||
coordf_t min_layer_height = min_layer_height_from_nozzle(print_config, idx_nozzle);
|
||||
coordf_t max_layer_height = print_config.max_layer_height.get_at(idx_nozzle - 1);
|
||||
coordf_t nozzle_dmr = print_config.nozzle_diameter.get_at(idx_nozzle - 1);
|
||||
return std::max(min_layer_height, (max_layer_height == 0.) ? (0.75 * nozzle_dmr) : max_layer_height);
|
||||
}
|
||||
|
||||
SlicingParameters SlicingParameters::create_from_config(
|
||||
const PrintConfig &print_config,
|
||||
const PrintObjectConfig &object_config,
|
||||
@ -45,6 +65,31 @@ SlicingParameters SlicingParameters::create_from_config(
|
||||
params.base_raft_layers = object_config.raft_layers.value;
|
||||
params.soluble_interface = soluble_interface;
|
||||
|
||||
// Miniumum/maximum of the minimum layer height over all extruders.
|
||||
params.min_layer_height = MIN_LAYER_HEIGHT;
|
||||
params.max_layer_height = FLT_MAX;
|
||||
if (object_config.support_material.value || params.base_raft_layers > 0) {
|
||||
// Has some form of support. Add the support layers to the minimum / maximum layer height limits.
|
||||
params.min_layer_height = std::max(
|
||||
min_layer_height_from_nozzle(print_config, object_config.support_material_extruder),
|
||||
min_layer_height_from_nozzle(print_config, object_config.support_material_interface_extruder));
|
||||
params.max_layer_height = std::min(
|
||||
max_layer_height_from_nozzle(print_config, object_config.support_material_extruder),
|
||||
max_layer_height_from_nozzle(print_config, object_config.support_material_interface_extruder));
|
||||
params.max_suport_layer_height = params.max_layer_height;
|
||||
}
|
||||
if (object_extruders.empty()) {
|
||||
params.min_layer_height = std::max(params.min_layer_height, min_layer_height_from_nozzle(print_config, 0));
|
||||
params.max_layer_height = std::min(params.max_layer_height, max_layer_height_from_nozzle(print_config, 0));
|
||||
} else {
|
||||
for (std::set<size_t>::const_iterator it_extruder = object_extruders.begin(); it_extruder != object_extruders.end(); ++ it_extruder) {
|
||||
params.min_layer_height = std::max(params.min_layer_height, min_layer_height_from_nozzle(print_config, *it_extruder));
|
||||
params.max_layer_height = std::min(params.max_layer_height, max_layer_height_from_nozzle(print_config, *it_extruder));
|
||||
}
|
||||
}
|
||||
params.min_layer_height = std::min(params.min_layer_height, params.layer_height);
|
||||
params.max_layer_height = std::max(params.max_layer_height, params.layer_height);
|
||||
|
||||
if (! soluble_interface) {
|
||||
params.gap_raft_object = object_config.support_material_contact_distance.value;
|
||||
params.gap_object_support = object_config.support_material_contact_distance.value;
|
||||
@ -101,12 +146,6 @@ SlicingParameters SlicingParameters::create_from_config(
|
||||
params.object_print_z_max += print_z;
|
||||
}
|
||||
|
||||
params.min_layer_height = std::min(params.layer_height, first_layer_height);
|
||||
params.max_layer_height = std::max(params.layer_height, first_layer_height);
|
||||
|
||||
//FIXME add it to the print configuration
|
||||
params.min_layer_height = 0.05;
|
||||
|
||||
// Calculate the maximum layer height as 0.75 from the minimum nozzle diameter.
|
||||
if (! object_extruders.empty()) {
|
||||
coordf_t min_object_extruder_dmr = 1000000.;
|
||||
@ -306,6 +345,7 @@ void adjust_layer_height_profile(
|
||||
return;
|
||||
|
||||
assert(layer_height_profile.size() >= 2);
|
||||
assert(std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_params.object_print_z_height()) < EPSILON);
|
||||
|
||||
// 1) Get the current layer thickness at z.
|
||||
coordf_t current_layer_height = slicing_params.layer_height;
|
||||
@ -355,21 +395,21 @@ void adjust_layer_height_profile(
|
||||
coordf_t lo = std::max(z_span_variable.first, z - 0.5 * band_width);
|
||||
coordf_t hi = std::min(z_span_variable.second, z + 0.5 * band_width);
|
||||
coordf_t z_step = 0.1;
|
||||
size_t i = 0;
|
||||
while (i < layer_height_profile.size() && layer_height_profile[i] < lo)
|
||||
i += 2;
|
||||
i -= 2;
|
||||
size_t idx = 0;
|
||||
while (idx < layer_height_profile.size() && layer_height_profile[idx] < lo)
|
||||
idx += 2;
|
||||
idx -= 2;
|
||||
|
||||
std::vector<double> profile_new;
|
||||
profile_new.reserve(layer_height_profile.size());
|
||||
assert(i >= 0 && i + 1 < layer_height_profile.size());
|
||||
profile_new.insert(profile_new.end(), layer_height_profile.begin(), layer_height_profile.begin() + i + 2);
|
||||
assert(idx >= 0 && idx + 1 < layer_height_profile.size());
|
||||
profile_new.insert(profile_new.end(), layer_height_profile.begin(), layer_height_profile.begin() + idx + 2);
|
||||
coordf_t zz = lo;
|
||||
size_t i_resampled_start = profile_new.size();
|
||||
while (zz < hi) {
|
||||
size_t next = i + 2;
|
||||
coordf_t z1 = layer_height_profile[i];
|
||||
coordf_t h1 = layer_height_profile[i + 1];
|
||||
size_t next = idx + 2;
|
||||
coordf_t z1 = layer_height_profile[idx];
|
||||
coordf_t h1 = layer_height_profile[idx + 1];
|
||||
coordf_t height = h1;
|
||||
if (next < layer_height_profile.size()) {
|
||||
coordf_t z2 = layer_height_profile[next];
|
||||
@ -409,21 +449,22 @@ void adjust_layer_height_profile(
|
||||
profile_new.push_back(clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, height));
|
||||
}
|
||||
zz += z_step;
|
||||
i = next;
|
||||
while (i < layer_height_profile.size() && layer_height_profile[i] < zz)
|
||||
i += 2;
|
||||
i -= 2;
|
||||
idx = next;
|
||||
while (idx < layer_height_profile.size() && layer_height_profile[idx] < zz)
|
||||
idx += 2;
|
||||
idx -= 2;
|
||||
}
|
||||
|
||||
i += 2;
|
||||
assert(i > 0);
|
||||
idx += 2;
|
||||
assert(idx > 0);
|
||||
size_t i_resampled_end = profile_new.size();
|
||||
if (i < layer_height_profile.size()) {
|
||||
assert(zz >= layer_height_profile[i - 2]);
|
||||
assert(zz <= layer_height_profile[i]);
|
||||
// profile_new.push_back(zz);
|
||||
// profile_new.push_back(layer_height_profile[i + 1]);
|
||||
profile_new.insert(profile_new.end(), layer_height_profile.begin() + i, layer_height_profile.end());
|
||||
if (idx < layer_height_profile.size()) {
|
||||
assert(zz >= layer_height_profile[idx - 2]);
|
||||
assert(zz <= layer_height_profile[idx]);
|
||||
profile_new.insert(profile_new.end(), layer_height_profile.begin() + idx, layer_height_profile.end());
|
||||
}
|
||||
else if (profile_new[profile_new.size() - 2] + 0.5 * EPSILON < slicing_params.object_print_z_height()) {
|
||||
profile_new.insert(profile_new.end(), layer_height_profile.end() - 2, layer_height_profile.end());
|
||||
}
|
||||
layer_height_profile = std::move(profile_new);
|
||||
|
||||
@ -448,6 +489,7 @@ void adjust_layer_height_profile(
|
||||
assert(layer_height_profile.size() > 2);
|
||||
assert(layer_height_profile.size() % 2 == 0);
|
||||
assert(layer_height_profile[0] == 0.);
|
||||
assert(std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_params.object_print_z_height()) < EPSILON);
|
||||
#ifdef _DEBUG
|
||||
for (size_t i = 2; i < layer_height_profile.size(); i += 2)
|
||||
assert(layer_height_profile[i - 2] <= layer_height_profile[i]);
|
||||
@ -601,7 +643,7 @@ int generate_layer_height_texture(
|
||||
const Point3 &color2 = palette_raw[idx2];
|
||||
|
||||
coordf_t z = cell_to_z1 * coordf_t(cell);
|
||||
assert(z >= lo && z <= hi);
|
||||
assert(z >= lo - EPSILON && z <= hi + EPSILON);
|
||||
|
||||
// Color mapping from layer height to RGB.
|
||||
Pointf3 color(
|
||||
|
@ -52,6 +52,11 @@ struct SlicingParameters
|
||||
// The regular layer height, applied for all but the first layer, if not overridden by layer ranges
|
||||
// or by the variable layer thickness table.
|
||||
coordf_t layer_height;
|
||||
// Minimum / maximum layer height, to be used for the automatic adaptive layer height algorithm,
|
||||
// or by an interactive layer height editor.
|
||||
coordf_t min_layer_height;
|
||||
coordf_t max_layer_height;
|
||||
coordf_t max_suport_layer_height;
|
||||
|
||||
// First layer height of the print, this may be used for the first layer of the raft
|
||||
// or for the first layer of the print.
|
||||
@ -75,11 +80,6 @@ struct SlicingParameters
|
||||
// Gap when placing object over support.
|
||||
coordf_t gap_support_object;
|
||||
|
||||
// Minimum / maximum layer height, to be used for the automatic adaptive layer height algorithm,
|
||||
// or by an interactive layer height editor.
|
||||
coordf_t min_layer_height;
|
||||
coordf_t max_layer_height;
|
||||
|
||||
// Bottom and top of the printed object.
|
||||
// If printed without a raft, object_print_z_min = 0 and object_print_z_max = object height.
|
||||
// Otherwise object_print_z_min is equal to the raft height.
|
||||
|
@ -170,6 +170,10 @@ ModelMaterial::attributes()
|
||||
void set_layer_height_ranges(t_layer_height_ranges ranges)
|
||||
%code%{ THIS->layer_height_ranges = ranges; %};
|
||||
|
||||
std::vector<double> layer_height_profile()
|
||||
%code%{ RETVAL = THIS->layer_height_profile_valid ? THIS->layer_height_profile : std::vector<double>(); %};
|
||||
void set_layer_height_profile(std::vector<double> profile)
|
||||
%code%{ THIS->layer_height_profile = profile; THIS->layer_height_profile_valid = true; %};
|
||||
|
||||
Ref<Pointf3> origin_translation()
|
||||
%code%{ RETVAL = &THIS->origin_translation; %};
|
||||
|
@ -120,23 +120,39 @@ _constant()
|
||||
void _infill();
|
||||
void _generate_support_material();
|
||||
|
||||
bool update_layer_height_profile();
|
||||
std::vector<double> get_layer_height_min_max()
|
||||
%code%{
|
||||
SlicingParameters slicing_params = THIS->slicing_parameters();
|
||||
RETVAL.push_back(slicing_params.min_layer_height);
|
||||
RETVAL.push_back(slicing_params.max_layer_height);
|
||||
RETVAL.push_back(slicing_params.first_print_layer_height);
|
||||
RETVAL.push_back(slicing_params.first_object_layer_height);
|
||||
RETVAL.push_back(slicing_params.layer_height);
|
||||
%};
|
||||
|
||||
void adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action)
|
||||
%code%{
|
||||
THIS->update_layer_height_profile();
|
||||
THIS->update_layer_height_profile(THIS->model_object()->layer_height_profile);
|
||||
adjust_layer_height_profile(
|
||||
THIS->slicing_parameters(), THIS->layer_height_profile, z, layer_thickness_delta, band_width, LayerHeightEditActionType(action));
|
||||
THIS->slicing_parameters(), THIS->model_object()->layer_height_profile, z, layer_thickness_delta, band_width, LayerHeightEditActionType(action));
|
||||
THIS->model_object()->layer_height_profile_valid = true;
|
||||
THIS->layer_height_profile_valid = false;
|
||||
%};
|
||||
|
||||
int generate_layer_height_texture(void *data, int rows, int cols, bool level_of_detail_2nd_level = true)
|
||||
void reset_layer_height_profile();
|
||||
|
||||
int generate_layer_height_texture(void *data, int rows, int cols, bool force = true)
|
||||
%code%{
|
||||
THIS->update_layer_height_profile();
|
||||
force |= THIS->update_layer_height_profile(THIS->model_object()->layer_height_profile);
|
||||
if (force) {
|
||||
SlicingParameters slicing_params = THIS->slicing_parameters();
|
||||
bool level_of_detail_2nd_level = true;
|
||||
RETVAL = generate_layer_height_texture(
|
||||
slicing_params,
|
||||
generate_object_layers(slicing_params, THIS->layer_height_profile),
|
||||
generate_object_layers(slicing_params, THIS->model_object()->layer_height_profile),
|
||||
data, rows, cols, level_of_detail_2nd_level);
|
||||
} else
|
||||
RETVAL = 0;
|
||||
%};
|
||||
|
||||
int ptr()
|
||||
|
Loading…
Reference in New Issue
Block a user