Initial implementation of a wipe tower preview UI.
This commit is contained in:
parent
7b6c9b3b3c
commit
cb0a66b743
7 changed files with 102 additions and 36 deletions
|
@ -240,11 +240,13 @@ sub layer_editing_allowed {
|
|||
return ! (defined($self->{layer_editing_initialized}) && $self->{layer_editing_initialized} == 2);
|
||||
}
|
||||
|
||||
sub _first_selected_object_id {
|
||||
sub _first_selected_object_id_for_variable_layer_height_editing {
|
||||
my ($self) = @_;
|
||||
for my $i (0..$#{$self->volumes}) {
|
||||
if ($self->volumes->[$i]->selected) {
|
||||
return int($self->volumes->[$i]->select_group_id / 1000000);
|
||||
my $object_id = int($self->volumes->[$i]->select_group_id / 1000000);
|
||||
# Objects with object_id >= 1000 have a specific meaning, for example the wipe tower proxy.
|
||||
return $object_id if $object_id < 10000;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
@ -332,7 +334,7 @@ sub mouse_event {
|
|||
my ($self, $e) = @_;
|
||||
|
||||
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 : -1;
|
||||
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;
|
||||
|
||||
if ($e->Entering && &Wx::wxMSW) {
|
||||
# wxMSW needs focus in order to catch mouse wheel events
|
||||
|
@ -502,7 +504,7 @@ sub mouse_wheel_event {
|
|||
my ($self, $e) = @_;
|
||||
|
||||
if ($self->layer_editing_enabled && $self->{print}) {
|
||||
my $object_idx_selected = $self->_first_selected_object_id;
|
||||
my $object_idx_selected = $self->_first_selected_object_id_for_variable_layer_height_editing;
|
||||
if ($object_idx_selected != -1) {
|
||||
# A volume is selected. Test, whether hovering over a layer thickness bar.
|
||||
if ($self->_variable_layer_thickness_bar_rect_mouse_inside($e)) {
|
||||
|
|
|
@ -53,6 +53,8 @@ sub new {
|
|||
$self->{config} = Slic3r::Config->new_from_defaults(qw(
|
||||
bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height
|
||||
serial_port serial_speed octoprint_host octoprint_apikey
|
||||
nozzle_diameter single_extruder_multi_material
|
||||
wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe
|
||||
));
|
||||
# C++ Slic3r::Model with Perl extensions in Slic3r/Model.pm
|
||||
$self->{model} = Slic3r::Model->new;
|
||||
|
@ -77,7 +79,8 @@ sub new {
|
|||
# Initialize handlers for canvases
|
||||
my $on_select_object = sub {
|
||||
my ($obj_idx) = @_;
|
||||
$self->select_object($obj_idx);
|
||||
# Ignore the special objects (the wipe tower proxy and such).
|
||||
$self->select_object((defined($obj_idx) && $obj_idx < 1000) ? $obj_idx : undef);
|
||||
};
|
||||
my $on_double_click = sub {
|
||||
$self->object_settings_dialog if $self->selected_object;
|
||||
|
@ -538,7 +541,8 @@ sub on_layer_editing_toggled {
|
|||
$self->{"btn_layer_editing"}->SetValue(0);
|
||||
}
|
||||
}
|
||||
$self->{canvas3D}->update;
|
||||
$self->{canvas3D}->Refresh;
|
||||
$self->{canvas3D}->Update;
|
||||
}
|
||||
|
||||
sub GetFrame {
|
||||
|
@ -1700,6 +1704,7 @@ sub on_config_change {
|
|||
my $self = shift;
|
||||
my ($config) = @_;
|
||||
|
||||
my $update_scheduled;
|
||||
foreach my $opt_key (@{$self->{config}->diff($config)}) {
|
||||
$self->{config}->set($opt_key, $config->get($opt_key));
|
||||
if ($opt_key eq 'bed_shape') {
|
||||
|
@ -1707,7 +1712,10 @@ sub on_config_change {
|
|||
$self->{canvas3D}->update_bed_size if $self->{canvas3D};
|
||||
$self->{preview3D}->set_bed_shape($self->{config}->bed_shape)
|
||||
if $self->{preview3D};
|
||||
$self->update;
|
||||
$update_scheduled = 1;
|
||||
} elsif ($opt_key =~ '^wipe_tower' || $opt_key == 'single_extruder_multi_material') {
|
||||
#$self->{canvas3D}->reload_scene if $self->{canvas3D};
|
||||
$update_scheduled = 1;
|
||||
} elsif ($opt_key eq 'serial_port') {
|
||||
if ($config->get('serial_port')) {
|
||||
$self->{btn_print}->Show;
|
||||
|
@ -1732,7 +1740,8 @@ sub on_config_change {
|
|||
$self->{"btn_layer_editing"}->SetValue(0);
|
||||
}
|
||||
$self->{canvas3D}->layer_editing_enabled(0);
|
||||
$self->{canvas3D}->update;
|
||||
$self->{canvas3D}->Refresh;
|
||||
$self->{canvas3D}->Update;
|
||||
} elsif ($self->{canvas3D}->layer_editing_allowed) {
|
||||
# Want to allow the layer editing, but do it only if the OpenGL supports it.
|
||||
if ($self->{htoolbar}) {
|
||||
|
@ -1743,6 +1752,8 @@ sub on_config_change {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
$self->update if $update_scheduled;
|
||||
|
||||
return if !$self->GetFrame->is_loaded;
|
||||
|
||||
|
@ -1955,7 +1966,7 @@ sub refresh_canvases {
|
|||
my ($self) = @_;
|
||||
|
||||
$self->{canvas}->Refresh;
|
||||
$self->{canvas3D}->update if $self->{canvas3D};
|
||||
$self->{canvas3D}->reload_scene if $self->{canvas3D};
|
||||
$self->{preview3D}->reload_print if $self->{preview3D};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,13 +29,8 @@ sub new {
|
|||
|
||||
$self->on_select(sub {
|
||||
my ($volume_idx) = @_;
|
||||
|
||||
my $obj_idx = undef;
|
||||
if ($volume_idx != -1) {
|
||||
$obj_idx = $self->volumes->[$volume_idx]->object_idx;
|
||||
}
|
||||
$self->{on_select_object}->($obj_idx)
|
||||
if $self->{on_select_object};
|
||||
$self->{on_select_object}->(($volume_idx == -1) ? undef : $self->volumes->[$volume_idx]->object_idx)
|
||||
if ($self->{on_select_object});
|
||||
});
|
||||
$self->on_move(sub {
|
||||
my @volume_idxs = @_;
|
||||
|
@ -47,13 +42,17 @@ sub new {
|
|||
my $instance_idx = $volume->instance_idx;
|
||||
next if $done{"${obj_idx}_${instance_idx}"};
|
||||
$done{"${obj_idx}_${instance_idx}"} = 1;
|
||||
|
||||
my $model_object = $self->{model}->get_object($obj_idx);
|
||||
$model_object
|
||||
->instances->[$instance_idx]
|
||||
->offset
|
||||
->translate($volume->origin->x, $volume->origin->y); #))
|
||||
$model_object->invalidate_bounding_box;
|
||||
if ($obj_idx < 1000) {
|
||||
# Move a regular object.
|
||||
my $model_object = $self->{model}->get_object($obj_idx);
|
||||
$model_object
|
||||
->instances->[$instance_idx]
|
||||
->offset
|
||||
->translate($volume->origin->x, $volume->origin->y); #))
|
||||
$model_object->invalidate_bounding_box;
|
||||
} elsif ($obj_idx == 1000) {
|
||||
# Move a wipe tower proxy.
|
||||
}
|
||||
}
|
||||
|
||||
$self->{on_instances_moved}->()
|
||||
|
@ -88,19 +87,45 @@ sub set_on_model_update {
|
|||
$self->on_model_update($cb);
|
||||
}
|
||||
|
||||
sub update {
|
||||
sub reload_scene {
|
||||
my ($self) = @_;
|
||||
|
||||
if (0) {
|
||||
my $i = 1;
|
||||
print STDERR "3D::reload_scene - Stack Trace:\n";
|
||||
while ( (my @call_details = (caller($i++))) ){
|
||||
print STDERR $call_details[1].":".$call_details[2]." in function ".$call_details[3]."\n";
|
||||
}
|
||||
}
|
||||
|
||||
$self->reset_objects;
|
||||
$self->update_bed_size;
|
||||
|
||||
foreach my $obj_idx (0..$#{$self->{model}->objects}) {
|
||||
my @volume_idxs = $self->load_object($self->{model}, $self->{print}, $obj_idx);
|
||||
|
||||
if ($self->{objects}[$obj_idx]->selected) {
|
||||
$self->select_volume($_) for @volume_idxs;
|
||||
}
|
||||
}
|
||||
if (0) {
|
||||
print "Config: $self->{config}\n";
|
||||
$self->{config}->save('d:\temp\cfg.ini');
|
||||
}
|
||||
if (defined $self->{config}->nozzle_diameter) {
|
||||
# Should the wipe tower be visualized?
|
||||
my $extruders_count = scalar @{ $self->{config}->nozzle_diameter };
|
||||
# Height of a print.
|
||||
my $height = $self->{model}->bounding_box->z_max;
|
||||
# Show at least a slab.
|
||||
$height = 10 if $height < 10;
|
||||
if ($extruders_count > 1 && $self->{config}->single_extruder_multi_material && $self->{config}->wipe_tower &&
|
||||
! $self->{config}->complete_objects) {
|
||||
$self->volumes->load_wipe_tower_preview(1000,
|
||||
$self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y,
|
||||
$self->{config}->wipe_tower_width, $self->{config}->wipe_tower_per_color_wipe * ($extruders_count - 1),
|
||||
$self->{model}->bounding_box->z_max, $self->UseVBOs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub update_bed_size {
|
||||
|
|
|
@ -997,8 +997,6 @@ sub build {
|
|||
$optgroup->append_single_option_line('filament_colour', 0);
|
||||
$optgroup->append_single_option_line('filament_diameter', 0);
|
||||
$optgroup->append_single_option_line('extrusion_multiplier', 0);
|
||||
$optgroup->append_single_option_line('filament_type', 0);
|
||||
$optgroup->append_single_option_line('filament_soluble', 0);
|
||||
$optgroup->append_single_option_line('filament_density', 0);
|
||||
$optgroup->append_single_option_line('filament_cost', 0);
|
||||
}
|
||||
|
@ -1071,7 +1069,11 @@ sub build {
|
|||
{
|
||||
my $page = $self->add_options_page('Advanced', 'wrench.png');
|
||||
{
|
||||
my $optgroup = $page->new_optgroup('Print speed override');
|
||||
my $optgroup = $page->new_optgroup('Filament properties');
|
||||
$optgroup->append_single_option_line('filament_type', 0);
|
||||
$optgroup->append_single_option_line('filament_soluble', 0);
|
||||
|
||||
$optgroup = $page->new_optgroup('Print speed override');
|
||||
$optgroup->append_single_option_line('filament_max_volumetric_speed', 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -299,6 +299,25 @@ std::vector<int> GLVolumeCollection::load_object(
|
|||
return volumes_idx;
|
||||
}
|
||||
|
||||
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs)
|
||||
{
|
||||
float color[4] = { 1.0f, 1.0f, 0.0f, 0.5f };
|
||||
this->volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume &v = *this->volumes.back();
|
||||
auto mesh = make_cube(width, depth, height);
|
||||
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
|
||||
v.origin = Pointf3(pos_x, pos_y, 0.);
|
||||
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
|
||||
v.bounding_box = v.indexed_vertex_array.bounding_box();
|
||||
v.indexed_vertex_array.finalize_geometry(use_VBOs);
|
||||
v.composite_id = obj_idx * 1000000;
|
||||
v.select_group_id = obj_idx * 1000000;
|
||||
v.drag_group_id = obj_idx * 1000;
|
||||
return int(this->volumes.size() - 1);
|
||||
}
|
||||
|
||||
void GLVolumeCollection::render_VBOs() const
|
||||
{
|
||||
// glEnable(GL_BLEND);
|
||||
|
@ -453,18 +472,19 @@ static void thick_lines_to_indexed_vertex_array(
|
|||
idx_a[TOP] = idx_prev[TOP];
|
||||
}
|
||||
if (ii == 0 || 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.);
|
||||
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);
|
||||
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 {
|
||||
idx_a[BOTTOM] = idx_prev[BOTTOM];
|
||||
}
|
||||
|
||||
if (ii == 0) {
|
||||
// Start of the 1st line segment.
|
||||
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);
|
||||
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);
|
||||
width_initial = width;
|
||||
bottom_z_initial = bottom_z;
|
||||
memcpy(idx_initial, idx_a, sizeof(int) * 4);
|
||||
|
@ -721,8 +741,7 @@ void _3DScene::_load_print_toolpaths(
|
|||
//FIXME why there are support layers?
|
||||
for (size_t i = 0; i < std::min(skirt_height, object0->support_layers.size()); ++ i)
|
||||
print_zs.push_back(float(object0->support_layers[i]->print_z));
|
||||
std::sort(print_zs.begin(), print_zs.end());
|
||||
print_zs.erase(std::unique(print_zs.begin(), print_zs.end()), print_zs.end());
|
||||
sort_remove_duplicates(print_zs);
|
||||
if (print_zs.size() > skirt_height)
|
||||
print_zs.erase(print_zs.begin() + skirt_height, print_zs.end());
|
||||
|
||||
|
|
|
@ -224,6 +224,9 @@ public:
|
|||
const std::string &select_by,
|
||||
const std::string &drag_by);
|
||||
|
||||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs);
|
||||
|
||||
// Bounding box of this volume, in unscaled coordinates.
|
||||
BoundingBoxf3 bounding_box;
|
||||
// Offset of the volume to be rendered.
|
||||
|
@ -310,6 +313,9 @@ public:
|
|||
const std::string &drag_by,
|
||||
bool use_VBOs);
|
||||
|
||||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs);
|
||||
|
||||
// Render the volumes by OpenGL.
|
||||
void render_VBOs() const;
|
||||
void render_legacy() const;
|
||||
|
|
|
@ -29,8 +29,7 @@
|
|||
|
||||
std::vector<double> color()
|
||||
%code%{ RETVAL.reserve(4); RETVAL.push_back(THIS->color[0]); RETVAL.push_back(THIS->color[1]); RETVAL.push_back(THIS->color[2]); RETVAL.push_back(THIS->color[3]); %};
|
||||
int composite_id()
|
||||
%code%{ RETVAL = THIS->composite_id; %};
|
||||
|
||||
int select_group_id()
|
||||
%code%{ RETVAL = THIS->select_group_id; %};
|
||||
int drag_group_id()
|
||||
|
@ -77,6 +76,8 @@
|
|||
|
||||
std::vector<int> load_object(ModelObject *object, int obj_idx, std::vector<int> instance_idxs, std::string color_by, std::string select_by, std::string drag_by, bool use_VBOs);
|
||||
|
||||
int load_wipe_tower_preview(int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs);
|
||||
|
||||
void erase()
|
||||
%code{% THIS->clear(); %};
|
||||
|
||||
|
|
Loading…
Reference in a new issue