Flip Y changed back to BOTTOM_LEFT
Merge remote-tracking branch 'origin/master' into feature_slice_to_png
@ -141,12 +141,12 @@ sub OnInit {
|
||||
$self->CallAfter(sub {
|
||||
eval {
|
||||
if (! $self->{preset_updater}->config_update()) {
|
||||
exit 0;
|
||||
$self->{mainframe}->Close;
|
||||
}
|
||||
};
|
||||
if ($@) {
|
||||
warn $@ . "\n";
|
||||
fatal_error(undef, $@);
|
||||
show_error(undef, $@);
|
||||
$self->{mainframe}->Close;
|
||||
}
|
||||
});
|
||||
|
||||
@ -169,7 +169,8 @@ sub OnInit {
|
||||
$self->update_ui_from_settings;
|
||||
});
|
||||
|
||||
# The following event is emited by PresetUpdater (C++)
|
||||
# The following event is emited by PresetUpdater (C++) to inform about
|
||||
# the newer Slic3r application version avaiable online.
|
||||
EVT_COMMAND($self, -1, $VERSION_ONLINE_EVENT, sub {
|
||||
my ($self, $event) = @_;
|
||||
my $version = $event->GetString;
|
||||
|
@ -127,6 +127,8 @@ sub new {
|
||||
$range->[1] *= $variation;
|
||||
}
|
||||
$_->set_scaling_factor($scale) for @{ $model_object->instances };
|
||||
|
||||
$self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%");
|
||||
$object->transform_thumbnail($self->{model}, $obj_idx);
|
||||
|
||||
#update print and start background processing
|
||||
@ -194,7 +196,7 @@ sub new {
|
||||
$self->schedule_background_process;
|
||||
} else {
|
||||
# Hide the print info box, it is no more valid.
|
||||
$self->{"print_info_box_show"}->(0);
|
||||
$self->print_info_box_show(0);
|
||||
}
|
||||
});
|
||||
|
||||
@ -292,9 +294,9 @@ sub new {
|
||||
$self->{right_panel} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
|
||||
### Scrolled Window for info boxes
|
||||
my $scrolled_window_sizer = Wx::BoxSizer->new(wxVERTICAL);
|
||||
my $scrolled_window_sizer = $self->{scrolled_window_sizer} = Wx::BoxSizer->new(wxVERTICAL);
|
||||
$scrolled_window_sizer->SetMinSize([310, -1]);
|
||||
my $scrolled_window_panel = Wx::ScrolledWindow->new($self->{right_panel}, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
my $scrolled_window_panel = $self->{scrolled_window_panel} = Wx::ScrolledWindow->new($self->{right_panel}, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
$scrolled_window_panel->SetSizer($scrolled_window_sizer);
|
||||
$scrolled_window_panel->SetScrollbars(1, 1, 1, 1);
|
||||
|
||||
@ -520,38 +522,9 @@ sub new {
|
||||
}
|
||||
}
|
||||
|
||||
my $print_info_sizer;
|
||||
{
|
||||
my $box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info"));
|
||||
$print_info_sizer = Wx::StaticBoxSizer->new($box, wxVERTICAL);
|
||||
$print_info_sizer->SetMinSize([300,-1]);
|
||||
my $grid_sizer = Wx::FlexGridSizer->new(2, 2, 5, 5);
|
||||
$grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
|
||||
$grid_sizer->AddGrowableCol(1, 1);
|
||||
$grid_sizer->AddGrowableCol(3, 1);
|
||||
$print_info_sizer->Add($grid_sizer, 0, wxEXPAND);
|
||||
my @info = (
|
||||
fil_m => L("Used Filament (m)"),
|
||||
fil_mm3 => L("Used Filament (mm³)"),
|
||||
fil_g => L("Used Filament (g)"),
|
||||
cost => L("Cost"),
|
||||
#==========================================================================================================================================
|
||||
normal_time => L("Estimated printing time (normal mode)"),
|
||||
# default_time => L("Estimated printing time (default mode)"),
|
||||
#==========================================================================================================================================
|
||||
silent_time => L("Estimated printing time (silent mode)"),
|
||||
);
|
||||
while (my $field = shift @info) {
|
||||
my $label = shift @info;
|
||||
my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
|
||||
$text->SetFont($Slic3r::GUI::small_font);
|
||||
$grid_sizer->Add($text, 0);
|
||||
|
||||
$self->{"print_info_$field"} = Wx::StaticText->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
|
||||
$self->{"print_info_$field"}->SetFont($Slic3r::GUI::small_font);
|
||||
$grid_sizer->Add($self->{"print_info_$field"}, 0);
|
||||
}
|
||||
}
|
||||
my $print_info_sizer = $self->{print_info_sizer} = Wx::StaticBoxSizer->new(
|
||||
Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info")), wxVERTICAL);
|
||||
$print_info_sizer->SetMinSize([300,-1]);
|
||||
|
||||
my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
||||
$self->{buttons_sizer} = $buttons_sizer;
|
||||
@ -572,19 +545,8 @@ sub new {
|
||||
$right_sizer->Add($frequently_changed_parameters_sizer, 0, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer;
|
||||
$right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM, 5);
|
||||
$right_sizer->Add($scrolled_window_panel, 1, wxEXPAND | wxALL, 1);
|
||||
# Callback for showing / hiding the print info box.
|
||||
$self->{"print_info_box_show"} = sub {
|
||||
# if ($right_sizer->IsShown(5) != $_[0]) {
|
||||
# $right_sizer->Show(5, $_[0]);
|
||||
# $self->Layout
|
||||
# }
|
||||
if ($scrolled_window_sizer->IsShown(2) != $_[0]) {
|
||||
$scrolled_window_sizer->Show(2, $_[0]);
|
||||
$scrolled_window_panel->Layout
|
||||
}
|
||||
};
|
||||
# Show the box initially, let it be shown after the slicing is finished.
|
||||
$self->{"print_info_box_show"}->(0);
|
||||
$self->print_info_box_show(0);
|
||||
|
||||
$self->{right_panel}->SetSizer($right_sizer);
|
||||
|
||||
@ -1300,7 +1262,7 @@ sub async_apply_config {
|
||||
$self->{canvas3D}->Refresh if Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D});
|
||||
|
||||
# Hide the slicing results if the current slicing status is no more valid.
|
||||
$self->{"print_info_box_show"}->(0) if $invalidated;
|
||||
$self->print_info_box_show(0) if $invalidated;
|
||||
|
||||
if (wxTheApp->{app_config}->get("background_processing")) {
|
||||
if ($invalidated) {
|
||||
@ -1618,16 +1580,7 @@ sub on_export_completed {
|
||||
|
||||
$self->{print_file} = undef;
|
||||
$self->{send_gcode_file} = undef;
|
||||
$self->{"print_info_cost"}->SetLabel(sprintf("%.2f" , $self->{print}->total_cost));
|
||||
$self->{"print_info_fil_g"}->SetLabel(sprintf("%.2f" , $self->{print}->total_weight));
|
||||
$self->{"print_info_fil_mm3"}->SetLabel(sprintf("%.2f" , $self->{print}->total_extruded_volume));
|
||||
#==========================================================================================================================================
|
||||
$self->{"print_info_normal_time"}->SetLabel($self->{print}->estimated_normal_print_time);
|
||||
# $self->{"print_info_default_time"}->SetLabel($self->{print}->estimated_default_print_time);
|
||||
#==========================================================================================================================================
|
||||
$self->{"print_info_silent_time"}->SetLabel($self->{print}->estimated_silent_print_time);
|
||||
$self->{"print_info_fil_m"}->SetLabel(sprintf("%.2f" , $self->{print}->total_used_filament / 1000));
|
||||
$self->{"print_info_box_show"}->(1);
|
||||
$self->print_info_box_show(1);
|
||||
|
||||
# this updates buttons status
|
||||
$self->object_list_changed;
|
||||
@ -1637,6 +1590,51 @@ sub on_export_completed {
|
||||
$self->{preview3D}->reload_print if $self->{preview3D};
|
||||
}
|
||||
|
||||
# Fill in the "Sliced info" box with the result of the G-code generator.
|
||||
sub print_info_box_show {
|
||||
my ($self, $show) = @_;
|
||||
my $scrolled_window_panel = $self->{scrolled_window_panel};
|
||||
my $scrolled_window_sizer = $self->{scrolled_window_sizer};
|
||||
return if $scrolled_window_sizer->IsShown(2) == $show;
|
||||
|
||||
if ($show) {
|
||||
my $print_info_sizer = $self->{print_info_sizer};
|
||||
$print_info_sizer->Clear(1);
|
||||
my $grid_sizer = Wx::FlexGridSizer->new(2, 2, 5, 5);
|
||||
$grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
|
||||
$grid_sizer->AddGrowableCol(1, 1);
|
||||
$grid_sizer->AddGrowableCol(3, 1);
|
||||
$print_info_sizer->Add($grid_sizer, 0, wxEXPAND);
|
||||
my @info = (
|
||||
L("Used Filament (m)")
|
||||
=> sprintf("%.2f" , $self->{print}->total_used_filament / 1000),
|
||||
L("Used Filament (mm³)")
|
||||
=> sprintf("%.2f" , $self->{print}->total_extruded_volume),
|
||||
L("Used Filament (g)"),
|
||||
=> sprintf("%.2f" , $self->{print}->total_weight),
|
||||
L("Cost"),
|
||||
=> sprintf("%.2f" , $self->{print}->total_cost),
|
||||
L("Estimated printing time (normal mode)")
|
||||
=> $self->{print}->estimated_normal_print_time,
|
||||
L("Estimated printing time (silent mode)")
|
||||
=> $self->{print}->estimated_silent_print_time
|
||||
);
|
||||
while ( my $label = shift @info) {
|
||||
my $value = shift @info;
|
||||
next if $value eq "N/A";
|
||||
my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
|
||||
$text->SetFont($Slic3r::GUI::small_font);
|
||||
$grid_sizer->Add($text, 0);
|
||||
my $field = Wx::StaticText->new($scrolled_window_panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
|
||||
$field->SetFont($Slic3r::GUI::small_font);
|
||||
$grid_sizer->Add($field, 0);
|
||||
}
|
||||
}
|
||||
|
||||
$scrolled_window_sizer->Show(2, $show);
|
||||
$scrolled_window_panel->Layout;
|
||||
}
|
||||
|
||||
sub do_print {
|
||||
my ($self) = @_;
|
||||
|
||||
@ -1669,7 +1667,7 @@ sub reload_from_disk {
|
||||
my $model_object = $self->{model}->objects->[$obj_idx];
|
||||
#FIXME convert to local file encoding
|
||||
return if !$model_object->input_file
|
||||
|| !-e $model_object->input_file;
|
||||
|| !-e Slic3r::encode_path($model_object->input_file);
|
||||
|
||||
my @new_obj_idx = $self->load_files([$model_object->input_file]);
|
||||
return if !@new_obj_idx;
|
||||
@ -2104,7 +2102,8 @@ sub object_list_changed {
|
||||
|
||||
my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file};
|
||||
my $model_fits = $self->{canvas3D} ? Slic3r::GUI::_3DScene::check_volumes_outside_state($self->{canvas3D}, $self->{config}) : 1;
|
||||
my $method = ($have_objects && ! $export_in_progress && $model_fits) ? 'Enable' : 'Disable';
|
||||
# $model_fits == 1 -> ModelInstance::PVS_Partly_Outside
|
||||
my $method = ($have_objects && ! $export_in_progress && ($model_fits != 1)) ? 'Enable' : 'Disable';
|
||||
$self->{"btn_$_"}->$method
|
||||
for grep $self->{"btn_$_"}, qw(reslice export_gcode print send_gcode);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 30 KiB |
BIN
resources/icons/printers/PrusaResearch_MK3MM2.png
Normal file
After Width: | Height: | Size: 41 KiB |
@ -1,6 +1,13 @@
|
||||
min_slic3r_version = 1.41.0-alpha
|
||||
0.2.0-alpha
|
||||
0.2.0-alpha2 Renamed the key MK3SMMU to MK3MMU2, added a generic PLA MMU2 material
|
||||
0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0
|
||||
0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters
|
||||
min_slic3r_version = 1.40.0
|
||||
0.1.11 fw version changed to 3.3.1
|
||||
0.1.10 MK3 jerk and acceleration update
|
||||
0.1.9 edited support extrusion width for 0.25 and 0.6 nozzles
|
||||
0.1.8 extrusion width for 0,25, 0.6 and variable layer height fixes
|
||||
0.1.7 Fixed errors in 0.25mm and 0.6mm profiles
|
||||
0.1.6 Split the MK2.5 profile from the MK2S
|
||||
min_slic3r_version = 1.40.0-beta
|
||||
0.1.5 fixed printer_variant fields for the i3 MK3 0.25 and 0.6mm nozzles
|
||||
|
@ -5,7 +5,7 @@
|
||||
name = Prusa Research
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the Slic3r configuration to be downgraded.
|
||||
config_version = 0.2.0-alpha
|
||||
config_version = 0.2.0-alpha2
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/
|
||||
|
||||
@ -27,9 +27,13 @@ name = Original Prusa i3 MK2.5
|
||||
variants = 0.4; 0.25; 0.6
|
||||
|
||||
[printer_model:MK2SMM]
|
||||
name = Original Prusa i3 MK2SMM
|
||||
name = Original Prusa i3 MK2S Multi Material Upgrade
|
||||
variants = 0.4; 0.6
|
||||
|
||||
[printer_model:MK3MM2]
|
||||
name = Original Prusa i3 MK3 Multi Material Upgrade 2.0
|
||||
variants = 0.4
|
||||
|
||||
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
||||
# not make it into the user interface.
|
||||
|
||||
@ -207,7 +211,7 @@ infill_extrusion_width = 0.5
|
||||
|
||||
[print:0.05mm ULTRADETAIL MK3]
|
||||
inherits = *0.05mm*
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material
|
||||
fill_pattern = grid
|
||||
top_infill_extrusion_width = 0.4
|
||||
|
||||
@ -252,7 +256,7 @@ solid_infill_speed = 50
|
||||
[print:0.10mm DETAIL MK3]
|
||||
inherits = *0.10mm*
|
||||
bridge_speed = 30
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material
|
||||
external_perimeter_speed = 35
|
||||
fill_pattern = grid
|
||||
infill_acceleration = 1500
|
||||
@ -358,7 +362,7 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and
|
||||
[print:0.15mm OPTIMAL MK3]
|
||||
inherits = *0.15mm*
|
||||
bridge_speed = 30
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material
|
||||
external_perimeter_speed = 35
|
||||
fill_pattern = grid
|
||||
infill_acceleration = 1500
|
||||
@ -426,6 +430,32 @@ perimeter_speed = 45
|
||||
solid_infill_speed = 200
|
||||
top_solid_infill_speed = 50
|
||||
|
||||
[print:0.15mm OPTIMAL MK3 MMU2]
|
||||
inherits = 0.15mm OPTIMAL MK3
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material
|
||||
bottom_solid_layers = 4
|
||||
external_perimeter_speed = 40
|
||||
fill_density = 10%
|
||||
infill_overlap = 15%
|
||||
perimeter_speed = 60
|
||||
small_perimeter_speed = 20
|
||||
support_material_threshold = 20
|
||||
top_solid_layers = 5
|
||||
|
||||
[print:0.20mm FAST MK3 MMU2]
|
||||
inherits = 0.20mm FAST MK3
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material
|
||||
bridge_flow_ratio = 0.8
|
||||
external_perimeter_speed = 40
|
||||
fill_density = 15%
|
||||
infill_overlap = 35%
|
||||
infill_speed = 150
|
||||
perimeter_speed = 50
|
||||
small_perimeter_speed = 20
|
||||
solid_infill_speed = 150
|
||||
wipe_tower_x = 169
|
||||
wipe_tower_y = 137
|
||||
|
||||
# XXXXXXXXXXXXXXXXXXXX
|
||||
# XXX--- 0.20mm ---XXX
|
||||
# XXXXXXXXXXXXXXXXXXXX
|
||||
@ -445,7 +475,7 @@ top_solid_infill_speed = 70
|
||||
[print:0.20mm FAST MK3]
|
||||
inherits = *0.20mm*
|
||||
bridge_speed = 30
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material
|
||||
external_perimeter_speed = 35
|
||||
fill_pattern = grid
|
||||
infill_acceleration = 1500
|
||||
@ -552,12 +582,16 @@ support_material_xy_spacing = 150%
|
||||
[filament:*common*]
|
||||
cooling = 1
|
||||
compatible_printers =
|
||||
compatible_printers_condition =
|
||||
# For now, all but selected filaments are disabled for the MMU 2.0
|
||||
compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
|
||||
end_filament_gcode = "; Filament-specific end gcode"
|
||||
extrusion_multiplier = 1
|
||||
filament_loading_speed = 28
|
||||
filament_unloading_speed = 90
|
||||
filament_toolchange_delay = 0
|
||||
filament_cooling_moves = 4
|
||||
filament_cooling_initial_speed = 2.2
|
||||
filament_cooling_final_speed = 3.4
|
||||
filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
|
||||
filament_cost = 0
|
||||
filament_density = 0
|
||||
@ -624,7 +658,8 @@ temperature = 255
|
||||
inherits = *common*
|
||||
bed_temperature = 50
|
||||
bridge_fan_speed = 100
|
||||
compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1
|
||||
# For now, all but selected filaments are disabled for the MMU 2.0
|
||||
compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
|
||||
cooling = 0
|
||||
disable_fan_first_layers = 1
|
||||
extrusion_multiplier = 1.2
|
||||
@ -642,7 +677,8 @@ temperature = 240
|
||||
|
||||
[filament:ColorFabb Brass Bronze]
|
||||
inherits = *PLA*
|
||||
compatible_printers_condition = nozzle_diameter[0]>0.35
|
||||
# For now, all but selected filaments are disabled for the MMU 2.0
|
||||
compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
|
||||
extrusion_multiplier = 1.2
|
||||
filament_colour = #804040
|
||||
filament_max_volumetric_speed = 10
|
||||
@ -667,7 +703,8 @@ inherits = *PLA*
|
||||
|
||||
[filament:ColorFabb Woodfil]
|
||||
inherits = *PLA*
|
||||
compatible_printers_condition = nozzle_diameter[0]>0.35
|
||||
# For now, all but selected filaments are disabled for the MMU 2.0
|
||||
compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
|
||||
extrusion_multiplier = 1.2
|
||||
filament_colour = #804040
|
||||
filament_max_volumetric_speed = 10
|
||||
@ -748,7 +785,8 @@ temperature = 275
|
||||
|
||||
[filament:Fillamentum Timberfil]
|
||||
inherits = *PLA*
|
||||
compatible_printers_condition = nozzle_diameter[0]>0.35
|
||||
# For now, all but selected filaments are disabled for the MMU 2.0
|
||||
compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
|
||||
extrusion_multiplier = 1.2
|
||||
filament_colour = #804040
|
||||
filament_max_volumetric_speed = 10
|
||||
@ -818,6 +856,21 @@ filament_notes = "List of manufacturers tested with standart PET print settings
|
||||
inherits = *PLA*
|
||||
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
|
||||
|
||||
[filament:*PLA MMU2*]
|
||||
inherits = Prusa PLA
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material
|
||||
filament_cooling_final_speed = 50
|
||||
filament_cooling_initial_speed = 10
|
||||
filament_cooling_moves = 7
|
||||
filament_loading_speed = 14
|
||||
filament_ramming_parameters = "120 110 4.03226 4.12903 4.25806 4.41935 4.58065 4.80645 5.35484 6.29032 7.58065 9.09677 10.5806 11.8387 12.6452 12.9677| 0.05 4.01935 0.45 4.15483 0.95 4.50968 1.45 4.94516 1.95 6.79677 2.45 9.87102 2.95 12.4388 3.45 13.0839 3.95 7.6 4.45 7.6 4.95 7.6"
|
||||
|
||||
[filament:Generic PLA MMU2]
|
||||
inherits = *PLA MMU2*
|
||||
|
||||
[filament:Prusa PLA MMU2]
|
||||
inherits = *PLA MMU2*
|
||||
|
||||
[filament:SemiFlex or Flexfill 98A]
|
||||
inherits = *FLEX*
|
||||
|
||||
@ -979,7 +1032,6 @@ end_gcode = G1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN
|
||||
start_gcode = M115 U3.1.0 ; tell printer latest fw version\n; Start G-Code sequence START\nT?\nM104 S[first_layer_temperature]\nM140 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nM190 S[first_layer_bed_temperature]\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\nG92 E0.0
|
||||
default_print_profile = 0.15mm OPTIMAL
|
||||
default_filament_profile = Prusa PLA
|
||||
|
||||
[printer:*mm-multi*]
|
||||
inherits = *multimaterial*
|
||||
@ -990,7 +1042,6 @@ printer_notes = Don't remove the following keywords! These keywords are used in
|
||||
start_gcode = M115 U3.1.0 ; tell printer latest fw version\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_wipe_tower}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\n{endif}\nG92 E0.0
|
||||
variable_layer_height = 0
|
||||
default_print_profile = 0.15mm OPTIMAL
|
||||
default_filament_profile = Prusa PLA
|
||||
|
||||
# XXXXXXXXXXXXXXXXX
|
||||
# XXX--- MK2 ---XXX
|
||||
@ -1107,6 +1158,34 @@ min_layer_height = 0.1
|
||||
printer_variant = 0.6
|
||||
default_print_profile = 0.15mm OPTIMAL 0.6 nozzle MK3
|
||||
|
||||
[printer:*mm2*]
|
||||
inherits = Original Prusa i3 MK3
|
||||
single_extruder_multi_material = 1
|
||||
max_print_height = 200
|
||||
cooling_tube_length = 10
|
||||
cooling_tube_retraction = 30
|
||||
parking_pos_retraction = 85
|
||||
retract_length_toolchange = 3
|
||||
extra_loading_move = -13
|
||||
printer_model = MK3MM2
|
||||
default_print_profile = 0.15mm OPTIMAL MK3 MMU2
|
||||
default_filament_profile = Prusa PLA MMU2
|
||||
|
||||
[printer:Original Prusa i3 MK3 MMU2 Single]
|
||||
inherits = *mm2*
|
||||
start_gcode = M107\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n ; go outside print area\nG1 Y-3.0 F1000.0 \nG1 Z0.4 F1000\n; select extruder\nT?\n; initial load\nG1 X50 E15 F1073\nG1 X100 E10 F2000\nG1 Z0.3 F1000\n\nG92 E0.0\nG1 X240.0 E15.0 F2400.0 \nG1 Y-2.0 F1000.0\nG1 X100.0 E10 F1400.0 \nG1 Z0.20 F1000\nG1 X0.0 E4 F1000.0\n\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
|
||||
end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
|
||||
|
||||
[printer:Original Prusa i3 MK3 MMU2]
|
||||
inherits = *mm2*
|
||||
# The 5x nozzle diameter defines the number of extruders. Other extruder parameters
|
||||
# (for example the retract values) are duplicaed from the first value, so they do not need
|
||||
# to be defined explicitely.
|
||||
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
|
||||
extruder_colour = #FFFF00;#FFFFFF;#804040;#0000FF;#C0C0C0
|
||||
start_gcode = M107\n\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
|
||||
end_gcode = G1 E-15.0000 F3000\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
|
||||
|
||||
# The obsolete presets will be removed when upgrading from the legacy configuration structure (up to Slic3r 1.39.2) to 1.40.0 and newer.
|
||||
[obsolete_presets]
|
||||
print="0.05mm DETAIL 0.25 nozzle";"0.05mm DETAIL MK3";"0.05mm DETAIL";"0.20mm NORMAL MK3";"0.35mm FAST MK3"
|
||||
|
@ -25,6 +25,9 @@ THE SOFTWARE.
|
||||
#ifndef SHINY_PREREQS_H
|
||||
#define SHINY_PREREQS_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef FALSE
|
||||
|
@ -93,8 +93,11 @@ float ShinyGetTickInvFreq(void) {
|
||||
|
||||
#elif SHINY_PLATFORM == SHINY_PLATFORM_POSIX
|
||||
|
||||
//#include <time.h>
|
||||
//#include <sys/time.h>
|
||||
|
||||
void ShinyGetTicks(shinytick_t *p) {
|
||||
timeval time;
|
||||
struct timeval time;
|
||||
gettimeofday(&time, NULL);
|
||||
|
||||
*p = time.tv_sec * 1000000 + time.tv_usec;
|
||||
|
@ -519,20 +519,28 @@ void arrangeRectangles() {
|
||||
|
||||
std::vector<Item> proba = {
|
||||
{
|
||||
{ {0, 0}, {20, 20}, {40, 0}, {0, 0} }
|
||||
Rectangle(100, 2)
|
||||
},
|
||||
{
|
||||
{ {0, 100}, {50, 60}, {100, 100}, {50, 0}, {0, 100} }
|
||||
|
||||
Rectangle(100, 2)
|
||||
},
|
||||
{
|
||||
Rectangle(100, 2)
|
||||
},
|
||||
{
|
||||
Rectangle(10, 10)
|
||||
},
|
||||
};
|
||||
|
||||
proba[0].rotate(Pi/3);
|
||||
proba[1].rotate(Pi-Pi/3);
|
||||
|
||||
std::vector<Item> input;
|
||||
input.insert(input.end(), prusaParts().begin(), prusaParts().end());
|
||||
// input.insert(input.end(), prusaExParts().begin(), prusaExParts().end());
|
||||
// input.insert(input.end(), stegoParts().begin(), stegoParts().end());
|
||||
input.insert(input.end(), stegoParts().begin(), stegoParts().end());
|
||||
// input.insert(input.end(), rects.begin(), rects.end());
|
||||
// input.insert(input.end(), proba.begin(), proba.end());
|
||||
input.insert(input.end(), proba.begin(), proba.end());
|
||||
// input.insert(input.end(), crasher.begin(), crasher.end());
|
||||
|
||||
Box bin(250*SCALE, 210*SCALE);
|
||||
@ -569,9 +577,9 @@ void arrangeRectangles() {
|
||||
Packer::SelectionConfig sconf;
|
||||
// sconf.allow_parallel = false;
|
||||
// sconf.force_parallel = false;
|
||||
// sconf.try_triplets = true;
|
||||
// sconf.try_triplets = false;
|
||||
// sconf.try_reverse_order = true;
|
||||
// sconf.waste_increment = 0.1;
|
||||
// sconf.waste_increment = 0.005;
|
||||
|
||||
arrange.configure(pconf, sconf);
|
||||
|
||||
|
@ -25,9 +25,60 @@ using Shapes = typename ShapeLike::Shapes<RawShape>;
|
||||
|
||||
/// Minkowski addition (not used yet)
|
||||
template<class RawShape>
|
||||
static RawShape minkowskiDiff(const RawShape& sh, const RawShape& /*other*/)
|
||||
static RawShape minkowskiDiff(const RawShape& sh, const RawShape& cother)
|
||||
{
|
||||
using Vertex = TPoint<RawShape>;
|
||||
//using Coord = TCoord<Vertex>;
|
||||
using Edge = _Segment<Vertex>;
|
||||
using sl = ShapeLike;
|
||||
using std::signbit;
|
||||
|
||||
// Copy the orbiter (controur only), we will have to work on it
|
||||
RawShape orbiter = sl::create(sl::getContour(cother));
|
||||
|
||||
// Make the orbiter reverse oriented
|
||||
for(auto &v : sl::getContour(orbiter)) v = -v;
|
||||
|
||||
// An egde with additional data for marking it
|
||||
struct MarkedEdge { Edge e; Radians turn_angle; bool is_turning_point; };
|
||||
|
||||
// Container for marked edges
|
||||
using EdgeList = std::vector<MarkedEdge>;
|
||||
|
||||
EdgeList A, B;
|
||||
|
||||
auto fillEdgeList = [](EdgeList& L, const RawShape& poly) {
|
||||
L.reserve(sl::contourVertexCount(poly));
|
||||
|
||||
auto it = sl::cbegin(poly);
|
||||
auto nextit = std::next(it);
|
||||
|
||||
L.emplace_back({Edge(*it, *nextit), 0, false});
|
||||
it++; nextit++;
|
||||
|
||||
while(nextit != sl::cend(poly)) {
|
||||
Edge e(*it, *nextit);
|
||||
auto& L_prev = L.back();
|
||||
auto phi = L_prev.e.angleToXaxis();
|
||||
auto phi_prev = e.angleToXaxis();
|
||||
auto turn_angle = phi-phi_prev;
|
||||
if(turn_angle > Pi) turn_angle -= 2*Pi;
|
||||
L.emplace_back({
|
||||
e,
|
||||
turn_angle,
|
||||
signbit(turn_angle) != signbit(L_prev.turn_angle)
|
||||
});
|
||||
it++; nextit++;
|
||||
}
|
||||
|
||||
L.front().turn_angle = L.front().e.angleToXaxis() -
|
||||
L.back().e.angleToXaxis();
|
||||
|
||||
if(L.front().turn_angle > Pi) L.front().turn_angle -= 2*Pi;
|
||||
};
|
||||
|
||||
fillEdgeList(A, sh);
|
||||
fillEdgeList(B, orbiter);
|
||||
|
||||
return sh;
|
||||
}
|
||||
@ -193,6 +244,9 @@ static RawShape nfpConvexOnly(const RawShape& sh, const RawShape& cother)
|
||||
// Lindmark's reasoning about the reference vertex of nfp in his thesis
|
||||
// ("No fit polygon problem" - section 2.1.9)
|
||||
|
||||
// TODO: dont do this here. Cache the rmu and lmd in Item and get translate
|
||||
// the nfp after this call
|
||||
|
||||
auto csh = sh; // Copy sh, we will sort the verices in the copy
|
||||
auto& cmp = _vsort<RawShape>;
|
||||
std::sort(ShapeLike::begin(csh), ShapeLike::end(csh), cmp);
|
||||
|
@ -48,32 +48,89 @@ template<class RawShape> class EdgeCache {
|
||||
using Coord = TCoord<Vertex>;
|
||||
using Edge = _Segment<Vertex>;
|
||||
|
||||
mutable std::vector<double> corners_;
|
||||
struct ContourCache {
|
||||
mutable std::vector<double> corners;
|
||||
std::vector<Edge> emap;
|
||||
std::vector<double> distances;
|
||||
double full_distance = 0;
|
||||
} contour_;
|
||||
|
||||
std::vector<Edge> emap_;
|
||||
std::vector<double> distances_;
|
||||
double full_distance_ = 0;
|
||||
std::vector<ContourCache> holes_;
|
||||
|
||||
void createCache(const RawShape& sh) {
|
||||
auto first = ShapeLike::cbegin(sh);
|
||||
auto next = first + 1;
|
||||
auto endit = ShapeLike::cend(sh);
|
||||
{ // For the contour
|
||||
auto first = ShapeLike::cbegin(sh);
|
||||
auto next = std::next(first);
|
||||
auto endit = ShapeLike::cend(sh);
|
||||
|
||||
distances_.reserve(ShapeLike::contourVertexCount(sh));
|
||||
contour_.distances.reserve(ShapeLike::contourVertexCount(sh));
|
||||
|
||||
while(next != endit) {
|
||||
emap_.emplace_back(*(first++), *(next++));
|
||||
full_distance_ += emap_.back().length();
|
||||
distances_.push_back(full_distance_);
|
||||
while(next != endit) {
|
||||
contour_.emap.emplace_back(*(first++), *(next++));
|
||||
contour_.full_distance += contour_.emap.back().length();
|
||||
contour_.distances.push_back(contour_.full_distance);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& h : ShapeLike::holes(sh)) { // For the holes
|
||||
auto first = h.begin();
|
||||
auto next = std::next(first);
|
||||
auto endit = h.end();
|
||||
|
||||
ContourCache hc;
|
||||
hc.distances.reserve(endit - first);
|
||||
|
||||
while(next != endit) {
|
||||
hc.emap.emplace_back(*(first++), *(next++));
|
||||
hc.full_distance += hc.emap.back().length();
|
||||
hc.distances.push_back(hc.full_distance);
|
||||
}
|
||||
|
||||
holes_.push_back(hc);
|
||||
}
|
||||
}
|
||||
|
||||
void fetchCorners() const {
|
||||
if(!corners_.empty()) return;
|
||||
if(!contour_.corners.empty()) return;
|
||||
|
||||
// TODO Accuracy
|
||||
corners_ = distances_;
|
||||
for(auto& d : corners_) d /= full_distance_;
|
||||
contour_.corners = contour_.distances;
|
||||
for(auto& d : contour_.corners) d /= contour_.full_distance;
|
||||
}
|
||||
|
||||
void fetchHoleCorners(unsigned hidx) const {
|
||||
auto& hc = holes_[hidx];
|
||||
if(!hc.corners.empty()) return;
|
||||
|
||||
// TODO Accuracy
|
||||
hc.corners = hc.distances;
|
||||
for(auto& d : hc.corners) d /= hc.full_distance;
|
||||
}
|
||||
|
||||
inline Vertex coords(const ContourCache& cache, double distance) const {
|
||||
assert(distance >= .0 && distance <= 1.0);
|
||||
|
||||
// distance is from 0.0 to 1.0, we scale it up to the full length of
|
||||
// the circumference
|
||||
double d = distance*cache.full_distance;
|
||||
|
||||
auto& distances = cache.distances;
|
||||
|
||||
// Magic: we find the right edge in log time
|
||||
auto it = std::lower_bound(distances.begin(), distances.end(), d);
|
||||
auto idx = it - distances.begin(); // get the index of the edge
|
||||
auto edge = cache.emap[idx]; // extrac the edge
|
||||
|
||||
// Get the remaining distance on the target edge
|
||||
auto ed = d - (idx > 0 ? *std::prev(it) : 0 );
|
||||
auto angle = edge.angleToXaxis();
|
||||
Vertex ret = edge.first();
|
||||
|
||||
// Get the point on the edge which lies in ed distance from the start
|
||||
ret += { static_cast<Coord>(std::round(ed*std::cos(angle))),
|
||||
static_cast<Coord>(std::round(ed*std::sin(angle))) };
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -102,37 +159,36 @@ public:
|
||||
* @return Returns the coordinates of the point lying on the polygon
|
||||
* circumference.
|
||||
*/
|
||||
inline Vertex coords(double distance) {
|
||||
assert(distance >= .0 && distance <= 1.0);
|
||||
|
||||
// distance is from 0.0 to 1.0, we scale it up to the full length of
|
||||
// the circumference
|
||||
double d = distance*full_distance_;
|
||||
|
||||
// Magic: we find the right edge in log time
|
||||
auto it = std::lower_bound(distances_.begin(), distances_.end(), d);
|
||||
auto idx = it - distances_.begin(); // get the index of the edge
|
||||
auto edge = emap_[idx]; // extrac the edge
|
||||
|
||||
// Get the remaining distance on the target edge
|
||||
auto ed = d - (idx > 0 ? *std::prev(it) : 0 );
|
||||
auto angle = edge.angleToXaxis();
|
||||
Vertex ret = edge.first();
|
||||
|
||||
// Get the point on the edge which lies in ed distance from the start
|
||||
ret += { static_cast<Coord>(std::round(ed*std::cos(angle))),
|
||||
static_cast<Coord>(std::round(ed*std::sin(angle))) };
|
||||
|
||||
return ret;
|
||||
inline Vertex coords(double distance) const {
|
||||
return coords(contour_, distance);
|
||||
}
|
||||
|
||||
inline double circumference() const BP2D_NOEXCEPT { return full_distance_; }
|
||||
inline Vertex coords(unsigned hidx, double distance) const {
|
||||
assert(hidx < holes_.size());
|
||||
return coords(holes_[hidx], distance);
|
||||
}
|
||||
|
||||
inline double circumference() const BP2D_NOEXCEPT {
|
||||
return contour_.full_distance;
|
||||
}
|
||||
|
||||
inline double circumference(unsigned hidx) const BP2D_NOEXCEPT {
|
||||
return holes_[hidx].full_distance;
|
||||
}
|
||||
|
||||
inline const std::vector<double>& corners() const BP2D_NOEXCEPT {
|
||||
fetchCorners();
|
||||
return corners_;
|
||||
return contour_.corners;
|
||||
}
|
||||
|
||||
inline const std::vector<double>&
|
||||
corners(unsigned holeidx) const BP2D_NOEXCEPT {
|
||||
fetchHoleCorners(holeidx);
|
||||
return holes_[holeidx].corners;
|
||||
}
|
||||
|
||||
inline unsigned holeCount() const BP2D_NOEXCEPT { return holes_.size(); }
|
||||
|
||||
};
|
||||
|
||||
template<NfpLevel lvl>
|
||||
@ -294,12 +350,20 @@ public:
|
||||
|
||||
for(auto& nfp : nfps ) ecache.emplace_back(nfp);
|
||||
|
||||
auto getNfpPoint = [&ecache](double relpos) {
|
||||
auto relpfloor = std::floor(relpos);
|
||||
auto nfp_idx = static_cast<unsigned>(relpfloor);
|
||||
if(nfp_idx >= ecache.size()) nfp_idx--;
|
||||
auto p = relpos - relpfloor;
|
||||
return ecache[nfp_idx].coords(p);
|
||||
struct Optimum {
|
||||
double relpos;
|
||||
unsigned nfpidx;
|
||||
int hidx;
|
||||
Optimum(double pos, unsigned nidx):
|
||||
relpos(pos), nfpidx(nidx), hidx(-1) {}
|
||||
Optimum(double pos, unsigned nidx, int holeidx):
|
||||
relpos(pos), nfpidx(nidx), hidx(holeidx) {}
|
||||
};
|
||||
|
||||
auto getNfpPoint = [&ecache](const Optimum& opt)
|
||||
{
|
||||
return opt.hidx < 0? ecache[opt.nfpidx].coords(opt.relpos) :
|
||||
ecache[opt.nfpidx].coords(opt.nfpidx, opt.relpos);
|
||||
};
|
||||
|
||||
Nfp::Shapes<RawShape> pile;
|
||||
@ -310,6 +374,8 @@ public:
|
||||
pile_area += mitem.area();
|
||||
}
|
||||
|
||||
// This is the kernel part of the object function that is
|
||||
// customizable by the library client
|
||||
auto _objfunc = config_.object_function?
|
||||
config_.object_function :
|
||||
[this](const Nfp::Shapes<RawShape>& pile, double occupied_area,
|
||||
@ -334,9 +400,8 @@ public:
|
||||
};
|
||||
|
||||
// Our object function for placement
|
||||
auto objfunc = [&] (double relpos)
|
||||
auto rawobjfunc = [&] (Vertex v)
|
||||
{
|
||||
Vertex v = getNfpPoint(relpos);
|
||||
auto d = v - iv;
|
||||
d += startpos;
|
||||
item.translation(d);
|
||||
@ -359,46 +424,74 @@ public:
|
||||
stopcr.type = opt::StopLimitType::RELATIVE;
|
||||
opt::TOptimizer<opt::Method::L_SIMPLEX> solver(stopcr);
|
||||
|
||||
double optimum = 0;
|
||||
Optimum optimum(0, 0);
|
||||
double best_score = penality_;
|
||||
|
||||
// double max_bound = 1.0*nfps.size();
|
||||
// Genetic should look like this:
|
||||
/*auto result = solver.optimize_min(objfunc,
|
||||
opt::initvals<double>(0.0),
|
||||
opt::bound(0.0, max_bound)
|
||||
);
|
||||
|
||||
if(result.score < penality_) {
|
||||
best_score = result.score;
|
||||
optimum = std::get<0>(result.optimum);
|
||||
}*/
|
||||
|
||||
// Local optimization with the four polygon corners as
|
||||
// starting points
|
||||
for(unsigned ch = 0; ch < ecache.size(); ch++) {
|
||||
auto& cache = ecache[ch];
|
||||
|
||||
auto contour_ofn = [&rawobjfunc, &getNfpPoint, ch]
|
||||
(double relpos)
|
||||
{
|
||||
return rawobjfunc(getNfpPoint(Optimum(relpos, ch)));
|
||||
};
|
||||
|
||||
std::for_each(cache.corners().begin(),
|
||||
cache.corners().end(),
|
||||
[ch, &solver, &objfunc,
|
||||
&best_score, &optimum]
|
||||
(double pos)
|
||||
[ch, &contour_ofn, &solver, &best_score,
|
||||
&optimum] (double pos)
|
||||
{
|
||||
try {
|
||||
auto result = solver.optimize_min(objfunc,
|
||||
opt::initvals<double>(ch+pos),
|
||||
opt::bound<double>(ch, 1.0 + ch)
|
||||
auto result = solver.optimize_min(contour_ofn,
|
||||
opt::initvals<double>(pos),
|
||||
opt::bound<double>(0, 1.0)
|
||||
);
|
||||
|
||||
if(result.score < best_score) {
|
||||
best_score = result.score;
|
||||
optimum = std::get<0>(result.optimum);
|
||||
optimum.relpos = std::get<0>(result.optimum);
|
||||
optimum.nfpidx = ch;
|
||||
optimum.hidx = -1;
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
derr() << "ERROR: " << e.what() << "\n";
|
||||
}
|
||||
});
|
||||
|
||||
for(unsigned hidx = 0; hidx < cache.holeCount(); ++hidx) {
|
||||
auto hole_ofn =
|
||||
[&rawobjfunc, &getNfpPoint, ch, hidx]
|
||||
(double pos)
|
||||
{
|
||||
Optimum opt(pos, ch, hidx);
|
||||
return rawobjfunc(getNfpPoint(opt));
|
||||
};
|
||||
|
||||
std::for_each(cache.corners(hidx).begin(),
|
||||
cache.corners(hidx).end(),
|
||||
[&hole_ofn, &solver, &best_score,
|
||||
&optimum, ch, hidx]
|
||||
(double pos)
|
||||
{
|
||||
try {
|
||||
auto result = solver.optimize_min(hole_ofn,
|
||||
opt::initvals<double>(pos),
|
||||
opt::bound<double>(0, 1.0)
|
||||
);
|
||||
|
||||
if(result.score < best_score) {
|
||||
best_score = result.score;
|
||||
Optimum o(std::get<0>(result.optimum),
|
||||
ch, hidx);
|
||||
optimum = o;
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
derr() << "ERROR: " << e.what() << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if( best_score < global_score ) {
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
};
|
||||
|
||||
// Safety test: try to pack each item into an empty bin. If it fails
|
||||
// then it should be removed from the not_packed list
|
||||
// then it should be removed from the list
|
||||
{ auto it = store_.begin();
|
||||
while (it != store_.end()) {
|
||||
Placer p(bin);
|
||||
@ -72,7 +72,7 @@ public:
|
||||
while(!was_packed) {
|
||||
|
||||
for(size_t j = 0; j < placers.size() && !was_packed; j++) {
|
||||
if(was_packed = placers[j].pack(item))
|
||||
if((was_packed = placers[j].pack(item)))
|
||||
makeProgress(placers[j], j);
|
||||
}
|
||||
|
||||
|
@ -103,6 +103,10 @@ public:
|
||||
bool contains(const BoundingBox3Base<PointClass>& other) const {
|
||||
return contains(other.min) && contains(other.max);
|
||||
}
|
||||
|
||||
bool intersects(const BoundingBox3Base<PointClass>& other) const {
|
||||
return (this->min.x < other.max.x) && (this->max.x > other.min.x) && (this->min.y < other.max.y) && (this->max.y > other.min.y) && (this->min.z < other.max.z) && (this->max.z > other.min.z);
|
||||
}
|
||||
};
|
||||
|
||||
class BoundingBox : public BoundingBoxBase<Point>
|
||||
|
@ -1989,7 +1989,7 @@ namespace Slic3r {
|
||||
|
||||
// stores object's name
|
||||
if (!obj->name.empty())
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << obj->name << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << xml_escape(obj->name) << "\"/>\n";
|
||||
|
||||
// stores object's config data
|
||||
for (const std::string& key : obj->config.keys())
|
||||
@ -2012,7 +2012,7 @@ namespace Slic3r {
|
||||
|
||||
// stores volume's name
|
||||
if (!volume->name.empty())
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << volume->name << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n";
|
||||
|
||||
// stores volume's modifier field
|
||||
if (volume->modifier)
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "../libslic3r.h"
|
||||
#include "../Model.hpp"
|
||||
#include "../GCode.hpp"
|
||||
#include "../Utils.hpp"
|
||||
#include "../slic3r/GUI/PresetBundle.hpp"
|
||||
#include "AMF.hpp"
|
||||
|
||||
@ -686,33 +687,6 @@ bool load_amf(const char *path, PresetBundle* bundle, Model *model)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string xml_escape(std::string text)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
for (;;)
|
||||
{
|
||||
pos = text.find_first_of("\"\'&<>", pos);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
|
||||
std::string replacement;
|
||||
switch (text[pos])
|
||||
{
|
||||
case '\"': replacement = """; break;
|
||||
case '\'': replacement = "'"; break;
|
||||
case '&': replacement = "&"; break;
|
||||
case '<': replacement = "<"; break;
|
||||
case '>': replacement = ">"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
text.replace(pos, 1, replacement);
|
||||
pos += replacement.size();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
bool store_amf(const char *path, Model *model, Print* print, bool export_print_config)
|
||||
{
|
||||
if ((path == nullptr) || (model == nullptr) || (print == nullptr))
|
||||
@ -761,7 +735,7 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
|
||||
for (const std::string &key : object->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << object->config.serialize(key) << "</metadata>\n";
|
||||
if (!object->name.empty())
|
||||
stream << " <metadata type=\"name\">" << object->name << "</metadata>\n";
|
||||
stream << " <metadata type=\"name\">" << xml_escape(object->name) << "</metadata>\n";
|
||||
std::vector<double> layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector<double>();
|
||||
if (layer_height_profile.size() >= 4 && (layer_height_profile.size() % 2) == 0) {
|
||||
// Store the layer height profile as a single semicolon separated list.
|
||||
@ -805,7 +779,7 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
|
||||
for (const std::string &key : volume->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << volume->config.serialize(key) << "</metadata>\n";
|
||||
if (!volume->name.empty())
|
||||
stream << " <metadata type=\"name\">" << volume->name << "</metadata>\n";
|
||||
stream << " <metadata type=\"name\">" << xml_escape(volume->name) << "</metadata>\n";
|
||||
if (volume->modifier)
|
||||
stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n";
|
||||
for (int i = 0; i < volume->mesh.stl.stats.number_of_facets; ++i) {
|
||||
|
@ -309,10 +309,12 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
||||
size_t object_idx;
|
||||
size_t layer_idx;
|
||||
};
|
||||
std::vector<std::vector<LayerToPrint>> per_object(print.objects.size(), std::vector<LayerToPrint>());
|
||||
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
std::vector<std::vector<LayerToPrint>> per_object(printable_objects.size(), std::vector<LayerToPrint>());
|
||||
std::vector<OrderingItem> ordering;
|
||||
for (size_t i = 0; i < print.objects.size(); ++ i) {
|
||||
per_object[i] = collect_layers_to_print(*print.objects[i]);
|
||||
for (size_t i = 0; i < printable_objects.size(); ++i) {
|
||||
per_object[i] = collect_layers_to_print(*printable_objects[i]);
|
||||
OrderingItem ordering_item;
|
||||
ordering_item.object_idx = i;
|
||||
ordering.reserve(ordering.size() + per_object[i].size());
|
||||
@ -337,8 +339,8 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
||||
std::pair<coordf_t, std::vector<LayerToPrint>> merged;
|
||||
// Assign an average print_z to the set of layers with nearly equal print_z.
|
||||
merged.first = 0.5 * (ordering[i].print_z + ordering[j-1].print_z);
|
||||
merged.second.assign(print.objects.size(), LayerToPrint());
|
||||
for (; i < j; ++ i) {
|
||||
merged.second.assign(printable_objects.size(), LayerToPrint());
|
||||
for (; i < j; ++i) {
|
||||
const OrderingItem &oi = ordering[i];
|
||||
assert(merged.second[oi.object_idx].layer() == nullptr);
|
||||
merged.second[oi.object_idx] = std::move(per_object[oi.object_idx][oi.layer_idx]);
|
||||
@ -375,10 +377,13 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
if (print->config.gcode_flavor.value == gcfMarlin)
|
||||
{
|
||||
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
}
|
||||
|
||||
if (! this->m_placeholder_parser_failed_templates.empty()) {
|
||||
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
|
||||
@ -412,45 +417,54 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
// resets time estimators
|
||||
m_normal_time_estimator.reset();
|
||||
m_normal_time_estimator.set_dialect(print.config.gcode_flavor);
|
||||
m_normal_time_estimator.set_acceleration(print.config.machine_max_acceleration_extruding.values[0]);
|
||||
m_normal_time_estimator.set_retract_acceleration(print.config.machine_max_acceleration_retracting.values[0]);
|
||||
m_normal_time_estimator.set_minimum_feedrate(print.config.machine_min_extruding_rate.values[0]);
|
||||
m_normal_time_estimator.set_minimum_travel_feedrate(print.config.machine_min_travel_rate.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config.machine_max_acceleration_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config.machine_max_acceleration_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config.machine_max_acceleration_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config.machine_max_acceleration_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config.machine_max_feedrate_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config.machine_max_feedrate_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config.machine_max_feedrate_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config.machine_max_feedrate_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config.machine_max_jerk_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[0]);
|
||||
m_silent_time_estimator_enabled = (print.config.gcode_flavor == gcfMarlin) && print.config.silent_mode;
|
||||
|
||||
m_silent_time_estimator_enabled = (print.config.gcode_flavor == gcfMarlin) && print.config.silent_mode && boost::starts_with(print.config.printer_model.value, "MK3");
|
||||
if (m_silent_time_estimator_enabled)
|
||||
{
|
||||
m_silent_time_estimator.reset();
|
||||
m_silent_time_estimator.set_dialect(print.config.gcode_flavor);
|
||||
m_silent_time_estimator.set_acceleration(print.config.machine_max_acceleration_extruding.values[1]);
|
||||
m_silent_time_estimator.set_retract_acceleration(print.config.machine_max_acceleration_retracting.values[1]);
|
||||
m_silent_time_estimator.set_minimum_feedrate(print.config.machine_min_extruding_rate.values[1]);
|
||||
m_silent_time_estimator.set_minimum_travel_feedrate(print.config.machine_min_travel_rate.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config.machine_max_acceleration_x.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config.machine_max_acceleration_y.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config.machine_max_acceleration_z.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config.machine_max_acceleration_e.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config.machine_max_feedrate_x.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config.machine_max_feedrate_y.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config.machine_max_feedrate_z.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config.machine_max_feedrate_e.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config.machine_max_jerk_x.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[1]);
|
||||
// Until we have a UI support for the other firmwares than the Marlin, use the hardcoded default values
|
||||
// and let the user to enter the G-code limits into the start G-code.
|
||||
// If the following block is enabled for other firmwares than the Marlin, then the function
|
||||
// this->print_machine_envelope(file, print);
|
||||
// shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
|
||||
if (print.config.gcode_flavor.value == gcfMarlin) {
|
||||
m_normal_time_estimator.set_max_acceleration(print.config.machine_max_acceleration_extruding.values[0]);
|
||||
m_normal_time_estimator.set_retract_acceleration(print.config.machine_max_acceleration_retracting.values[0]);
|
||||
m_normal_time_estimator.set_minimum_feedrate(print.config.machine_min_extruding_rate.values[0]);
|
||||
m_normal_time_estimator.set_minimum_travel_feedrate(print.config.machine_min_travel_rate.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config.machine_max_acceleration_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config.machine_max_acceleration_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config.machine_max_acceleration_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config.machine_max_acceleration_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config.machine_max_feedrate_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config.machine_max_feedrate_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config.machine_max_feedrate_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config.machine_max_feedrate_e.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config.machine_max_jerk_x.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[0]);
|
||||
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[0]);
|
||||
|
||||
if (m_silent_time_estimator_enabled)
|
||||
{
|
||||
m_silent_time_estimator.reset();
|
||||
m_silent_time_estimator.set_dialect(print.config.gcode_flavor);
|
||||
m_silent_time_estimator.set_max_acceleration(print.config.machine_max_acceleration_extruding.values[1]);
|
||||
m_silent_time_estimator.set_retract_acceleration(print.config.machine_max_acceleration_retracting.values[1]);
|
||||
m_silent_time_estimator.set_minimum_feedrate(print.config.machine_min_extruding_rate.values[1]);
|
||||
m_silent_time_estimator.set_minimum_travel_feedrate(print.config.machine_min_travel_rate.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config.machine_max_acceleration_x.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config.machine_max_acceleration_y.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config.machine_max_acceleration_z.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config.machine_max_acceleration_e.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config.machine_max_feedrate_x.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config.machine_max_feedrate_y.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config.machine_max_feedrate_z.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config.machine_max_feedrate_e.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config.machine_max_jerk_x.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// resets analyzer
|
||||
m_analyzer.reset();
|
||||
m_enable_analyzer = preview_data != nullptr;
|
||||
@ -463,9 +477,10 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
// How many times will be change_layer() called?
|
||||
// change_layer() in turn increments the progress bar status.
|
||||
m_layer_count = 0;
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
if (print.config.complete_objects.value) {
|
||||
// Add each of the object's layers separately.
|
||||
for (auto object : print.objects) {
|
||||
for (auto object : printable_objects) {
|
||||
std::vector<coordf_t> zs;
|
||||
zs.reserve(object->layers.size() + object->support_layers.size());
|
||||
for (auto layer : object->layers)
|
||||
@ -478,7 +493,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
} else {
|
||||
// Print all objects with the same print_z together.
|
||||
std::vector<coordf_t> zs;
|
||||
for (auto object : print.objects) {
|
||||
for (auto object : printable_objects) {
|
||||
zs.reserve(zs.size() + object->layers.size() + object->support_layers.size());
|
||||
for (auto layer : object->layers)
|
||||
zs.push_back(layer->print_z);
|
||||
@ -497,8 +512,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
{
|
||||
// get the minimum cross-section used in the print
|
||||
std::vector<double> mm3_per_mm;
|
||||
for (auto object : print.objects) {
|
||||
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) {
|
||||
for (auto object : printable_objects) {
|
||||
for (size_t region_id = 0; region_id < print.regions.size(); ++region_id) {
|
||||
auto region = print.regions[region_id];
|
||||
for (auto layer : object->layers) {
|
||||
auto layerm = layer->regions[region_id];
|
||||
@ -558,7 +573,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
_write(file, "\n");
|
||||
}
|
||||
// Write some terse information on the slicing parameters.
|
||||
const PrintObject *first_object = print.objects.front();
|
||||
const PrintObject *first_object = printable_objects.front();
|
||||
const double layer_height = first_object->config.layer_height.value;
|
||||
const double first_layer_height = first_object->config.first_layer_height.get_abs_value(layer_height);
|
||||
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) {
|
||||
@ -587,13 +602,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
size_t initial_print_object_id = 0;
|
||||
bool has_wipe_tower = false;
|
||||
if (print.config.complete_objects.value) {
|
||||
// Find the 1st printing object, find its tool ordering and the initial extruder ID.
|
||||
for (; initial_print_object_id < print.objects.size(); ++initial_print_object_id) {
|
||||
tool_ordering = ToolOrdering(*print.objects[initial_print_object_id], initial_extruder_id);
|
||||
if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Find the 1st printing object, find its tool ordering and the initial extruder ID.
|
||||
for (; initial_print_object_id < printable_objects.size(); ++initial_print_object_id) {
|
||||
tool_ordering = ToolOrdering(*printable_objects[initial_print_object_id], initial_extruder_id);
|
||||
if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Find tool ordering for all the objects at once, and the initial extruder ID.
|
||||
// If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it.
|
||||
tool_ordering = print.m_tool_ordering.empty() ?
|
||||
@ -667,7 +683,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
// Collect outer contours of all objects over all layers.
|
||||
// Discard objects only containing thin walls (offset would fail on an empty polygon).
|
||||
Polygons islands;
|
||||
for (const PrintObject *object : print.objects)
|
||||
for (const PrintObject *object : printable_objects)
|
||||
for (const Layer *layer : object->layers)
|
||||
for (const ExPolygon &expoly : layer->slices.expolygons)
|
||||
for (const Point © : object->_shifted_copies) {
|
||||
@ -715,7 +731,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
if (print.config.complete_objects.value) {
|
||||
// Print objects from the smallest to the tallest to avoid collisions
|
||||
// when moving onto next object starting point.
|
||||
std::vector<PrintObject*> objects(print.objects);
|
||||
std::vector<PrintObject*> objects(printable_objects);
|
||||
std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; });
|
||||
size_t finished_objects = 0;
|
||||
for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) {
|
||||
@ -776,7 +792,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
// Order objects using a nearest neighbor search.
|
||||
std::vector<size_t> object_indices;
|
||||
Points object_reference_points;
|
||||
for (PrintObject *object : print.objects)
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
for (PrintObject *object : printable_objects)
|
||||
object_reference_points.push_back(object->_shifted_copies.front());
|
||||
Slic3r::Geometry::chained_path(object_reference_points, object_indices);
|
||||
// Sort layers by Z.
|
||||
@ -790,7 +807,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
// Verify, whether the print overaps the priming extrusions.
|
||||
BoundingBoxf bbox_print(get_print_extrusions_extents(print));
|
||||
coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON;
|
||||
for (const PrintObject *print_object : print.objects)
|
||||
for (const PrintObject *print_object : printable_objects)
|
||||
bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz));
|
||||
bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz));
|
||||
BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print));
|
||||
@ -853,9 +870,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
_write(file, m_writer.postamble());
|
||||
|
||||
// calculates estimated printing time
|
||||
m_normal_time_estimator.calculate_time();
|
||||
m_normal_time_estimator.calculate_time(false);
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.calculate_time();
|
||||
m_silent_time_estimator.calculate_time(false);
|
||||
|
||||
// Get filament stats.
|
||||
print.filament_stats.clear();
|
||||
|
@ -67,11 +67,13 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
|
||||
ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material)
|
||||
{
|
||||
m_print_config_ptr = &print.config;
|
||||
|
||||
PrintObjectPtrs objects = print.get_printable_objects();
|
||||
// Initialize the print layers for all objects and all layers.
|
||||
coordf_t object_bottom_z = 0.;
|
||||
{
|
||||
std::vector<coordf_t> zs;
|
||||
for (auto object : print.objects) {
|
||||
for (auto object : objects) {
|
||||
zs.reserve(zs.size() + object->layers.size() + object->support_layers.size());
|
||||
for (auto layer : object->layers)
|
||||
zs.emplace_back(layer->print_z);
|
||||
@ -84,7 +86,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
||||
}
|
||||
|
||||
// Collect extruders reuqired to print the layers.
|
||||
for (auto object : print.objects)
|
||||
for (auto object : objects)
|
||||
this->collect_extruders(*object);
|
||||
|
||||
// Reorder the extruders to minimize tool switches.
|
||||
@ -440,19 +442,18 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con
|
||||
|
||||
// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange
|
||||
// and returns volume that is left to be wiped on the wipe tower.
|
||||
float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int new_extruder, float volume_to_wipe)
|
||||
float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe)
|
||||
{
|
||||
const LayerTools& lt = *m_layer_tools;
|
||||
const float min_infill_volume = 0.f; // ignore infill with smaller volume than this
|
||||
|
||||
if (print.config.filament_soluble.get_at(new_extruder))
|
||||
return volume_to_wipe; // Soluble filament cannot be wiped in a random infill
|
||||
if (print.config.filament_soluble.get_at(old_extruder) || print.config.filament_soluble.get_at(new_extruder))
|
||||
return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it
|
||||
|
||||
// we will sort objects so that dedicated for wiping are at the beginning:
|
||||
PrintObjectPtrs object_list = print.objects;
|
||||
PrintObjectPtrs object_list = print.get_printable_objects();
|
||||
std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config.wipe_into_objects; });
|
||||
|
||||
|
||||
// We will now iterate through
|
||||
// - first the dedicated objects to mark perimeters or infills (depending on infill_first)
|
||||
// - second through the dedicated ones again to mark infills or perimeters (depending on infill_first)
|
||||
@ -546,7 +547,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config);
|
||||
unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config);
|
||||
|
||||
for (const PrintObject* object : print.objects) {
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
for (const PrintObject* object : printable_objects) {
|
||||
// Finds this layer:
|
||||
auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
|
||||
if (this_layer_it == object->layers.end())
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
|
||||
// This function goes through all infill entities, decides which ones will be used for wiping and
|
||||
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
|
||||
float mark_wiping_extrusions(const Print& print, unsigned int new_extruder, float volume_to_wipe);
|
||||
float mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe);
|
||||
|
||||
void ensure_perimeters_infills_order(const Print& print);
|
||||
|
||||
@ -66,8 +66,10 @@ public:
|
||||
wipe_tower_partitions(0),
|
||||
wipe_tower_layer_height(0.) {}
|
||||
|
||||
bool operator< (const LayerTools &rhs) const { return print_z - EPSILON < rhs.print_z; }
|
||||
bool operator==(const LayerTools &rhs) const { return std::abs(print_z - rhs.print_z) < EPSILON; }
|
||||
// Changing these operators to epsilon version can make a problem in cases where support and object layers get close to each other.
|
||||
// In case someone tries to do it, make sure you know what you're doing and test it properly (slice multiple objects at once with supports).
|
||||
bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; }
|
||||
bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; }
|
||||
|
||||
bool is_extruder_order(unsigned int a, unsigned int b) const;
|
||||
|
||||
|
@ -490,7 +490,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
|
||||
// box_coordinates cleaning_box(xy(0.5f, - 1.5f), m_wipe_tower_width, wipe_area);
|
||||
|
||||
const float prime_section_width = std::min(240.f / tools.size(), 60.f);
|
||||
box_coordinates cleaning_box(xy(5.f, 0.f), prime_section_width, 100.f);
|
||||
box_coordinates cleaning_box(xy(5.f, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f);
|
||||
|
||||
PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width);
|
||||
writer.set_extrusion_flow(m_extrusion_flow)
|
||||
|
@ -79,7 +79,6 @@ namespace Slic3r {
|
||||
}
|
||||
|
||||
GCodeTimeEstimator::Block::Block()
|
||||
: st_synchronized(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -196,11 +195,14 @@ namespace Slic3r {
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::calculate_time()
|
||||
void GCodeTimeEstimator::calculate_time(bool start_from_beginning)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_reset_time();
|
||||
_set_blocks_st_synchronize(false);
|
||||
if (start_from_beginning)
|
||||
{
|
||||
_reset_time();
|
||||
_last_st_synchronized_block_id = -1;
|
||||
}
|
||||
_calculate_time();
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
@ -414,7 +416,10 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::set_acceleration(float acceleration_mm_sec2)
|
||||
{
|
||||
_state.acceleration = acceleration_mm_sec2;
|
||||
_state.acceleration = (_state.max_acceleration == 0) ?
|
||||
acceleration_mm_sec2 :
|
||||
// Clamp the acceleration with the maximum.
|
||||
std::min(_state.max_acceleration, acceleration_mm_sec2);
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::get_acceleration() const
|
||||
@ -422,6 +427,18 @@ namespace Slic3r {
|
||||
return _state.acceleration;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_max_acceleration(float acceleration_mm_sec2)
|
||||
{
|
||||
_state.max_acceleration = acceleration_mm_sec2;
|
||||
if (acceleration_mm_sec2 > 0)
|
||||
_state.acceleration = acceleration_mm_sec2;
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::get_max_acceleration() const
|
||||
{
|
||||
return _state.max_acceleration;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_retract_acceleration(float acceleration_mm_sec2)
|
||||
{
|
||||
_state.retract_acceleration = acceleration_mm_sec2;
|
||||
@ -469,6 +486,7 @@ namespace Slic3r {
|
||||
|
||||
GCodeFlavor GCodeTimeEstimator::get_dialect() const
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
return _state.dialect;
|
||||
}
|
||||
|
||||
@ -519,6 +537,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::add_additional_time(float timeSec)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_state.additional_time += timeSec;
|
||||
}
|
||||
|
||||
@ -540,6 +559,9 @@ namespace Slic3r {
|
||||
set_e_local_positioning_type(Absolute);
|
||||
|
||||
set_feedrate(DEFAULT_FEEDRATE);
|
||||
// Setting the maximum acceleration to zero means that the there is no limit and the G-code
|
||||
// is allowed to set excessive values.
|
||||
set_max_acceleration(0);
|
||||
set_acceleration(DEFAULT_ACCELERATION);
|
||||
set_retract_acceleration(DEFAULT_RETRACT_ACCELERATION);
|
||||
set_minimum_feedrate(DEFAULT_MINIMUM_FEEDRATE);
|
||||
@ -593,6 +615,8 @@ namespace Slic3r {
|
||||
|
||||
reset_g1_line_id();
|
||||
_g1_line_ids.clear();
|
||||
|
||||
_last_st_synchronized_block_id = -1;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_reset_time()
|
||||
@ -605,26 +629,19 @@ namespace Slic3r {
|
||||
_blocks.clear();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_set_blocks_st_synchronize(bool state)
|
||||
{
|
||||
for (Block& block : _blocks)
|
||||
{
|
||||
block.st_synchronized = state;
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_calculate_time()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_forward_pass();
|
||||
_reverse_pass();
|
||||
_recalculate_trapezoids();
|
||||
|
||||
_time += get_additional_time();
|
||||
|
||||
for (Block& block : _blocks)
|
||||
for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size(); ++i)
|
||||
{
|
||||
if (block.st_synchronized)
|
||||
continue;
|
||||
Block& block = _blocks[i];
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
float block_time = 0.0f;
|
||||
@ -647,6 +664,8 @@ namespace Slic3r {
|
||||
block.elapsed_time = _time;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
_last_st_synchronized_block_id = _blocks.size() - 1;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line)
|
||||
@ -782,6 +801,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processG1(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
increment_g1_line_id();
|
||||
|
||||
// updates axes positions from line
|
||||
@ -979,6 +999,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
GCodeFlavor dialect = get_dialect();
|
||||
|
||||
float value;
|
||||
@ -1000,31 +1021,37 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_units(Inches);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG21(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_units(Millimeters);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG28(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG90(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_global_positioning_type(Absolute);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG91(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_global_positioning_type(Relative);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG92(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
float lengthsScaleFactor = (get_units() == Inches) ? INCHES_TO_MM : 1.0f;
|
||||
bool anyFound = false;
|
||||
|
||||
@ -1065,26 +1092,31 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processM1(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_simulate_st_synchronize();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_e_local_positioning_type(Absolute);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM83(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_e_local_positioning_type(Relative);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM109(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM201(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
GCodeFlavor dialect = get_dialect();
|
||||
|
||||
// see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
|
||||
@ -1105,6 +1137,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processM203(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
GCodeFlavor dialect = get_dialect();
|
||||
|
||||
// see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
|
||||
@ -1129,6 +1162,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processM204(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
float value;
|
||||
if (line.has_value('S', value))
|
||||
set_acceleration(value);
|
||||
@ -1139,6 +1173,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processM205(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (line.has_x())
|
||||
{
|
||||
float max_jerk = line.x();
|
||||
@ -1165,6 +1200,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processM221(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
float value_s;
|
||||
float value_t;
|
||||
if (line.has_value('S', value_s) && !line.has_value('T', value_t))
|
||||
@ -1173,6 +1209,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processM566(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (line.has_x())
|
||||
set_axis_max_jerk(X, line.x() * MMMIN_TO_MMSEC);
|
||||
|
||||
@ -1188,19 +1225,17 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_simulate_st_synchronize()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_calculate_time();
|
||||
_set_blocks_st_synchronize(true);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_forward_pass()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (_blocks.size() > 1)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)_blocks.size() - 1; ++i)
|
||||
{
|
||||
if (_blocks[i].st_synchronized || _blocks[i + 1].st_synchronized)
|
||||
continue;
|
||||
|
||||
for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size() - 1; ++i)
|
||||
{
|
||||
_planner_forward_pass_kernel(_blocks[i], _blocks[i + 1]);
|
||||
}
|
||||
}
|
||||
@ -1208,13 +1243,11 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_reverse_pass()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (_blocks.size() > 1)
|
||||
{
|
||||
for (int i = (int)_blocks.size() - 1; i >= 1; --i)
|
||||
for (int i = (int)_blocks.size() - 1; i >= _last_st_synchronized_block_id + 2; --i)
|
||||
{
|
||||
if (_blocks[i - 1].st_synchronized || _blocks[i].st_synchronized)
|
||||
continue;
|
||||
|
||||
_planner_reverse_pass_kernel(_blocks[i - 1], _blocks[i]);
|
||||
}
|
||||
}
|
||||
@ -1222,6 +1255,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_planner_forward_pass_kernel(Block& prev, Block& curr)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
// If the previous block is an acceleration block, but it is not long enough to complete the
|
||||
// full speed change within the block, we need to adjust the entry speed accordingly. Entry
|
||||
// speeds have already been reset, maximized, and reverse planned by reverse planner.
|
||||
@ -1262,13 +1296,13 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_recalculate_trapezoids()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
Block* curr = nullptr;
|
||||
Block* next = nullptr;
|
||||
|
||||
for (Block& b : _blocks)
|
||||
for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size(); ++i)
|
||||
{
|
||||
if (b.st_synchronized)
|
||||
continue;
|
||||
Block& b = _blocks[i];
|
||||
|
||||
curr = next;
|
||||
next = &b;
|
||||
|
@ -72,6 +72,8 @@ namespace Slic3r {
|
||||
Axis axis[Num_Axis];
|
||||
float feedrate; // mm/s
|
||||
float acceleration; // mm/s^2
|
||||
// hard limit for the acceleration, to which the firmware will clamp.
|
||||
float max_acceleration; // mm/s^2
|
||||
float retract_acceleration; // mm/s^2
|
||||
float additional_time; // s
|
||||
float minimum_feedrate; // mm/s
|
||||
@ -142,8 +144,6 @@ namespace Slic3r {
|
||||
Trapezoid trapezoid;
|
||||
float elapsed_time;
|
||||
|
||||
bool st_synchronized;
|
||||
|
||||
Block();
|
||||
|
||||
// Returns the length of the move covered by this block, in mm
|
||||
@ -209,6 +209,8 @@ namespace Slic3r {
|
||||
BlocksList _blocks;
|
||||
// Map between g1 line id and blocks id, used to speed up export of remaining times
|
||||
G1LineIdToBlockIdMap _g1_line_ids;
|
||||
// Index of the last block already st_synchronized
|
||||
int _last_st_synchronized_block_id;
|
||||
float _time; // s
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
@ -225,7 +227,10 @@ namespace Slic3r {
|
||||
void add_gcode_block(const std::string &str) { this->add_gcode_block(str.c_str()); }
|
||||
|
||||
// Calculates the time estimate from the gcode lines added using add_gcode_line() or add_gcode_block()
|
||||
void calculate_time();
|
||||
// start_from_beginning:
|
||||
// if set to true all blocks will be used to calculate the time estimate,
|
||||
// if set to false only the blocks not yet processed will be used and the calculated time will be added to the current calculated time
|
||||
void calculate_time(bool start_from_beginning);
|
||||
|
||||
// Calculates the time estimate from the given gcode in string format
|
||||
void calculate_time_from_text(const std::string& gcode);
|
||||
@ -263,6 +268,10 @@ namespace Slic3r {
|
||||
void set_acceleration(float acceleration_mm_sec2);
|
||||
float get_acceleration() const;
|
||||
|
||||
// Maximum acceleration for the machine. The firmware simulator will clamp the M204 Sxxx to this maximum.
|
||||
void set_max_acceleration(float acceleration_mm_sec2);
|
||||
float get_max_acceleration() const;
|
||||
|
||||
void set_retract_acceleration(float acceleration_mm_sec2);
|
||||
float get_retract_acceleration() const;
|
||||
|
||||
@ -314,8 +323,6 @@ namespace Slic3r {
|
||||
void _reset_time();
|
||||
void _reset_blocks();
|
||||
|
||||
void _set_blocks_st_synchronize(bool state);
|
||||
|
||||
// Calculates the time estimate
|
||||
void _calculate_time();
|
||||
|
||||
|
@ -18,7 +18,9 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
{
|
||||
this->config.apply(print_config, true);
|
||||
m_extrusion_axis = this->config.get_extrusion_axis();
|
||||
this->m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
|
||||
m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
|
||||
m_max_acceleration = (print_config.gcode_flavor.value == gcfMarlin) ?
|
||||
print_config.machine_max_acceleration_extruding.values.front() : 0;
|
||||
}
|
||||
|
||||
void GCodeWriter::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
||||
@ -85,7 +87,7 @@ std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, in
|
||||
}
|
||||
gcode << temperature;
|
||||
if (tool != -1 &&
|
||||
( (this->multiple_extruders && ! this->m_single_extruder_multi_material) ||
|
||||
( (this->multiple_extruders && ! m_single_extruder_multi_material) ||
|
||||
FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) ) {
|
||||
gcode << " T" << tool;
|
||||
}
|
||||
@ -170,6 +172,10 @@ std::string GCodeWriter::set_fan(unsigned int speed, bool dont_save)
|
||||
|
||||
std::string GCodeWriter::set_acceleration(unsigned int acceleration)
|
||||
{
|
||||
// Clamp the acceleration to the allowed maximum.
|
||||
if (m_max_acceleration > 0 && acceleration > m_max_acceleration)
|
||||
acceleration = m_max_acceleration;
|
||||
|
||||
if (acceleration == 0 || acceleration == m_last_acceleration)
|
||||
return std::string();
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
GCodeWriter() :
|
||||
multiple_extruders(false), m_extrusion_axis("E"), m_extruder(nullptr),
|
||||
m_single_extruder_multi_material(false),
|
||||
m_last_acceleration(0), m_last_fan_speed(0),
|
||||
m_last_acceleration(0), m_max_acceleration(0), m_last_fan_speed(0),
|
||||
m_last_bed_temperature(0), m_last_bed_temperature_reached(true),
|
||||
m_lifted(0)
|
||||
{}
|
||||
@ -74,6 +74,9 @@ private:
|
||||
bool m_single_extruder_multi_material;
|
||||
Extruder* m_extruder;
|
||||
unsigned int m_last_acceleration;
|
||||
// Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware.
|
||||
// If set to zero, the limit is not in action.
|
||||
unsigned int m_max_acceleration;
|
||||
unsigned int m_last_fan_speed;
|
||||
unsigned int m_last_bed_temperature;
|
||||
bool m_last_bed_temperature_reached;
|
||||
|
@ -530,12 +530,12 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
||||
// arranger.useMinimumBoundigBoxRotation();
|
||||
pcfg.rotations = { 0.0 };
|
||||
|
||||
// Magic: we will specify what is the goal of arrangement...
|
||||
// In this case we override the default object to make the larger items go
|
||||
// into the center of the pile and smaller items orbit it so the resulting
|
||||
// pile has a circle-like shape. This is good for the print bed's heat
|
||||
// profile. We alse sacrafice a bit of pack efficiency for this to work. As
|
||||
// a side effect, the arrange procedure is a lot faster (we do not need to
|
||||
// Magic: we will specify what is the goal of arrangement... In this case
|
||||
// we override the default object function to make the larger items go into
|
||||
// the center of the pile and smaller items orbit it so the resulting pile
|
||||
// has a circle-like shape. This is good for the print bed's heat profile.
|
||||
// We alse sacrafice a bit of pack efficiency for this to work. As a side
|
||||
// effect, the arrange procedure is a lot faster (we do not need to
|
||||
// calculate the convex hulls)
|
||||
pcfg.object_function = [bin, hasbin](
|
||||
NfpPlacer::Pile pile, // The currently arranged pile
|
||||
@ -1235,6 +1235,59 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||
return;
|
||||
}
|
||||
|
||||
void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
|
||||
{
|
||||
for (ModelVolume* vol : this->volumes)
|
||||
{
|
||||
if (!vol->modifier)
|
||||
{
|
||||
for (ModelInstance* inst : this->instances)
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
|
||||
double c = cos(inst->rotation);
|
||||
double s = sin(inst->rotation);
|
||||
|
||||
for (int f = 0; f < vol->mesh.stl.stats.number_of_facets; ++f)
|
||||
{
|
||||
const stl_facet& facet = vol->mesh.stl.facet_start[f];
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
// original point
|
||||
const stl_vertex& v = facet.vertex[i];
|
||||
Pointf3 p((double)v.x, (double)v.y, (double)v.z);
|
||||
|
||||
// scale
|
||||
p.x *= inst->scaling_factor;
|
||||
p.y *= inst->scaling_factor;
|
||||
p.z *= inst->scaling_factor;
|
||||
|
||||
// rotate Z
|
||||
double x = p.x;
|
||||
double y = p.y;
|
||||
p.x = c * x - s * y;
|
||||
p.y = s * x + c * y;
|
||||
|
||||
// translate
|
||||
p.x += inst->offset.x;
|
||||
p.y += inst->offset.y;
|
||||
|
||||
bb.merge(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (print_volume.contains(bb))
|
||||
inst->print_volume_state = ModelInstance::PVS_Inside;
|
||||
else if (print_volume.intersects(bb))
|
||||
inst->print_volume_state = ModelInstance::PVS_Partly_Outside;
|
||||
else
|
||||
inst->print_volume_state = ModelInstance::PVS_Fully_Outside;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelObject::print_info() const
|
||||
{
|
||||
using namespace std;
|
||||
|
@ -132,6 +132,8 @@ public:
|
||||
void cut(coordf_t z, Model* model) const;
|
||||
void split(ModelObjectPtrs* new_objects);
|
||||
|
||||
void check_instances_print_volume_state(const BoundingBoxf3& print_volume);
|
||||
|
||||
// Print object statistics to console.
|
||||
void print_info() const;
|
||||
|
||||
@ -197,12 +199,24 @@ private:
|
||||
// Knows the affine transformation of an object.
|
||||
class ModelInstance
|
||||
{
|
||||
friend class ModelObject;
|
||||
public:
|
||||
enum EPrintVolumeState : unsigned char
|
||||
{
|
||||
PVS_Inside,
|
||||
PVS_Partly_Outside,
|
||||
PVS_Fully_Outside,
|
||||
Num_BedStates
|
||||
};
|
||||
|
||||
friend class ModelObject;
|
||||
|
||||
double rotation; // Rotation around the Z axis, in radians around mesh center point
|
||||
double scaling_factor;
|
||||
Pointf offset; // in unscaled coordinates
|
||||
|
||||
// flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
|
||||
EPrintVolumeState print_volume_state;
|
||||
|
||||
ModelObject* get_object() const { return this->object; }
|
||||
|
||||
// To be called on an external mesh
|
||||
@ -213,14 +227,16 @@ public:
|
||||
BoundingBoxf3 transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate = false) const;
|
||||
// To be called on an external polygon. It does not translate the polygon, only rotates and scales.
|
||||
void transform_polygon(Polygon* polygon) const;
|
||||
|
||||
|
||||
bool is_printable() const { return print_volume_state == PVS_Inside; }
|
||||
|
||||
private:
|
||||
// Parent object, owning this instance.
|
||||
ModelObject* object;
|
||||
|
||||
ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object) {}
|
||||
ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object), print_volume_state(PVS_Inside) {}
|
||||
ModelInstance(ModelObject *object, const ModelInstance &other) :
|
||||
rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object) {}
|
||||
rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object), print_volume_state(PVS_Inside) {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -75,6 +75,13 @@ bool Print::reload_model_instances()
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
PrintObjectPtrs Print::get_printable_objects() const
|
||||
{
|
||||
PrintObjectPtrs printable_objects(this->objects);
|
||||
printable_objects.erase(std::remove_if(printable_objects.begin(), printable_objects.end(), [](PrintObject* o) { return !o->is_printable(); }), printable_objects.end());
|
||||
return printable_objects;
|
||||
}
|
||||
|
||||
PrintRegion* Print::add_region()
|
||||
{
|
||||
regions.push_back(new PrintRegion(this));
|
||||
@ -538,11 +545,17 @@ std::string Print::validate() const
|
||||
BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height));
|
||||
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
|
||||
print_volume.min.z = -1e10;
|
||||
unsigned int printable_count = 0;
|
||||
for (PrintObject *po : this->objects) {
|
||||
if (!print_volume.contains(po->model_object()->tight_bounding_box(false)))
|
||||
return L("Some objects are outside of the print volume.");
|
||||
po->model_object()->check_instances_print_volume_state(print_volume);
|
||||
po->reload_model_instances();
|
||||
if (po->is_printable())
|
||||
++printable_count;
|
||||
}
|
||||
|
||||
if (printable_count == 0)
|
||||
return L("All objects are outside of the print volume.");
|
||||
|
||||
if (this->config.complete_objects) {
|
||||
// Check horizontal clearance.
|
||||
{
|
||||
@ -862,8 +875,9 @@ void Print::_make_skirt()
|
||||
// prepended to the first 'n' layers (with 'n' = skirt_height).
|
||||
// $skirt_height_z in this case is the highest possible skirt height for safety.
|
||||
coordf_t skirt_height_z = 0.;
|
||||
for (const PrintObject *object : this->objects) {
|
||||
size_t skirt_layers = this->has_infinite_skirt() ?
|
||||
PrintObjectPtrs printable_objects = get_printable_objects();
|
||||
for (const PrintObject *object : printable_objects) {
|
||||
size_t skirt_layers = this->has_infinite_skirt() ?
|
||||
object->layer_count() :
|
||||
std::min(size_t(this->config.skirt_height.value), object->layer_count());
|
||||
skirt_height_z = std::max(skirt_height_z, object->layers[skirt_layers-1]->print_z);
|
||||
@ -871,7 +885,7 @@ void Print::_make_skirt()
|
||||
|
||||
// Collect points from all layers contained in skirt height.
|
||||
Points points;
|
||||
for (const PrintObject *object : this->objects) {
|
||||
for (const PrintObject *object : printable_objects) {
|
||||
Points object_points;
|
||||
// Get object layers up to skirt_height_z.
|
||||
for (const Layer *layer : object->layers) {
|
||||
@ -984,7 +998,8 @@ void Print::_make_brim()
|
||||
// Brim is only printed on first layer and uses perimeter extruder.
|
||||
Flow flow = this->brim_flow();
|
||||
Polygons islands;
|
||||
for (PrintObject *object : this->objects) {
|
||||
PrintObjectPtrs printable_objects = get_printable_objects();
|
||||
for (PrintObject *object : printable_objects) {
|
||||
Polygons object_islands;
|
||||
for (ExPolygon &expoly : object->layers.front()->slices.expolygons)
|
||||
object_islands.push_back(expoly.contour);
|
||||
@ -1136,7 +1151,7 @@ void Print::_make_wipe_tower()
|
||||
float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange
|
||||
|
||||
// try to assign some infills/objects for the wiping:
|
||||
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, extruder_id, wipe_volumes[current_extruder_id][extruder_id]);
|
||||
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, wipe_volumes[current_extruder_id][extruder_id]);
|
||||
|
||||
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe);
|
||||
current_extruder_id = extruder_id;
|
||||
|
@ -209,6 +209,8 @@ public:
|
||||
void combine_infill();
|
||||
void _generate_support_material();
|
||||
|
||||
bool is_printable() const { return !this->_shifted_copies.empty(); }
|
||||
|
||||
private:
|
||||
Print* _print;
|
||||
ModelObject* _model_object;
|
||||
@ -263,6 +265,8 @@ public:
|
||||
void reload_object(size_t idx);
|
||||
bool reload_model_instances();
|
||||
|
||||
PrintObjectPtrs get_printable_objects() const;
|
||||
|
||||
// methods for handling regions
|
||||
PrintRegion* get_region(size_t idx) { return regions.at(idx); }
|
||||
const PrintRegion* get_region(size_t idx) const { return regions.at(idx); }
|
||||
|
@ -83,8 +83,6 @@ template<> class FilePrinter<FilePrinterFormat::PNG> {
|
||||
std::stringstream second;
|
||||
|
||||
Layer() {}
|
||||
Layer(const Raster::Resolution& res, const Raster::PixelDim& pd):
|
||||
first(res, pd) {}
|
||||
|
||||
Layer(const Layer&) = delete;
|
||||
Layer(Layer&& m):
|
||||
@ -129,13 +127,17 @@ template<> class FilePrinter<FilePrinterFormat::PNG> {
|
||||
+layerh_str+"+printer=DWARF3\n";
|
||||
}
|
||||
|
||||
// Change this to TOP_LEFT if you want correct PNG orientation
|
||||
static const Raster::Origin ORIGIN = Raster::Origin::BOTTOM_LEFT;
|
||||
|
||||
public:
|
||||
inline FilePrinter(double width_mm, double height_mm,
|
||||
unsigned width_px, unsigned height_px,
|
||||
double exp_time, double exp_time_first):
|
||||
res_(width_px, height_px), exp_time_s_(exp_time),
|
||||
exp_time_first_s_(exp_time_first),
|
||||
pxdim_(width_mm/width_px, height_mm/height_px)
|
||||
res_(width_px, height_px),
|
||||
pxdim_(width_mm/width_px, height_mm/height_px),
|
||||
exp_time_s_(exp_time),
|
||||
exp_time_first_s_(exp_time_first)
|
||||
{
|
||||
}
|
||||
|
||||
@ -157,12 +159,12 @@ public:
|
||||
|
||||
inline void beginLayer(unsigned lyr) {
|
||||
if(layers_rst_.size() <= lyr) layers_rst_.resize(lyr+1);
|
||||
layers_rst_[lyr].first.reset(res_, pxdim_);
|
||||
layers_rst_[lyr].first.reset(res_, pxdim_, ORIGIN);
|
||||
}
|
||||
|
||||
inline void beginLayer() {
|
||||
layers_rst_.emplace_back();
|
||||
layers_rst_.front().first.reset(res_, pxdim_);
|
||||
layers_rst_.front().first.reset(res_, pxdim_, ORIGIN);
|
||||
}
|
||||
|
||||
inline void finishLayer(unsigned lyr_id) {
|
||||
@ -337,13 +339,13 @@ void print_to(Print& print,
|
||||
});
|
||||
});
|
||||
|
||||
if(print.has_support_material() && layer_id > 0) {
|
||||
/*if(print.has_support_material() && layer_id > 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "support material for layer "
|
||||
<< layer_id
|
||||
<< " defined but export is "
|
||||
"not yet implemented.";
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,10 @@ bool PrintObject::reload_model_instances()
|
||||
Points copies;
|
||||
copies.reserve(this->_model_object->instances.size());
|
||||
for (const ModelInstance *mi : this->_model_object->instances)
|
||||
copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y));
|
||||
{
|
||||
if (mi->is_printable())
|
||||
copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y));
|
||||
}
|
||||
return this->set_copies(copies);
|
||||
}
|
||||
|
||||
@ -291,6 +294,9 @@ bool PrintObject::has_support_material() const
|
||||
|
||||
void PrintObject::_prepare_infill()
|
||||
{
|
||||
if (!this->is_printable())
|
||||
return;
|
||||
|
||||
// This will assign a type (top/bottom/internal) to $layerm->slices.
|
||||
// Then the classifcation of $layerm->slices is transfered onto
|
||||
// the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
|
||||
@ -1177,8 +1183,8 @@ void PrintObject::_slice()
|
||||
|
||||
this->typed_slices = false;
|
||||
|
||||
#if 0
|
||||
// Disable parallelization for debugging purposes.
|
||||
#ifdef SLIC3R_PROFILE
|
||||
// Disable parallelization so the Shiny profiler works
|
||||
static tbb::task_scheduler_init *tbb_init = nullptr;
|
||||
tbb_init = new tbb::task_scheduler_init(1);
|
||||
#endif
|
||||
@ -1442,6 +1448,9 @@ void PrintObject::_simplify_slices(double distance)
|
||||
|
||||
void PrintObject::_make_perimeters()
|
||||
{
|
||||
if (!this->is_printable())
|
||||
return;
|
||||
|
||||
if (this->state.is_done(posPerimeters)) return;
|
||||
this->state.set_started(posPerimeters);
|
||||
|
||||
@ -1550,6 +1559,9 @@ void PrintObject::_make_perimeters()
|
||||
|
||||
void PrintObject::_infill()
|
||||
{
|
||||
if (!this->is_printable())
|
||||
return;
|
||||
|
||||
if (this->state.is_done(posInfill)) return;
|
||||
this->state.set_started(posInfill);
|
||||
|
||||
@ -1954,6 +1966,9 @@ void PrintObject::combine_infill()
|
||||
|
||||
void PrintObject::_generate_support_material()
|
||||
{
|
||||
if (!this->is_printable())
|
||||
return;
|
||||
|
||||
PrintObjectSupportMaterial support_material(this, PrintObject::slicing_parameters());
|
||||
support_material.generate(*this);
|
||||
}
|
||||
|
@ -45,9 +45,10 @@ private:
|
||||
TRawRenderer raw_renderer_;
|
||||
TRendererAA renderer_;
|
||||
Origin o_;
|
||||
std::function<void(agg::path_storage&)> flipy_ = [](agg::path_storage&) {};
|
||||
public:
|
||||
inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd,
|
||||
Origin o = Origin::TOP_LEFT):
|
||||
Origin o):
|
||||
resolution_(res), pxdim_(pd),
|
||||
buf_(res.pixels()),
|
||||
rbuf_(reinterpret_cast<TPixelRenderer::value_type*>(buf_.data()),
|
||||
@ -64,6 +65,10 @@ public:
|
||||
// ras.gamma(agg::gamma_power(1.0));
|
||||
|
||||
clear();
|
||||
|
||||
if(o_ == Origin::TOP_LEFT) flipy_ = [this](agg::path_storage& path) {
|
||||
path.flip_y(0, resolution_.height_px);
|
||||
};
|
||||
}
|
||||
|
||||
void draw(const ExPolygon &poly) {
|
||||
@ -71,13 +76,12 @@ public:
|
||||
agg::scanline_p8 scanlines;
|
||||
|
||||
auto&& path = to_path(poly.contour);
|
||||
if(o_ == Origin::TOP_LEFT) path.flip_y(0, resolution_.height_px);
|
||||
flipy_(path);
|
||||
ras.add_path(path);
|
||||
|
||||
for(auto h : poly.holes) {
|
||||
auto&& holepath = to_path(h);
|
||||
if(o_ == Origin::TOP_LEFT)
|
||||
holepath.flip_y(0, resolution_.height_px);
|
||||
flipy_(holepath);
|
||||
ras.add_path(holepath);
|
||||
}
|
||||
|
||||
@ -92,6 +96,8 @@ public:
|
||||
|
||||
inline const Raster::Resolution resolution() { return resolution_; }
|
||||
|
||||
inline Origin origin() const /*noexcept*/ { return o_; }
|
||||
|
||||
private:
|
||||
double getPx(const Point& p) {
|
||||
return p.x * SCALING_FACTOR/pxdim_.w_mm;
|
||||
@ -131,9 +137,15 @@ void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd)
|
||||
{
|
||||
// Free up the unneccessary memory and make sure it stays clear after
|
||||
// an exception
|
||||
impl_.reset();
|
||||
auto o = impl_? impl_->origin() : Origin::TOP_LEFT;
|
||||
reset(r, pd, o);
|
||||
}
|
||||
|
||||
impl_.reset(new Impl(r, pd));
|
||||
void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,
|
||||
Raster::Origin o)
|
||||
{
|
||||
impl_.reset();
|
||||
impl_.reset(new Impl(r, pd, o));
|
||||
}
|
||||
|
||||
void Raster::reset()
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
|
||||
/// Constructor taking the resolution and the pixel dimension.
|
||||
explicit Raster(const Resolution& r, const PixelDim& pd,
|
||||
Origin o = Origin::TOP_LEFT );
|
||||
Origin o = Origin::BOTTOM_LEFT );
|
||||
Raster();
|
||||
Raster(const Raster& cpy) = delete;
|
||||
Raster& operator=(const Raster& cpy) = delete;
|
||||
@ -61,6 +61,7 @@ public:
|
||||
|
||||
/// Reallocated everything for the given resolution and pixel dimension.
|
||||
void reset(const Resolution& r, const PixelDim& pd);
|
||||
void reset(const Resolution& r, const PixelDim& pd, Origin o);
|
||||
|
||||
/**
|
||||
* Release the allocated resources. Drawing in this state ends in
|
||||
|
@ -84,6 +84,8 @@ inline T next_highest_power_of_2(T v)
|
||||
return ++ v;
|
||||
}
|
||||
|
||||
extern std::string xml_escape(std::string text);
|
||||
|
||||
class PerlCallback {
|
||||
public:
|
||||
PerlCallback(void *sv) : m_callback(nullptr) { this->register_callback(sv); }
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#define SLIC3R_FORK_NAME "Slic3r Prusa Edition"
|
||||
#define SLIC3R_VERSION "1.41.0-alpha"
|
||||
#define SLIC3R_VERSION "1.41.0-alpha2"
|
||||
#define SLIC3R_BUILD "UNKNOWN"
|
||||
|
||||
typedef int32_t coord_t;
|
||||
|
@ -387,4 +387,31 @@ unsigned get_current_pid()
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string xml_escape(std::string text)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
for (;;)
|
||||
{
|
||||
pos = text.find_first_of("\"\'&<>", pos);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
|
||||
std::string replacement;
|
||||
switch (text[pos])
|
||||
{
|
||||
case '\"': replacement = """; break;
|
||||
case '\'': replacement = "'"; break;
|
||||
case '&': replacement = "&"; break;
|
||||
case '<': replacement = "<"; break;
|
||||
case '>': replacement = ">"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
text.replace(pos, 1, replacement);
|
||||
pos += replacement.size();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
@ -22,11 +22,6 @@
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/spin_mutex.h>
|
||||
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/dcmemory.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/settings.h>
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
#include "GUI.hpp"
|
||||
@ -540,8 +535,8 @@ double GLVolume::layer_height_texture_z_to_row_id() const
|
||||
|
||||
void GLVolume::generate_layer_height_texture(PrintObject *print_object, bool force)
|
||||
{
|
||||
GLTexture *tex = this->layer_height_texture.get();
|
||||
if (tex == nullptr)
|
||||
LayersTexture *tex = this->layer_height_texture.get();
|
||||
if (tex == nullptr)
|
||||
// No layer_height_texture is assigned to this GLVolume, therefore the layer height texture cannot be filled.
|
||||
return;
|
||||
|
||||
@ -588,8 +583,8 @@ std::vector<int> GLVolumeCollection::load_object(
|
||||
};
|
||||
|
||||
// Object will have a single common layer height texture for all volumes.
|
||||
std::shared_ptr<GLTexture> layer_height_texture = std::make_shared<GLTexture>();
|
||||
|
||||
std::shared_ptr<LayersTexture> layer_height_texture = std::make_shared<LayersTexture>();
|
||||
|
||||
std::vector<int> volumes_idx;
|
||||
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++ volume_idx) {
|
||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||
@ -743,7 +738,7 @@ void GLVolumeCollection::render_legacy() const
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config)
|
||||
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstance::EPrintVolumeState* out_state)
|
||||
{
|
||||
if (config == nullptr)
|
||||
return false;
|
||||
@ -757,18 +752,31 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config)
|
||||
// Allow the objects to protrude below the print bed
|
||||
print_volume.min.z = -1e10;
|
||||
|
||||
bool contained = true;
|
||||
ModelInstance::EPrintVolumeState state = ModelInstance::PVS_Inside;
|
||||
bool all_contained = true;
|
||||
|
||||
for (GLVolume* volume : this->volumes)
|
||||
{
|
||||
if ((volume != nullptr) && !volume->is_modifier)
|
||||
{
|
||||
bool state = print_volume.contains(volume->transformed_bounding_box());
|
||||
contained &= state;
|
||||
volume->is_outside = !state;
|
||||
const BoundingBoxf3& bb = volume->transformed_bounding_box();
|
||||
bool contained = print_volume.contains(bb);
|
||||
all_contained &= contained;
|
||||
|
||||
volume->is_outside = !contained;
|
||||
|
||||
if ((state == ModelInstance::PVS_Inside) && volume->is_outside)
|
||||
state = ModelInstance::PVS_Fully_Outside;
|
||||
|
||||
if ((state == ModelInstance::PVS_Fully_Outside) && volume->is_outside && print_volume.intersects(bb))
|
||||
state = ModelInstance::PVS_Partly_Outside;
|
||||
}
|
||||
}
|
||||
|
||||
return contained;
|
||||
if (out_state != nullptr)
|
||||
*out_state = state;
|
||||
|
||||
return all_contained;
|
||||
}
|
||||
|
||||
void GLVolumeCollection::reset_outside_state()
|
||||
@ -1576,246 +1584,8 @@ void _3DScene::point3_to_verts(const Point3& point, double width, double height,
|
||||
thick_point_to_verts(point, width, height, volume);
|
||||
}
|
||||
|
||||
_3DScene::LegendTexture _3DScene::s_legend_texture;
|
||||
_3DScene::WarningTexture _3DScene::s_warning_texture;
|
||||
GUI::GLCanvas3DManager _3DScene::s_canvas_mgr;
|
||||
|
||||
unsigned int _3DScene::TextureBase::finalize()
|
||||
{
|
||||
if ((m_tex_id == 0) && !m_data.empty()) {
|
||||
// sends buffer to gpu
|
||||
::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
::glGenTextures(1, &m_tex_id);
|
||||
::glBindTexture(GL_TEXTURE_2D, (GLuint)m_tex_id);
|
||||
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)m_data.data());
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
::glBindTexture(GL_TEXTURE_2D, 0);
|
||||
m_data.clear();
|
||||
}
|
||||
return (m_tex_width > 0 && m_tex_height > 0) ? m_tex_id : 0;
|
||||
}
|
||||
|
||||
void _3DScene::TextureBase::_destroy_texture()
|
||||
{
|
||||
if (m_tex_id > 0)
|
||||
{
|
||||
::glDeleteTextures(1, &m_tex_id);
|
||||
m_tex_id = 0;
|
||||
m_tex_height = 0;
|
||||
m_tex_width = 0;
|
||||
}
|
||||
m_data.clear();
|
||||
}
|
||||
|
||||
|
||||
const unsigned char _3DScene::WarningTexture::Background_Color[3] = { 9, 91, 134 };
|
||||
const unsigned char _3DScene::WarningTexture::Opacity = 255;
|
||||
|
||||
// Generate a texture data, but don't load it into the GPU yet, as the GPU context may not yet be valid.
|
||||
bool _3DScene::WarningTexture::generate(const std::string& msg)
|
||||
{
|
||||
// Mark the texture as released, but don't release the texture from the GPU yet.
|
||||
m_tex_width = m_tex_height = 0;
|
||||
m_data.clear();
|
||||
|
||||
if (msg.empty())
|
||||
return false;
|
||||
|
||||
wxMemoryDC memDC;
|
||||
// select default font
|
||||
memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
|
||||
// calculates texture size
|
||||
wxCoord w, h;
|
||||
memDC.GetTextExtent(msg, &w, &h);
|
||||
m_tex_width = (unsigned int)w;
|
||||
m_tex_height = (unsigned int)h;
|
||||
|
||||
// generates bitmap
|
||||
wxBitmap bitmap(m_tex_width, m_tex_height);
|
||||
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
bitmap.UseAlpha();
|
||||
#endif
|
||||
|
||||
memDC.SelectObject(bitmap);
|
||||
memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2])));
|
||||
memDC.Clear();
|
||||
|
||||
memDC.SetTextForeground(*wxWHITE);
|
||||
|
||||
// draw message
|
||||
memDC.DrawText(msg, 0, 0);
|
||||
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
// Convert the bitmap into a linear data ready to be loaded into the GPU.
|
||||
{
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
|
||||
|
||||
// prepare buffer
|
||||
m_data.assign(4 * m_tex_width * m_tex_height, 0);
|
||||
for (unsigned int h = 0; h < m_tex_height; ++h)
|
||||
{
|
||||
unsigned int hh = h * m_tex_width;
|
||||
unsigned char* px_ptr = m_data.data() + 4 * hh;
|
||||
for (unsigned int w = 0; w < m_tex_width; ++w)
|
||||
{
|
||||
*px_ptr++ = image.GetRed(w, h);
|
||||
*px_ptr++ = image.GetGreen(w, h);
|
||||
*px_ptr++ = image.GetBlue(w, h);
|
||||
*px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const unsigned char _3DScene::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 };
|
||||
const unsigned char _3DScene::LegendTexture::Background_Color[3] = { 9, 91, 134 };
|
||||
const unsigned char _3DScene::LegendTexture::Opacity = 255;
|
||||
|
||||
// Generate a texture data, but don't load it into the GPU yet, as the GPU context may not yet be valid.
|
||||
bool _3DScene::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
|
||||
{
|
||||
// Mark the texture as released, but don't release the texture from the GPU yet.
|
||||
m_tex_width = m_tex_height = 0;
|
||||
m_data.clear();
|
||||
|
||||
// collects items to render
|
||||
auto title = _(preview_data.get_legend_title());
|
||||
const GCodePreviewData::LegendItemsList& items = preview_data.get_legend_items(tool_colors);
|
||||
|
||||
unsigned int items_count = (unsigned int)items.size();
|
||||
if (items_count == 0)
|
||||
// nothing to render, return
|
||||
return false;
|
||||
|
||||
wxMemoryDC memDC;
|
||||
// select default font
|
||||
memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
|
||||
// calculates texture size
|
||||
wxCoord w, h;
|
||||
memDC.GetTextExtent(title, &w, &h);
|
||||
unsigned int title_width = (unsigned int)w;
|
||||
unsigned int title_height = (unsigned int)h;
|
||||
|
||||
unsigned int max_text_width = 0;
|
||||
unsigned int max_text_height = 0;
|
||||
for (const GCodePreviewData::LegendItem& item : items)
|
||||
{
|
||||
memDC.GetTextExtent(GUI::from_u8(item.text), &w, &h);
|
||||
max_text_width = std::max(max_text_width, (unsigned int)w);
|
||||
max_text_height = std::max(max_text_height, (unsigned int)h);
|
||||
}
|
||||
|
||||
m_tex_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width);
|
||||
m_tex_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square;
|
||||
if (items_count > 1)
|
||||
m_tex_height += (items_count - 1) * Px_Square_Contour;
|
||||
|
||||
// generates bitmap
|
||||
wxBitmap bitmap(m_tex_width, m_tex_height);
|
||||
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
bitmap.UseAlpha();
|
||||
#endif
|
||||
|
||||
memDC.SelectObject(bitmap);
|
||||
memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2])));
|
||||
memDC.Clear();
|
||||
|
||||
memDC.SetTextForeground(*wxWHITE);
|
||||
|
||||
// draw title
|
||||
unsigned int title_x = Px_Border;
|
||||
unsigned int title_y = Px_Border;
|
||||
memDC.DrawText(title, title_x, title_y);
|
||||
|
||||
// draw icons contours as background
|
||||
unsigned int squares_contour_x = Px_Border;
|
||||
unsigned int squares_contour_y = Px_Border + title_height + Px_Title_Offset;
|
||||
unsigned int squares_contour_width = Px_Square + 2 * Px_Square_Contour;
|
||||
unsigned int squares_contour_height = items_count * Px_Square + 2 * Px_Square_Contour;
|
||||
if (items_count > 1)
|
||||
squares_contour_height += (items_count - 1) * Px_Square_Contour;
|
||||
|
||||
wxColour color(Squares_Border_Color[0], Squares_Border_Color[1], Squares_Border_Color[2]);
|
||||
wxPen pen(color);
|
||||
wxBrush brush(color);
|
||||
memDC.SetPen(pen);
|
||||
memDC.SetBrush(brush);
|
||||
memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height));
|
||||
|
||||
// draw items (colored icon + text)
|
||||
unsigned int icon_x = squares_contour_x + Px_Square_Contour;
|
||||
unsigned int icon_x_inner = icon_x + 1;
|
||||
unsigned int icon_y = squares_contour_y + Px_Square_Contour;
|
||||
unsigned int icon_y_step = Px_Square + Px_Square_Contour;
|
||||
|
||||
unsigned int text_x = icon_x + Px_Square + Px_Text_Offset;
|
||||
unsigned int text_y_offset = (Px_Square - max_text_height) / 2;
|
||||
|
||||
unsigned int px_inner_square = Px_Square - 2;
|
||||
|
||||
for (const GCodePreviewData::LegendItem& item : items)
|
||||
{
|
||||
// draw darker icon perimeter
|
||||
const std::vector<unsigned char>& item_color_bytes = item.color.as_bytes();
|
||||
wxImage::HSVValue dark_hsv = wxImage::RGBtoHSV(wxImage::RGBValue(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2]));
|
||||
dark_hsv.value *= 0.75;
|
||||
wxImage::RGBValue dark_rgb = wxImage::HSVtoRGB(dark_hsv);
|
||||
color.Set(dark_rgb.red, dark_rgb.green, dark_rgb.blue, item_color_bytes[3]);
|
||||
pen.SetColour(color);
|
||||
brush.SetColour(color);
|
||||
memDC.SetPen(pen);
|
||||
memDC.SetBrush(brush);
|
||||
memDC.DrawRectangle(wxRect(icon_x, icon_y, Px_Square, Px_Square));
|
||||
|
||||
// draw icon interior
|
||||
color.Set(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2], item_color_bytes[3]);
|
||||
pen.SetColour(color);
|
||||
brush.SetColour(color);
|
||||
memDC.SetPen(pen);
|
||||
memDC.SetBrush(brush);
|
||||
memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square));
|
||||
|
||||
// draw text
|
||||
memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset);
|
||||
|
||||
// update y
|
||||
icon_y += icon_y_step;
|
||||
}
|
||||
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
// Convert the bitmap into a linear data ready to be loaded into the GPU.
|
||||
{
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
|
||||
|
||||
// prepare buffer
|
||||
m_data.assign(4 * m_tex_width * m_tex_height, 0);
|
||||
for (unsigned int h = 0; h < m_tex_height; ++h)
|
||||
{
|
||||
unsigned int hh = h * m_tex_width;
|
||||
unsigned char* px_ptr = m_data.data() + 4 * hh;
|
||||
for (unsigned int w = 0; w < m_tex_width; ++w)
|
||||
{
|
||||
*px_ptr++ = image.GetRed(w, h);
|
||||
*px_ptr++ = image.GetGreen(w, h);
|
||||
*px_ptr++ = image.GetBlue(w, h);
|
||||
*px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void _3DScene::init_gl()
|
||||
{
|
||||
s_canvas_mgr.init_gl();
|
||||
@ -1881,7 +1651,7 @@ void _3DScene::update_volumes_selection(wxGLCanvas* canvas, const std::vector<in
|
||||
s_canvas_mgr.update_volumes_selection(canvas, selections);
|
||||
}
|
||||
|
||||
bool _3DScene::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config)
|
||||
int _3DScene::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config)
|
||||
{
|
||||
return s_canvas_mgr.check_volumes_outside_state(canvas, config);
|
||||
}
|
||||
@ -2218,54 +1988,9 @@ void _3DScene::load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* pr
|
||||
s_canvas_mgr.load_gcode_preview(canvas, preview_data, str_tool_colors);
|
||||
}
|
||||
|
||||
void _3DScene::generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
|
||||
{
|
||||
s_legend_texture.generate(preview_data, tool_colors);
|
||||
}
|
||||
|
||||
unsigned int _3DScene::get_legend_texture_width()
|
||||
{
|
||||
return s_legend_texture.get_texture_width();
|
||||
}
|
||||
|
||||
unsigned int _3DScene::get_legend_texture_height()
|
||||
{
|
||||
return s_legend_texture.get_texture_height();
|
||||
}
|
||||
|
||||
void _3DScene::reset_legend_texture()
|
||||
{
|
||||
s_legend_texture.reset_texture();
|
||||
}
|
||||
|
||||
unsigned int _3DScene::finalize_legend_texture()
|
||||
{
|
||||
return s_legend_texture.finalize();
|
||||
}
|
||||
|
||||
unsigned int _3DScene::get_warning_texture_width()
|
||||
{
|
||||
return s_warning_texture.get_texture_width();
|
||||
}
|
||||
|
||||
unsigned int _3DScene::get_warning_texture_height()
|
||||
{
|
||||
return s_warning_texture.get_texture_height();
|
||||
}
|
||||
|
||||
void _3DScene::generate_warning_texture(const std::string& msg)
|
||||
{
|
||||
s_warning_texture.generate(msg);
|
||||
}
|
||||
|
||||
void _3DScene::reset_warning_texture()
|
||||
{
|
||||
s_warning_texture.reset_texture();
|
||||
}
|
||||
|
||||
unsigned int _3DScene::finalize_warning_texture()
|
||||
{
|
||||
return s_warning_texture.finalize();
|
||||
s_canvas_mgr.reset_legend_texture();
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "../../libslic3r/Line.hpp"
|
||||
#include "../../libslic3r/TriangleMesh.hpp"
|
||||
#include "../../libslic3r/Utils.hpp"
|
||||
#include "../../libslic3r/Model.hpp"
|
||||
#include "../../slic3r/GUI/GLCanvas3DManager.hpp"
|
||||
|
||||
class wxBitmap;
|
||||
@ -199,10 +200,10 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class GLTexture
|
||||
class LayersTexture
|
||||
{
|
||||
public:
|
||||
GLTexture() : width(0), height(0), levels(0), cells(0) {}
|
||||
LayersTexture() : width(0), height(0), levels(0), cells(0) {}
|
||||
|
||||
// Texture data
|
||||
std::vector<char> data;
|
||||
@ -341,7 +342,7 @@ public:
|
||||
void release_geometry() { this->indexed_vertex_array.release_geometry(); }
|
||||
|
||||
/************************************************ Layer height texture ****************************************************/
|
||||
std::shared_ptr<GLTexture> layer_height_texture;
|
||||
std::shared_ptr<LayersTexture> layer_height_texture;
|
||||
// Data to render this volume using the layer height texture
|
||||
LayerHeightTextureData layer_height_texture_data;
|
||||
|
||||
@ -422,7 +423,9 @@ public:
|
||||
print_box_max[0] = max_x; print_box_max[1] = max_y; print_box_max[2] = max_z;
|
||||
}
|
||||
|
||||
bool check_outside_state(const DynamicPrintConfig* config);
|
||||
// returns true if all the volumes are completely contained in the print volume
|
||||
// returns the containment state in the given out_state, if non-null
|
||||
bool check_outside_state(const DynamicPrintConfig* config, ModelInstance::EPrintVolumeState* out_state);
|
||||
void reset_outside_state();
|
||||
|
||||
void update_colors_by_extruder(const DynamicPrintConfig* config);
|
||||
@ -437,65 +440,6 @@ private:
|
||||
|
||||
class _3DScene
|
||||
{
|
||||
class TextureBase
|
||||
{
|
||||
protected:
|
||||
unsigned int m_tex_id;
|
||||
unsigned int m_tex_width;
|
||||
unsigned int m_tex_height;
|
||||
|
||||
// generate() fills in m_data with the pixels, while finalize() moves the data to the GPU before rendering.
|
||||
std::vector<unsigned char> m_data;
|
||||
|
||||
public:
|
||||
TextureBase() : m_tex_id(0), m_tex_width(0), m_tex_height(0) {}
|
||||
virtual ~TextureBase() { _destroy_texture(); }
|
||||
|
||||
// If not loaded, load the texture data into the GPU. Return a texture ID or 0 if the texture has zero size.
|
||||
unsigned int finalize();
|
||||
|
||||
unsigned int get_texture_id() const { return m_tex_id; }
|
||||
unsigned int get_texture_width() const { return m_tex_width; }
|
||||
unsigned int get_texture_height() const { return m_tex_height; }
|
||||
|
||||
void reset_texture() { _destroy_texture(); }
|
||||
|
||||
private:
|
||||
void _destroy_texture();
|
||||
};
|
||||
|
||||
class WarningTexture : public TextureBase
|
||||
{
|
||||
static const unsigned char Background_Color[3];
|
||||
static const unsigned char Opacity;
|
||||
|
||||
public:
|
||||
WarningTexture() : TextureBase() {}
|
||||
|
||||
// Generate a texture data, but don't load it into the GPU yet, as the glcontext may not be valid yet.
|
||||
bool generate(const std::string& msg);
|
||||
};
|
||||
|
||||
class LegendTexture : public TextureBase
|
||||
{
|
||||
static const unsigned int Px_Title_Offset = 5;
|
||||
static const unsigned int Px_Text_Offset = 5;
|
||||
static const unsigned int Px_Square = 20;
|
||||
static const unsigned int Px_Square_Contour = 1;
|
||||
static const unsigned int Px_Border = Px_Square / 2;
|
||||
static const unsigned char Squares_Border_Color[3];
|
||||
static const unsigned char Background_Color[3];
|
||||
static const unsigned char Opacity;
|
||||
|
||||
public:
|
||||
LegendTexture() : TextureBase() {}
|
||||
|
||||
// Generate a texture data, but don't load it into the GPU yet, as the glcontext may not be valid yet.
|
||||
bool generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||
};
|
||||
|
||||
static LegendTexture s_legend_texture;
|
||||
static WarningTexture s_warning_texture;
|
||||
static GUI::GLCanvas3DManager s_canvas_mgr;
|
||||
|
||||
public:
|
||||
@ -516,7 +460,7 @@ public:
|
||||
static void deselect_volumes(wxGLCanvas* canvas);
|
||||
static void select_volume(wxGLCanvas* canvas, unsigned int id);
|
||||
static void update_volumes_selection(wxGLCanvas* canvas, const std::vector<int>& selections);
|
||||
static bool check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config);
|
||||
static int check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config);
|
||||
static bool move_volume_up(wxGLCanvas* canvas, unsigned int id);
|
||||
static bool move_volume_down(wxGLCanvas* canvas, unsigned int id);
|
||||
|
||||
@ -597,21 +541,7 @@ public:
|
||||
static void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors);
|
||||
static void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors);
|
||||
|
||||
// generates the legend texture in dependence of the current shown view type
|
||||
static void generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||
static unsigned int get_legend_texture_width();
|
||||
static unsigned int get_legend_texture_height();
|
||||
|
||||
static void reset_legend_texture();
|
||||
static unsigned int finalize_legend_texture();
|
||||
|
||||
static unsigned int get_warning_texture_width();
|
||||
static unsigned int get_warning_texture_height();
|
||||
|
||||
// generates a warning texture containing the given message
|
||||
static void generate_warning_texture(const std::string& msg);
|
||||
static void reset_warning_texture();
|
||||
static unsigned int finalize_warning_texture();
|
||||
|
||||
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
|
||||
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
|
||||
|
@ -65,22 +65,27 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, cons
|
||||
auto namefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
namefont.SetWeight(wxFONTWEIGHT_BOLD);
|
||||
|
||||
// wxGrid appends widgets by rows, but we need to construct them in columns.
|
||||
// These vectors are used to hold the elements so that they can be appended in the right order.
|
||||
std::vector<wxStaticText*> titles;
|
||||
std::vector<wxStaticBitmap*> bitmaps;
|
||||
std::vector<wxPanel*> variants_panels;
|
||||
|
||||
for (const auto &model : models) {
|
||||
auto *panel = new wxPanel(this);
|
||||
auto *col_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
panel->SetSizer(col_sizer);
|
||||
|
||||
auto *title = new wxStaticText(panel, wxID_ANY, model.name, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
|
||||
title->SetFont(namefont);
|
||||
col_sizer->Add(title, 0, wxBOTTOM, 3);
|
||||
|
||||
auto bitmap_file = wxString::Format("printers/%s_%s.png", vendor.id, model.id);
|
||||
wxBitmap bitmap(GUI::from_u8(Slic3r::var(bitmap_file.ToStdString())), wxBITMAP_TYPE_PNG);
|
||||
auto *bitmap_widget = new wxStaticBitmap(panel, wxID_ANY, bitmap);
|
||||
col_sizer->Add(bitmap_widget, 0, wxBOTTOM, 3);
|
||||
|
||||
col_sizer->AddSpacer(20);
|
||||
auto *title = new wxStaticText(this, wxID_ANY, model.name, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
|
||||
title->SetFont(namefont);
|
||||
title->Wrap(std::max((int)MODEL_MIN_WRAP, bitmap.GetWidth()));
|
||||
titles.push_back(title);
|
||||
|
||||
auto *bitmap_widget = new wxStaticBitmap(this, wxID_ANY, bitmap);
|
||||
bitmaps.push_back(bitmap_widget);
|
||||
|
||||
auto *variants_panel = new wxPanel(this);
|
||||
auto *variants_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
variants_panel->SetSizer(variants_sizer);
|
||||
const auto model_id = model.id;
|
||||
|
||||
bool default_variant = true; // Mark the first variant as default in the GUI
|
||||
@ -88,22 +93,26 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, cons
|
||||
const auto label = wxString::Format("%s %s %s %s", variant.name, _(L("mm")), _(L("nozzle")),
|
||||
(default_variant ? _(L("(default)")) : wxString()));
|
||||
default_variant = false;
|
||||
auto *cbox = new Checkbox(panel, label, model_id, variant.name);
|
||||
auto *cbox = new Checkbox(variants_panel, label, model_id, variant.name);
|
||||
const size_t idx = cboxes.size();
|
||||
cboxes.push_back(cbox);
|
||||
bool enabled = appconfig_vendors.get_variant("PrusaResearch", model_id, variant.name);
|
||||
variants_checked += enabled;
|
||||
cbox->SetValue(enabled);
|
||||
col_sizer->Add(cbox, 0, wxBOTTOM, 3);
|
||||
variants_sizer->Add(cbox, 0, wxBOTTOM, 3);
|
||||
cbox->Bind(wxEVT_CHECKBOX, [this, idx](wxCommandEvent &event) {
|
||||
if (idx >= this->cboxes.size()) { return; }
|
||||
this->on_checkbox(this->cboxes[idx], event.IsChecked());
|
||||
});
|
||||
}
|
||||
|
||||
printer_grid->Add(panel);
|
||||
variants_panels.push_back(variants_panel);
|
||||
}
|
||||
|
||||
for (auto title : titles) { printer_grid->Add(title, 0, wxBOTTOM, 3); }
|
||||
for (auto bitmap : bitmaps) { printer_grid->Add(bitmap, 0, wxBOTTOM, 20); }
|
||||
for (auto vp : variants_panels) { printer_grid->Add(vp); }
|
||||
|
||||
auto *all_none_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto *sel_all = new wxButton(this, wxID_ANY, _(L("Select all")));
|
||||
auto *sel_none = new wxButton(this, wxID_ANY, _(L("Select none")));
|
||||
@ -214,7 +223,7 @@ void ConfigWizardPage::enable_next(bool enable) { parent->p->enable_next(enable)
|
||||
|
||||
// Wizard pages
|
||||
|
||||
PageWelcome::PageWelcome(ConfigWizard *parent) :
|
||||
PageWelcome::PageWelcome(ConfigWizard *parent, bool check_first_variant) :
|
||||
ConfigWizardPage(parent, wxString::Format(_(L("Welcome to the Slic3r %s")), ConfigWizard::name()), _(L("Welcome"))),
|
||||
printer_picker(nullptr),
|
||||
others_buttons(new wxPanel(parent)),
|
||||
@ -238,7 +247,10 @@ PageWelcome::PageWelcome(ConfigWizard *parent) :
|
||||
AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors;
|
||||
|
||||
printer_picker = new PrinterPicker(this, vendor_prusa->second, appconfig_vendors);
|
||||
printer_picker->select_one(0, true); // Select the default (first) model/variant on the Prusa vendor
|
||||
if (check_first_variant) {
|
||||
// Select the default (first) model/variant on the Prusa vendor
|
||||
printer_picker->select_one(0, true);
|
||||
}
|
||||
printer_picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) {
|
||||
appconfig_vendors.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable);
|
||||
this->on_variant_checked();
|
||||
@ -779,7 +791,6 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
||||
app_config->set("version_check", page_update->version_check ? "1" : "0");
|
||||
app_config->set("preset_update", page_update->preset_update ? "1" : "0");
|
||||
app_config->reset_selections();
|
||||
// ^ TODO: replace with appropriate printer selection
|
||||
preset_bundle->load_presets(*app_config);
|
||||
} else {
|
||||
for (ConfigWizardPage *page = page_firmware; page != nullptr; page = page->page_next()) {
|
||||
@ -831,7 +842,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) :
|
||||
p->btnsizer->Add(p->btn_finish, 0, wxLEFT, BTN_SPACING);
|
||||
p->btnsizer->Add(p->btn_cancel, 0, wxLEFT, BTN_SPACING);
|
||||
|
||||
p->add_page(p->page_welcome = new PageWelcome(this));
|
||||
p->add_page(p->page_welcome = new PageWelcome(this, reason == RR_DATA_EMPTY || reason == RR_DATA_LEGACY));
|
||||
p->add_page(p->page_update = new PageUpdate(this));
|
||||
p->add_page(p->page_vendors = new PageVendors(this));
|
||||
p->add_page(p->page_firmware = new PageFirmware(this));
|
||||
|
@ -27,6 +27,7 @@ namespace GUI {
|
||||
|
||||
enum {
|
||||
WRAP_WIDTH = 500,
|
||||
MODEL_MIN_WRAP = 150,
|
||||
|
||||
DIALOG_MARGIN = 15,
|
||||
INDEX_MARGIN = 40,
|
||||
@ -103,7 +104,7 @@ struct PageWelcome: ConfigWizardPage
|
||||
wxPanel *others_buttons;
|
||||
wxCheckBox *cbox_reset;
|
||||
|
||||
PageWelcome(ConfigWizard *parent);
|
||||
PageWelcome(ConfigWizard *parent, bool check_first_variant);
|
||||
|
||||
virtual wxPanel* extra_buttons() { return others_buttons; }
|
||||
virtual void on_page_set();
|
||||
|
@ -15,6 +15,10 @@
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/dcmemory.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/settings.h>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/spin_mutex.h>
|
||||
@ -1381,7 +1385,8 @@ void GLCanvas3D::Gizmos::render(const GLCanvas3D& canvas, const BoundingBoxf3& b
|
||||
|
||||
::glDisable(GL_DEPTH_TEST);
|
||||
|
||||
_render_current_gizmo(box);
|
||||
if (box.radius() > 0.0)
|
||||
_render_current_gizmo(box);
|
||||
|
||||
::glPushMatrix();
|
||||
::glLoadIdentity();
|
||||
@ -1456,6 +1461,224 @@ float GLCanvas3D::Gizmos::_get_total_overlay_height() const
|
||||
return height;
|
||||
}
|
||||
|
||||
const unsigned char GLCanvas3D::WarningTexture::Background_Color[3] = { 9, 91, 134 };
|
||||
const unsigned char GLCanvas3D::WarningTexture::Opacity = 255;
|
||||
|
||||
bool GLCanvas3D::WarningTexture::generate(const std::string& msg)
|
||||
{
|
||||
reset();
|
||||
|
||||
if (msg.empty())
|
||||
return false;
|
||||
|
||||
wxMemoryDC memDC;
|
||||
// select default font
|
||||
memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
|
||||
// calculates texture size
|
||||
wxCoord w, h;
|
||||
memDC.GetTextExtent(msg, &w, &h);
|
||||
m_width = (int)w;
|
||||
m_height = (int)h;
|
||||
|
||||
// generates bitmap
|
||||
wxBitmap bitmap(m_width, m_height);
|
||||
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
bitmap.UseAlpha();
|
||||
#endif
|
||||
|
||||
memDC.SelectObject(bitmap);
|
||||
memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2])));
|
||||
memDC.Clear();
|
||||
|
||||
memDC.SetTextForeground(*wxWHITE);
|
||||
|
||||
// draw message
|
||||
memDC.DrawText(msg, 0, 0);
|
||||
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
// Convert the bitmap into a linear data ready to be loaded into the GPU.
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
|
||||
|
||||
// prepare buffer
|
||||
std::vector<unsigned char> data(4 * m_width * m_height, 0);
|
||||
for (int h = 0; h < m_height; ++h)
|
||||
{
|
||||
int hh = h * m_width;
|
||||
unsigned char* px_ptr = data.data() + 4 * hh;
|
||||
for (int w = 0; w < m_width; ++w)
|
||||
{
|
||||
*px_ptr++ = image.GetRed(w, h);
|
||||
*px_ptr++ = image.GetGreen(w, h);
|
||||
*px_ptr++ = image.GetBlue(w, h);
|
||||
*px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity;
|
||||
}
|
||||
}
|
||||
|
||||
// sends buffer to gpu
|
||||
::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
::glGenTextures(1, &m_id);
|
||||
::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id);
|
||||
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
::glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const unsigned char GLCanvas3D::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 };
|
||||
const unsigned char GLCanvas3D::LegendTexture::Background_Color[3] = { 9, 91, 134 };
|
||||
const unsigned char GLCanvas3D::LegendTexture::Opacity = 255;
|
||||
|
||||
bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
|
||||
{
|
||||
reset();
|
||||
|
||||
// collects items to render
|
||||
auto title = _(preview_data.get_legend_title());
|
||||
const GCodePreviewData::LegendItemsList& items = preview_data.get_legend_items(tool_colors);
|
||||
|
||||
unsigned int items_count = (unsigned int)items.size();
|
||||
if (items_count == 0)
|
||||
// nothing to render, return
|
||||
return false;
|
||||
|
||||
wxMemoryDC memDC;
|
||||
// select default font
|
||||
memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
|
||||
// calculates texture size
|
||||
wxCoord w, h;
|
||||
memDC.GetTextExtent(title, &w, &h);
|
||||
int title_width = (int)w;
|
||||
int title_height = (int)h;
|
||||
|
||||
int max_text_width = 0;
|
||||
int max_text_height = 0;
|
||||
for (const GCodePreviewData::LegendItem& item : items)
|
||||
{
|
||||
memDC.GetTextExtent(GUI::from_u8(item.text), &w, &h);
|
||||
max_text_width = std::max(max_text_width, (int)w);
|
||||
max_text_height = std::max(max_text_height, (int)h);
|
||||
}
|
||||
|
||||
m_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width);
|
||||
m_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square;
|
||||
if (items_count > 1)
|
||||
m_height += (items_count - 1) * Px_Square_Contour;
|
||||
|
||||
// generates bitmap
|
||||
wxBitmap bitmap(m_width, m_height);
|
||||
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
bitmap.UseAlpha();
|
||||
#endif
|
||||
|
||||
memDC.SelectObject(bitmap);
|
||||
memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2])));
|
||||
memDC.Clear();
|
||||
|
||||
memDC.SetTextForeground(*wxWHITE);
|
||||
|
||||
// draw title
|
||||
int title_x = Px_Border;
|
||||
int title_y = Px_Border;
|
||||
memDC.DrawText(title, title_x, title_y);
|
||||
|
||||
// draw icons contours as background
|
||||
int squares_contour_x = Px_Border;
|
||||
int squares_contour_y = Px_Border + title_height + Px_Title_Offset;
|
||||
int squares_contour_width = Px_Square + 2 * Px_Square_Contour;
|
||||
int squares_contour_height = items_count * Px_Square + 2 * Px_Square_Contour;
|
||||
if (items_count > 1)
|
||||
squares_contour_height += (items_count - 1) * Px_Square_Contour;
|
||||
|
||||
wxColour color(Squares_Border_Color[0], Squares_Border_Color[1], Squares_Border_Color[2]);
|
||||
wxPen pen(color);
|
||||
wxBrush brush(color);
|
||||
memDC.SetPen(pen);
|
||||
memDC.SetBrush(brush);
|
||||
memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height));
|
||||
|
||||
// draw items (colored icon + text)
|
||||
int icon_x = squares_contour_x + Px_Square_Contour;
|
||||
int icon_x_inner = icon_x + 1;
|
||||
int icon_y = squares_contour_y + Px_Square_Contour;
|
||||
int icon_y_step = Px_Square + Px_Square_Contour;
|
||||
|
||||
int text_x = icon_x + Px_Square + Px_Text_Offset;
|
||||
int text_y_offset = (Px_Square - max_text_height) / 2;
|
||||
|
||||
int px_inner_square = Px_Square - 2;
|
||||
|
||||
for (const GCodePreviewData::LegendItem& item : items)
|
||||
{
|
||||
// draw darker icon perimeter
|
||||
const std::vector<unsigned char>& item_color_bytes = item.color.as_bytes();
|
||||
wxImage::HSVValue dark_hsv = wxImage::RGBtoHSV(wxImage::RGBValue(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2]));
|
||||
dark_hsv.value *= 0.75;
|
||||
wxImage::RGBValue dark_rgb = wxImage::HSVtoRGB(dark_hsv);
|
||||
color.Set(dark_rgb.red, dark_rgb.green, dark_rgb.blue, item_color_bytes[3]);
|
||||
pen.SetColour(color);
|
||||
brush.SetColour(color);
|
||||
memDC.SetPen(pen);
|
||||
memDC.SetBrush(brush);
|
||||
memDC.DrawRectangle(wxRect(icon_x, icon_y, Px_Square, Px_Square));
|
||||
|
||||
// draw icon interior
|
||||
color.Set(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2], item_color_bytes[3]);
|
||||
pen.SetColour(color);
|
||||
brush.SetColour(color);
|
||||
memDC.SetPen(pen);
|
||||
memDC.SetBrush(brush);
|
||||
memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square));
|
||||
|
||||
// draw text
|
||||
memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset);
|
||||
|
||||
// update y
|
||||
icon_y += icon_y_step;
|
||||
}
|
||||
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
// Convert the bitmap into a linear data ready to be loaded into the GPU.
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
|
||||
|
||||
// prepare buffer
|
||||
std::vector<unsigned char> data(4 * m_width * m_height, 0);
|
||||
for (int h = 0; h < m_height; ++h)
|
||||
{
|
||||
int hh = h * m_width;
|
||||
unsigned char* px_ptr = data.data() + 4 * hh;
|
||||
for (int w = 0; w < m_width; ++w)
|
||||
{
|
||||
*px_ptr++ = image.GetRed(w, h);
|
||||
*px_ptr++ = image.GetGreen(w, h);
|
||||
*px_ptr++ = image.GetBlue(w, h);
|
||||
*px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity;
|
||||
}
|
||||
}
|
||||
|
||||
// sends buffer to gpu
|
||||
::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
::glGenTextures(1, &m_id);
|
||||
::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id);
|
||||
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
::glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GLGizmoBase* GLCanvas3D::Gizmos::_get_current() const
|
||||
{
|
||||
GizmosMap::const_iterator it = m_gizmos.find(m_current);
|
||||
@ -1655,9 +1878,11 @@ void GLCanvas3D::update_volumes_selection(const std::vector<int>& selections)
|
||||
}
|
||||
}
|
||||
|
||||
bool GLCanvas3D::check_volumes_outside_state(const DynamicPrintConfig* config) const
|
||||
int GLCanvas3D::check_volumes_outside_state(const DynamicPrintConfig* config) const
|
||||
{
|
||||
return m_volumes.check_outside_state(config);
|
||||
ModelInstance::EPrintVolumeState state;
|
||||
m_volumes.check_outside_state(config, &state);
|
||||
return (int)state;
|
||||
}
|
||||
|
||||
bool GLCanvas3D::move_volume_up(unsigned int id)
|
||||
@ -1905,7 +2130,7 @@ void GLCanvas3D::update_volumes_colors_by_extruder()
|
||||
|
||||
void GLCanvas3D::update_gizmos_data()
|
||||
{
|
||||
if (!m_gizmos.is_running())
|
||||
if (!m_gizmos.is_enabled())
|
||||
return;
|
||||
|
||||
int id = _get_first_selected_object_id();
|
||||
@ -1917,26 +2142,16 @@ void GLCanvas3D::update_gizmos_data()
|
||||
ModelInstance* model_instance = model_object->instances[0];
|
||||
if (model_instance != nullptr)
|
||||
{
|
||||
switch (m_gizmos.get_current_type())
|
||||
{
|
||||
case Gizmos::Scale:
|
||||
{
|
||||
m_gizmos.set_scale(model_instance->scaling_factor);
|
||||
break;
|
||||
}
|
||||
case Gizmos::Rotate:
|
||||
{
|
||||
m_gizmos.set_angle_z(model_instance->rotation);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_gizmos.set_scale(model_instance->scaling_factor);
|
||||
m_gizmos.set_angle_z(model_instance->rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gizmos.set_scale(1.0f);
|
||||
m_gizmos.set_angle_z(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::render()
|
||||
@ -2051,8 +2266,12 @@ void GLCanvas3D::reload_scene(bool force)
|
||||
m_objects_volumes_idxs.push_back(load_object(*m_model, obj_idx));
|
||||
}
|
||||
|
||||
// 1st call to reset if no objects left
|
||||
update_gizmos_data();
|
||||
update_volumes_selection(m_objects_selections);
|
||||
// 2nd call to restore if something selected
|
||||
if (!m_objects_selections.empty())
|
||||
update_gizmos_data();
|
||||
|
||||
if (m_config->has("nozzle_diameter"))
|
||||
{
|
||||
@ -2082,25 +2301,28 @@ void GLCanvas3D::reload_scene(bool force)
|
||||
// checks for geometry outside the print volume to render it accordingly
|
||||
if (!m_volumes.empty())
|
||||
{
|
||||
bool contained = m_volumes.check_outside_state(m_config);
|
||||
ModelInstance::EPrintVolumeState state;
|
||||
bool contained = m_volumes.check_outside_state(m_config, &state);
|
||||
|
||||
if (!contained)
|
||||
{
|
||||
enable_warning_texture(true);
|
||||
_3DScene::generate_warning_texture(L("Detected object outside print volume"));
|
||||
m_on_enable_action_buttons_callback.call(false);
|
||||
_generate_warning_texture(L("Detected object outside print volume"));
|
||||
m_on_enable_action_buttons_callback.call(state == ModelInstance::PVS_Fully_Outside);
|
||||
}
|
||||
else
|
||||
{
|
||||
enable_warning_texture(false);
|
||||
m_volumes.reset_outside_state();
|
||||
_3DScene::reset_warning_texture();
|
||||
_reset_warning_texture();
|
||||
m_on_enable_action_buttons_callback.call(!m_model->objects.empty());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
enable_warning_texture(false);
|
||||
_3DScene::reset_warning_texture();
|
||||
_reset_warning_texture();
|
||||
m_on_enable_action_buttons_callback.call(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2490,11 +2712,11 @@ void GLCanvas3D::load_gcode_preview(const GCodePreviewData& preview_data, const
|
||||
_load_gcode_unretractions(preview_data);
|
||||
|
||||
if (m_volumes.empty())
|
||||
_3DScene::reset_legend_texture();
|
||||
reset_legend_texture();
|
||||
else
|
||||
{
|
||||
_3DScene::generate_legend_texture(preview_data, tool_colors);
|
||||
|
||||
_generate_legend_texture(preview_data, tool_colors);
|
||||
|
||||
// removes empty volumes
|
||||
m_volumes.volumes.erase(std::remove_if(m_volumes.volumes.begin(), m_volumes.volumes.end(),
|
||||
[](const GLVolume* volume) { return volume->print_zs.empty(); }), m_volumes.volumes.end());
|
||||
@ -3103,6 +3325,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
{
|
||||
deselect_volumes();
|
||||
_on_select(-1);
|
||||
update_gizmos_data();
|
||||
}
|
||||
}
|
||||
else if (evt.LeftUp() && m_gizmos.is_dragging())
|
||||
@ -3130,6 +3353,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
m_mouse.set_start_position_3D_as_invalid();
|
||||
m_mouse.set_start_position_2D_as_invalid();
|
||||
m_mouse.dragging = false;
|
||||
m_dirty = true;
|
||||
}
|
||||
else if (evt.Moving())
|
||||
{
|
||||
@ -3181,6 +3405,14 @@ Point GLCanvas3D::get_local_mouse_position() const
|
||||
return Point(mouse_pos.x, mouse_pos.y);
|
||||
}
|
||||
|
||||
void GLCanvas3D::reset_legend_texture()
|
||||
{
|
||||
if (!set_current())
|
||||
return;
|
||||
|
||||
m_legend_texture.reset();
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_is_shown_on_screen() const
|
||||
{
|
||||
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
|
||||
@ -3272,7 +3504,7 @@ BoundingBoxf3 GLCanvas3D::_selected_volumes_bounding_box() const
|
||||
BoundingBoxf3 bb;
|
||||
for (const GLVolume* volume : m_volumes.volumes)
|
||||
{
|
||||
if ((volume != nullptr) && volume->selected)
|
||||
if ((volume != nullptr) && !volume->is_wipe_tower && volume->selected)
|
||||
bb.merge(volume->transformed_bounding_box());
|
||||
}
|
||||
return bb;
|
||||
@ -3441,6 +3673,7 @@ void GLCanvas3D::_picking_pass() const
|
||||
::glDisable(GL_MULTISAMPLE);
|
||||
|
||||
::glDisable(GL_BLEND);
|
||||
::glEnable(GL_DEPTH_TEST);
|
||||
|
||||
::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
@ -3549,7 +3782,7 @@ void GLCanvas3D::_render_objects() const
|
||||
{
|
||||
const BoundingBoxf3& bed_bb = m_bed.get_bounding_box();
|
||||
m_volumes.set_print_box((float)bed_bb.min.x, (float)bed_bb.min.y, 0.0f, (float)bed_bb.max.x, (float)bed_bb.max.y, (float)m_config->opt_float("max_print_height"));
|
||||
m_volumes.check_outside_state(m_config);
|
||||
m_volumes.check_outside_state(m_config, nullptr);
|
||||
}
|
||||
// do not cull backfaces to show broken geometry, if any
|
||||
::glDisable(GL_CULL_FACE);
|
||||
@ -3588,11 +3821,11 @@ void GLCanvas3D::_render_warning_texture() const
|
||||
return;
|
||||
|
||||
// If the warning texture has not been loaded into the GPU, do it now.
|
||||
unsigned int tex_id = _3DScene::finalize_warning_texture();
|
||||
unsigned int tex_id = m_warning_texture.get_id();
|
||||
if (tex_id > 0)
|
||||
{
|
||||
unsigned int w = _3DScene::get_warning_texture_width();
|
||||
unsigned int h = _3DScene::get_warning_texture_height();
|
||||
int w = m_warning_texture.get_width();
|
||||
int h = m_warning_texture.get_height();
|
||||
if ((w > 0) && (h > 0))
|
||||
{
|
||||
::glDisable(GL_DEPTH_TEST);
|
||||
@ -3621,11 +3854,11 @@ void GLCanvas3D::_render_legend_texture() const
|
||||
return;
|
||||
|
||||
// If the legend texture has not been loaded into the GPU, do it now.
|
||||
unsigned int tex_id = _3DScene::finalize_legend_texture();
|
||||
unsigned int tex_id = m_legend_texture.get_id();
|
||||
if (tex_id > 0)
|
||||
{
|
||||
unsigned int w = _3DScene::get_legend_texture_width();
|
||||
unsigned int h = _3DScene::get_legend_texture_height();
|
||||
int w = m_legend_texture.get_width();
|
||||
int h = m_legend_texture.get_height();
|
||||
if ((w > 0) && (h > 0))
|
||||
{
|
||||
::glDisable(GL_DEPTH_TEST);
|
||||
@ -4539,5 +4772,29 @@ std::vector<float> GLCanvas3D::_parse_colors(const std::vector<std::string>& col
|
||||
return output;
|
||||
}
|
||||
|
||||
void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
|
||||
{
|
||||
if (!set_current())
|
||||
return;
|
||||
|
||||
m_legend_texture.generate(preview_data, tool_colors);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_generate_warning_texture(const std::string& msg)
|
||||
{
|
||||
if (!set_current())
|
||||
return;
|
||||
|
||||
m_warning_texture.generate(msg);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_reset_warning_texture()
|
||||
{
|
||||
if (!set_current())
|
||||
return;
|
||||
|
||||
m_warning_texture.reset();
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
@ -394,9 +394,35 @@ public:
|
||||
GLGizmoBase* _get_current() const;
|
||||
};
|
||||
|
||||
class WarningTexture : public GUI::GLTexture
|
||||
{
|
||||
static const unsigned char Background_Color[3];
|
||||
static const unsigned char Opacity;
|
||||
|
||||
public:
|
||||
bool generate(const std::string& msg);
|
||||
};
|
||||
|
||||
class LegendTexture : public GUI::GLTexture
|
||||
{
|
||||
static const int Px_Title_Offset = 5;
|
||||
static const int Px_Text_Offset = 5;
|
||||
static const int Px_Square = 20;
|
||||
static const int Px_Square_Contour = 1;
|
||||
static const int Px_Border = Px_Square / 2;
|
||||
static const unsigned char Squares_Border_Color[3];
|
||||
static const unsigned char Background_Color[3];
|
||||
static const unsigned char Opacity;
|
||||
|
||||
public:
|
||||
bool generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||
};
|
||||
|
||||
private:
|
||||
wxGLCanvas* m_canvas;
|
||||
wxGLContext* m_context;
|
||||
LegendTexture m_legend_texture;
|
||||
WarningTexture m_warning_texture;
|
||||
wxTimer* m_timer;
|
||||
Camera m_camera;
|
||||
Bed m_bed;
|
||||
@ -469,7 +495,7 @@ public:
|
||||
void deselect_volumes();
|
||||
void select_volume(unsigned int id);
|
||||
void update_volumes_selection(const std::vector<int>& selections);
|
||||
bool check_volumes_outside_state(const DynamicPrintConfig* config) const;
|
||||
int check_volumes_outside_state(const DynamicPrintConfig* config) const;
|
||||
bool move_volume_up(unsigned int id);
|
||||
bool move_volume_down(unsigned int id);
|
||||
|
||||
@ -578,6 +604,8 @@ public:
|
||||
Size get_canvas_size() const;
|
||||
Point get_local_mouse_position() const;
|
||||
|
||||
void reset_legend_texture();
|
||||
|
||||
private:
|
||||
bool _is_shown_on_screen() const;
|
||||
void _force_zoom_to_bed();
|
||||
@ -643,6 +671,13 @@ private:
|
||||
void _on_move(const std::vector<int>& volume_idxs);
|
||||
void _on_select(int volume_idx);
|
||||
|
||||
// generates the legend texture in dependence of the current shown view type
|
||||
void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||
|
||||
// generates a warning texture containing the given message
|
||||
void _generate_warning_texture(const std::string& msg);
|
||||
void _reset_warning_texture();
|
||||
|
||||
static std::vector<float> _parse_colors(const std::vector<std::string>& colors);
|
||||
};
|
||||
|
||||
|
@ -237,7 +237,7 @@ void GLCanvas3DManager::update_volumes_selection(wxGLCanvas* canvas, const std::
|
||||
it->second->update_volumes_selection(selections);
|
||||
}
|
||||
|
||||
bool GLCanvas3DManager::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const
|
||||
int GLCanvas3DManager::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const
|
||||
{
|
||||
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||
return (it != m_canvases.end()) ? it->second->check_volumes_outside_state(config) : false;
|
||||
@ -550,6 +550,15 @@ void GLCanvas3DManager::load_gcode_preview(wxGLCanvas* canvas, const GCodePrevie
|
||||
it->second->load_gcode_preview(*preview_data, str_tool_colors);
|
||||
}
|
||||
|
||||
void GLCanvas3DManager::reset_legend_texture()
|
||||
{
|
||||
for (CanvasesMap::value_type& canvas : m_canvases)
|
||||
{
|
||||
if (canvas.second != nullptr)
|
||||
canvas.second->reset_legend_texture();
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas3DManager::register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback)
|
||||
{
|
||||
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
void deselect_volumes(wxGLCanvas* canvas);
|
||||
void select_volume(wxGLCanvas* canvas, unsigned int id);
|
||||
void update_volumes_selection(wxGLCanvas* canvas, const std::vector<int>& selections);
|
||||
bool check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const;
|
||||
int check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const;
|
||||
bool move_volume_up(wxGLCanvas* canvas, unsigned int id);
|
||||
bool move_volume_down(wxGLCanvas* canvas, unsigned int id);
|
||||
|
||||
@ -137,6 +137,8 @@ public:
|
||||
void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors);
|
||||
void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors);
|
||||
|
||||
void reset_legend_texture();
|
||||
|
||||
void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback);
|
||||
void register_on_double_click_callback(wxGLCanvas* canvas, void* callback);
|
||||
void register_on_right_click_callback(wxGLCanvas* canvas, void* callback);
|
||||
|
@ -79,7 +79,8 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap
|
||||
if (generate_mipmaps)
|
||||
{
|
||||
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
|
||||
_generate_mipmaps(image);
|
||||
unsigned int levels_count = _generate_mipmaps(image);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1 + levels_count);
|
||||
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
else
|
||||
@ -149,14 +150,14 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo
|
||||
::glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void GLTexture::_generate_mipmaps(wxImage& image)
|
||||
unsigned int GLTexture::_generate_mipmaps(wxImage& image)
|
||||
{
|
||||
int w = image.GetWidth();
|
||||
int h = image.GetHeight();
|
||||
GLint level = 0;
|
||||
std::vector<unsigned char> data(w * h * 4, 0);
|
||||
|
||||
while ((w > 1) && (h > 1))
|
||||
while ((w > 1) || (h > 1))
|
||||
{
|
||||
++level;
|
||||
|
||||
@ -183,6 +184,8 @@ void GLTexture::_generate_mipmaps(wxImage& image)
|
||||
|
||||
::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
|
||||
}
|
||||
|
||||
return (unsigned int)level;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
|
@ -10,7 +10,7 @@ namespace GUI {
|
||||
|
||||
class GLTexture
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
unsigned int m_id;
|
||||
int m_width;
|
||||
int m_height;
|
||||
@ -18,7 +18,7 @@ namespace GUI {
|
||||
|
||||
public:
|
||||
GLTexture();
|
||||
~GLTexture();
|
||||
virtual ~GLTexture();
|
||||
|
||||
bool load_from_file(const std::string& filename, bool generate_mipmaps);
|
||||
void reset();
|
||||
@ -26,12 +26,13 @@ namespace GUI {
|
||||
unsigned int get_id() const;
|
||||
int get_width() const;
|
||||
int get_height() const;
|
||||
|
||||
const std::string& get_source() const;
|
||||
|
||||
static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top);
|
||||
|
||||
private:
|
||||
void _generate_mipmaps(wxImage& image);
|
||||
protected:
|
||||
unsigned int _generate_mipmaps(wxImage& image);
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
@ -268,7 +268,7 @@ void PresetBundle::load_installed_printers(const AppConfig &config)
|
||||
}
|
||||
|
||||
// Load selections (current print, current filaments, current printer) from config.ini
|
||||
// This is done just once on application start up.
|
||||
// This is done on application start up or after updates are applied.
|
||||
void PresetBundle::load_selections(const AppConfig &config)
|
||||
{
|
||||
// Update visibility of presets based on application vendor / model / variant configuration.
|
||||
|
@ -1742,27 +1742,27 @@ PageShp TabPrinter::build_kinematics_page()
|
||||
}
|
||||
|
||||
std::vector<std::string> axes{ "x", "y", "z", "e" };
|
||||
auto optgroup = page->new_optgroup(_(L("Maximum accelerations")));
|
||||
for (const std::string &axis : axes) {
|
||||
append_option_line(optgroup, "machine_max_acceleration_" + axis);
|
||||
}
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Maximum feedrates")));
|
||||
auto optgroup = page->new_optgroup(_(L("Maximum feedrates")));
|
||||
for (const std::string &axis : axes) {
|
||||
append_option_line(optgroup, "machine_max_feedrate_" + axis);
|
||||
}
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Starting Acceleration")));
|
||||
optgroup = page->new_optgroup(_(L("Maximum accelerations")));
|
||||
for (const std::string &axis : axes) {
|
||||
append_option_line(optgroup, "machine_max_acceleration_" + axis);
|
||||
}
|
||||
append_option_line(optgroup, "machine_max_acceleration_extruding");
|
||||
append_option_line(optgroup, "machine_max_acceleration_retracting");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Advanced")));
|
||||
append_option_line(optgroup, "machine_min_extruding_rate");
|
||||
append_option_line(optgroup, "machine_min_travel_rate");
|
||||
optgroup = page->new_optgroup(_(L("Jerk limits")));
|
||||
for (const std::string &axis : axes) {
|
||||
append_option_line(optgroup, "machine_max_jerk_" + axis);
|
||||
}
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Minimum feedrates")));
|
||||
append_option_line(optgroup, "machine_min_extruding_rate");
|
||||
append_option_line(optgroup, "machine_min_travel_rate");
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
|
@ -322,10 +322,13 @@ Updates PresetUpdater::priv::get_config_updates() const
|
||||
|
||||
const auto ver_current = idx.find(vp.config_version);
|
||||
if (ver_current == idx.end()) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Preset bundle (`%1%`) version not found in index: %2%") % idx.vendor() % vp.config_version.to_string();
|
||||
continue;
|
||||
auto message = (boost::format("Preset bundle `%1%` version not found in index: %2%") % idx.vendor() % vp.config_version.to_string()).str();
|
||||
BOOST_LOG_TRIVIAL(error) << message;
|
||||
throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
// Getting a recommended version from the latest index, wich may have been downloaded
|
||||
// from the internet, or installed / updated from the installation resources.
|
||||
const auto recommended = idx.recommended();
|
||||
if (recommended == idx.end()) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("No recommended version for vendor: %1%, invalid index?") % idx.vendor();
|
||||
@ -353,25 +356,34 @@ Updates PresetUpdater::priv::get_config_updates() const
|
||||
}
|
||||
|
||||
auto path_src = cache_path / (idx.vendor() + ".ini");
|
||||
auto path_in_rsrc = rsrc_path / (idx.vendor() + ".ini");
|
||||
if (! fs::exists(path_src)) {
|
||||
auto path_in_rsrc = rsrc_path / (idx.vendor() + ".ini");
|
||||
if (! fs::exists(path_in_rsrc)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << boost::format("Index for vendor %1% indicates update, but bundle found in neither cache nor resources")
|
||||
% idx.vendor();;
|
||||
% idx.vendor();
|
||||
continue;
|
||||
} else {
|
||||
path_src = std::move(path_in_rsrc);
|
||||
path_in_rsrc.clear();
|
||||
}
|
||||
}
|
||||
|
||||
const auto new_vp = VendorProfile::from_ini(path_src, false);
|
||||
auto new_vp = VendorProfile::from_ini(path_src, false);
|
||||
bool found = false;
|
||||
if (new_vp.config_version == recommended->config_version) {
|
||||
updates.updates.emplace_back(std::move(path_src), std::move(bundle_path), *recommended);
|
||||
} else {
|
||||
found = true;
|
||||
} else if (! path_in_rsrc.empty() && fs::exists(path_in_rsrc)) {
|
||||
new_vp = VendorProfile::from_ini(path_in_rsrc, false);
|
||||
if (new_vp.config_version == recommended->config_version) {
|
||||
updates.updates.emplace_back(std::move(path_in_rsrc), std::move(bundle_path), *recommended);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (! found)
|
||||
BOOST_LOG_TRIVIAL(warning) << boost::format("Index for vendor %1% indicates update (%2%) but the new bundle was found neither in cache nor resources")
|
||||
% idx.vendor()
|
||||
% recommended->config_version.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,10 +542,21 @@ bool PresetUpdater::config_update() const
|
||||
std::unordered_map<std::string, wxString> incompats_map;
|
||||
for (const auto &incompat : updates.incompats) {
|
||||
auto vendor = incompat.name();
|
||||
auto restrictions = wxString::Format(_(L("requires min. %s and max. %s")),
|
||||
incompat.version.min_slic3r_version.to_string(),
|
||||
incompat.version.max_slic3r_version.to_string()
|
||||
);
|
||||
|
||||
const auto min_slic3r = incompat.version.min_slic3r_version;
|
||||
const auto max_slic3r = incompat.version.max_slic3r_version;
|
||||
wxString restrictions;
|
||||
if (min_slic3r != Semver::zero() && max_slic3r != Semver::inf()) {
|
||||
restrictions = wxString::Format(_(L("requires min. %s and max. %s")),
|
||||
min_slic3r.to_string(),
|
||||
max_slic3r.to_string()
|
||||
);
|
||||
} else if (min_slic3r != Semver::zero()) {
|
||||
restrictions = wxString::Format(_(L("requires min. %s")), min_slic3r.to_string());
|
||||
} else {
|
||||
restrictions = wxString::Format(_(L("requires max. %s")), max_slic3r.to_string());
|
||||
}
|
||||
|
||||
incompats_map.emplace(std::make_pair(std::move(vendor), std::move(restrictions)));
|
||||
}
|
||||
|
||||
@ -545,9 +568,10 @@ bool PresetUpdater::config_update() const
|
||||
BOOST_LOG_TRIVIAL(info) << "User wants to re-configure...";
|
||||
p->perform_updates(std::move(updates));
|
||||
GUI::ConfigWizard wizard(nullptr, GUI::ConfigWizard::RR_DATA_INCOMPAT);
|
||||
if (! wizard.run(GUI::get_preset_bundle(), this)) {
|
||||
if (! wizard.run(GUI::get_preset_bundle(), this)) {
|
||||
return false;
|
||||
}
|
||||
GUI::load_current_presets();
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "User wants to exit Slic3r, bye...";
|
||||
return false;
|
||||
@ -577,7 +601,6 @@ bool PresetUpdater::config_update() const
|
||||
|
||||
// Reload global configuration
|
||||
auto *app_config = GUI::get_app_config();
|
||||
app_config->reset_selections();
|
||||
GUI::get_preset_bundle()->load_presets(*app_config);
|
||||
GUI::load_current_presets();
|
||||
} else {
|
||||
|
@ -105,10 +105,6 @@
|
||||
void release_geometry();
|
||||
|
||||
void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z);
|
||||
bool check_outside_state(DynamicPrintConfig* config)
|
||||
%code%{
|
||||
RETVAL = THIS->check_outside_state(config);
|
||||
%};
|
||||
|
||||
void reset_outside_state();
|
||||
void update_colors_by_extruder(DynamicPrintConfig* config);
|
||||
@ -234,7 +230,7 @@ update_volumes_selection(canvas, selections)
|
||||
CODE:
|
||||
_3DScene::update_volumes_selection((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), selections);
|
||||
|
||||
bool
|
||||
int
|
||||
check_volumes_outside_state(canvas, config)
|
||||
SV *canvas;
|
||||
DynamicPrintConfig *config;
|
||||
@ -627,64 +623,12 @@ register_on_update_geometry_info_callback(canvas, callback)
|
||||
SV *callback;
|
||||
CODE:
|
||||
_3DScene::register_on_update_geometry_info_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||
|
||||
unsigned int
|
||||
finalize_legend_texture()
|
||||
CODE:
|
||||
RETVAL = _3DScene::finalize_legend_texture();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
unsigned int
|
||||
get_legend_texture_width()
|
||||
CODE:
|
||||
RETVAL = _3DScene::get_legend_texture_width();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
unsigned int
|
||||
get_legend_texture_height()
|
||||
CODE:
|
||||
RETVAL = _3DScene::get_legend_texture_height();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
void
|
||||
reset_legend_texture()
|
||||
CODE:
|
||||
_3DScene::reset_legend_texture();
|
||||
|
||||
void
|
||||
generate_warning_texture(std::string msg)
|
||||
CODE:
|
||||
_3DScene::generate_warning_texture(msg);
|
||||
|
||||
unsigned int
|
||||
finalize_warning_texture()
|
||||
CODE:
|
||||
RETVAL = _3DScene::finalize_warning_texture();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
unsigned int
|
||||
get_warning_texture_width()
|
||||
CODE:
|
||||
RETVAL = _3DScene::get_warning_texture_width();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
unsigned int
|
||||
get_warning_texture_height()
|
||||
CODE:
|
||||
RETVAL = _3DScene::get_warning_texture_height();
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
void
|
||||
reset_warning_texture()
|
||||
CODE:
|
||||
_3DScene::reset_warning_texture();
|
||||
|
||||
std::vector<int>
|
||||
load_model_object(canvas, model_object, obj_idx, instance_idxs)
|
||||
SV *canvas;
|
||||
|