mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-07 07:29:06 +08:00
Merge branch 'master' of https://github.com/prusa3d/Slic3r into scene_manipulators
This commit is contained in:
commit
eb95e29be6
@ -535,7 +535,11 @@ sub new {
|
||||
fil_mm3 => L("Used Filament (mm³)"),
|
||||
fil_g => L("Used Filament (g)"),
|
||||
cost => L("Cost"),
|
||||
time => L("Estimated printing time"),
|
||||
#==========================================================================================================================================
|
||||
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;
|
||||
@ -1617,7 +1621,11 @@ sub on_export_completed {
|
||||
$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_time"}->SetLabel($self->{print}->estimated_print_time);
|
||||
#==========================================================================================================================================
|
||||
$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);
|
||||
|
||||
@ -1694,6 +1702,34 @@ sub export_object_stl {
|
||||
$self->statusbar->SetStatusText(L("STL file exported to ").$output_file);
|
||||
}
|
||||
|
||||
sub fix_through_netfabb {
|
||||
my ($self) = @_;
|
||||
my ($obj_idx, $object) = $self->selected_object;
|
||||
return if !defined $obj_idx;
|
||||
my $model_object = $self->{model}->objects->[$obj_idx];
|
||||
my $model_fixed = Slic3r::Model->new;
|
||||
Slic3r::GUI::fix_model_by_win10_sdk_gui($model_object, $self->{print}, $model_fixed);
|
||||
|
||||
my @new_obj_idx = $self->load_model_objects(@{$model_fixed->objects});
|
||||
return if !@new_obj_idx;
|
||||
|
||||
foreach my $new_obj_idx (@new_obj_idx) {
|
||||
my $o = $self->{model}->objects->[$new_obj_idx];
|
||||
$o->clear_instances;
|
||||
$o->add_instance($_) for @{$model_object->instances};
|
||||
#$o->invalidate_bounding_box;
|
||||
|
||||
if ($o->volumes_count == $model_object->volumes_count) {
|
||||
for my $i (0..($o->volumes_count-1)) {
|
||||
$o->get_volume($i)->config->apply($model_object->get_volume($i)->config);
|
||||
}
|
||||
}
|
||||
#FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid,
|
||||
}
|
||||
|
||||
$self->remove($obj_idx);
|
||||
}
|
||||
|
||||
sub export_amf {
|
||||
my ($self) = @_;
|
||||
return if !@{$self->{objects}};
|
||||
@ -2272,6 +2308,11 @@ sub object_menu {
|
||||
$frame->_append_menu_item($menu, L("Export object as STL…"), L('Export this single object as STL file'), sub {
|
||||
$self->export_object_stl;
|
||||
}, undef, 'brick_go.png');
|
||||
if (Slic3r::GUI::is_windows10) {
|
||||
$frame->_append_menu_item($menu, L("Fix STL through Netfabb"), L('Fix the model by sending it to a Netfabb cloud service through Windows 10 API'), sub {
|
||||
$self->fix_through_netfabb;
|
||||
}, undef, 'brick_go.png');
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
min_slic3r_version = 1.41.0-alpha
|
||||
0.2.0-alpha
|
||||
min_slic3r_version = 1.40.0
|
||||
0.1.6 Split the MK2.5 profile from the MK2S
|
||||
min_slic3r_version = 1.40.0-beta
|
||||
|
@ -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.1.6
|
||||
config_version = 0.2.0-alpha
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/
|
||||
|
||||
@ -140,7 +140,7 @@ infill_extrusion_width = 0.25
|
||||
perimeter_extrusion_width = 0.25
|
||||
solid_infill_extrusion_width = 0.25
|
||||
top_infill_extrusion_width = 0.25
|
||||
support_material_extrusion_width = 0.18
|
||||
support_material_extrusion_width = 0.2
|
||||
support_material_interface_layers = 0
|
||||
support_material_interface_spacing = 0.15
|
||||
support_material_spacing = 1
|
||||
@ -155,6 +155,7 @@ infill_extrusion_width = 0.7
|
||||
perimeter_extrusion_width = 0.65
|
||||
solid_infill_extrusion_width = 0.65
|
||||
top_infill_extrusion_width = 0.6
|
||||
support_material_extrusion_width = 0.55
|
||||
|
||||
[print:*soluble_support*]
|
||||
overhangs = 1
|
||||
@ -213,26 +214,18 @@ top_infill_extrusion_width = 0.4
|
||||
[print:0.05mm ULTRADETAIL 0.25 nozzle]
|
||||
inherits = *0.05mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 and num_extruders==1
|
||||
external_perimeter_extrusion_width = 0
|
||||
extrusion_width = 0.28
|
||||
fill_density = 20%
|
||||
first_layer_extrusion_width = 0.3
|
||||
infill_extrusion_width = 0
|
||||
infill_speed = 20
|
||||
max_print_speed = 100
|
||||
perimeter_extrusion_width = 0
|
||||
perimeter_speed = 20
|
||||
small_perimeter_speed = 15
|
||||
solid_infill_extrusion_width = 0
|
||||
solid_infill_speed = 20
|
||||
support_material_speed = 20
|
||||
top_infill_extrusion_width = 0
|
||||
|
||||
[print:0.05mm ULTRADETAIL 0.25 nozzle MK3]
|
||||
inherits = *0.05mm*; *0.25nozzle*
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 and num_extruders==1
|
||||
fill_pattern = grid
|
||||
top_infill_extrusion_width = 0.4
|
||||
|
||||
# XXXXXXXXXXXXXXXXXXXX
|
||||
# XXX--- 0.10mm ---XXX
|
||||
@ -294,7 +287,6 @@ infill_speed = 200
|
||||
max_print_speed = 200
|
||||
perimeter_speed = 45
|
||||
solid_infill_speed = 200
|
||||
top_infill_extrusion_width = 0.4
|
||||
top_solid_infill_speed = 50
|
||||
|
||||
[print:0.10mm DETAIL 0.6 nozzle MK3]
|
||||
@ -308,7 +300,6 @@ infill_speed = 200
|
||||
max_print_speed = 200
|
||||
perimeter_speed = 45
|
||||
solid_infill_speed = 200
|
||||
top_infill_extrusion_width = 0.4
|
||||
top_solid_infill_speed = 50
|
||||
|
||||
# XXXXXXXXXXXXXXXXXXXX
|
||||
@ -358,7 +349,6 @@ perimeter_acceleration = 600
|
||||
perimeter_speed = 25
|
||||
small_perimeter_speed = 15
|
||||
solid_infill_speed = 40
|
||||
support_material_extrusion_width = 0.2
|
||||
top_solid_infill_speed = 30
|
||||
|
||||
[print:0.15mm OPTIMAL 0.6 nozzle]
|
||||
@ -544,7 +534,6 @@ external_perimeter_extrusion_width = 0.6
|
||||
external_perimeter_speed = 30
|
||||
notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
|
||||
perimeter_speed = 40
|
||||
support_material_extrusion_width = 0.55
|
||||
support_material_interface_layers = 3
|
||||
support_material_xy_spacing = 120%
|
||||
top_infill_extrusion_width = 0.57
|
||||
@ -912,6 +901,23 @@ end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbe
|
||||
extruder_colour = #FFFF00
|
||||
extruder_offset = 0x0
|
||||
gcode_flavor = marlin
|
||||
silent_mode = 0
|
||||
machine_max_acceleration_e = 10000
|
||||
machine_max_acceleration_extruding = 1500
|
||||
machine_max_acceleration_retracting = 1500
|
||||
machine_max_acceleration_x = 9000
|
||||
machine_max_acceleration_y = 9000
|
||||
machine_max_acceleration_z = 500
|
||||
machine_max_feedrate_e = 120
|
||||
machine_max_feedrate_x = 500
|
||||
machine_max_feedrate_y = 500
|
||||
machine_max_feedrate_z = 12
|
||||
machine_max_jerk_e = 2.5
|
||||
machine_max_jerk_x = 10
|
||||
machine_max_jerk_y = 10
|
||||
machine_max_jerk_z = 0.2
|
||||
machine_min_extruding_rate = 0
|
||||
machine_min_travel_rate = 0
|
||||
layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]
|
||||
max_layer_height = 0.25
|
||||
min_layer_height = 0.07
|
||||
@ -935,7 +941,7 @@ retract_speed = 35
|
||||
serial_port =
|
||||
serial_speed = 250000
|
||||
single_extruder_multi_material = 0
|
||||
start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
|
||||
start_gcode = M115 U3.1.0 ; tell printer latest fw version\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
|
||||
toolchange_gcode =
|
||||
use_firmware_retraction = 0
|
||||
use_relative_e_distances = 1
|
||||
@ -971,7 +977,7 @@ printer_model = MK2SMM
|
||||
inherits = *multimaterial*
|
||||
end_gcode = G1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n
|
||||
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\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\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
|
||||
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
|
||||
|
||||
@ -981,7 +987,7 @@ end_gcode = {if not has_wipe_tower}\n; Pull the filament into the cooling tubes.
|
||||
extruder_colour = #FFAA55;#5182DB;#4ECDD3;#FB7259
|
||||
nozzle_diameter = 0.4,0.4,0.4,0.4
|
||||
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\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\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
|
||||
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
|
||||
@ -1005,7 +1011,7 @@ printer_variant = 0.25
|
||||
default_print_profile = 0.10mm DETAIL 0.25 nozzle
|
||||
|
||||
[printer:Original Prusa i3 MK2 0.6 nozzle]
|
||||
inherits = *common*; *0.6nozzle*
|
||||
inherits = *common*
|
||||
max_layer_height = 0.35
|
||||
min_layer_height = 0.1
|
||||
nozzle_diameter = 0.6
|
||||
@ -1020,7 +1026,7 @@ default_print_profile = 0.20mm NORMAL 0.6 nozzle
|
||||
inherits = *mm-single*
|
||||
|
||||
[printer:Original Prusa i3 MK2 MM Single Mode 0.6 nozzle]
|
||||
inherits = *mm-single*; *0.6nozzle*
|
||||
inherits = *mm-single*
|
||||
nozzle_diameter = 0.6
|
||||
printer_variant = 0.6
|
||||
default_print_profile = 0.20mm NORMAL 0.6 nozzle
|
||||
@ -1030,7 +1036,7 @@ inherits = *mm-multi*
|
||||
nozzle_diameter = 0.4,0.4,0.4,0.4
|
||||
|
||||
[printer:Original Prusa i3 MK2 MultiMaterial 0.6 nozzle]
|
||||
inherits = *mm-multi*; *0.6nozzle*
|
||||
inherits = *mm-multi*
|
||||
nozzle_diameter = 0.6,0.6,0.6,0.6
|
||||
printer_variant = 0.6
|
||||
default_print_profile = 0.20mm NORMAL 0.6 nozzle
|
||||
@ -1042,17 +1048,17 @@ default_print_profile = 0.20mm NORMAL 0.6 nozzle
|
||||
[printer:Original Prusa i3 MK2.5]
|
||||
inherits = Original Prusa i3 MK2
|
||||
printer_model = MK2.5
|
||||
start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
|
||||
start_gcode = M115 U3.2.1 ; tell printer latest fw version\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
|
||||
|
||||
[printer:Original Prusa i3 MK2.5 0.25 nozzle]
|
||||
inherits = Original Prusa i3 MK2 0.25 nozzle
|
||||
printer_model = MK2.5
|
||||
start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
|
||||
start_gcode = M115 U3.2.1 ; tell printer latest fw version\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
|
||||
|
||||
[printer:Original Prusa i3 MK2.5 0.6 nozzle]
|
||||
inherits = Original Prusa i3 MK2 0.6 nozzle
|
||||
printer_model = MK2.5
|
||||
start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
|
||||
start_gcode = M115 U3.2.1 ; tell printer latest fw version\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
|
||||
|
||||
# XXXXXXXXXXXXXXXXX
|
||||
# XXX--- MK3 ---XXX
|
||||
@ -1061,38 +1067,47 @@ start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM201 X9000 Y9000 Z50
|
||||
[printer:Original Prusa i3 MK3]
|
||||
inherits = *common*
|
||||
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors
|
||||
machine_max_acceleration_e = 9000,9000
|
||||
machine_max_acceleration_extruding = 1250,960
|
||||
machine_max_acceleration_retracting = 1250,1250
|
||||
machine_max_acceleration_x = 1000,1000
|
||||
machine_max_acceleration_y = 1000,1000
|
||||
machine_max_acceleration_z = 1000,1000
|
||||
machine_max_feedrate_e = 120,120
|
||||
machine_max_feedrate_x = 200,172
|
||||
machine_max_feedrate_y = 200,172
|
||||
machine_max_feedrate_z = 12,12
|
||||
machine_max_jerk_e = 1.5,1.5
|
||||
machine_max_jerk_x = 8,8
|
||||
machine_max_jerk_y = 8,8
|
||||
machine_max_jerk_z = 0.4,0.4
|
||||
machine_min_extruding_rate = 0,0
|
||||
machine_min_travel_rate = 0,0
|
||||
silent_mode = 1
|
||||
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_MK3\n
|
||||
retract_lift_below = 209
|
||||
max_print_height = 210
|
||||
start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
|
||||
start_gcode = M115 U3.3.0 ; tell printer latest fw version\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
|
||||
printer_model = MK3
|
||||
default_print_profile = 0.15mm OPTIMAL MK3
|
||||
|
||||
[printer:Original Prusa i3 MK3 0.25 nozzle]
|
||||
inherits = *common*
|
||||
inherits = Original Prusa i3 MK3
|
||||
nozzle_diameter = 0.25
|
||||
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors
|
||||
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_MK3\n
|
||||
retract_lift_below = 209
|
||||
max_print_height = 210
|
||||
start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
|
||||
printer_model = MK3
|
||||
max_layer_height = 0.1
|
||||
min_layer_height = 0.05
|
||||
printer_variant = 0.25
|
||||
default_print_profile = 0.10mm DETAIL 0.25 nozzle MK3
|
||||
|
||||
[printer:Original Prusa i3 MK3 0.6 nozzle]
|
||||
inherits = *common*
|
||||
inherits = Original Prusa i3 MK3
|
||||
nozzle_diameter = 0.6
|
||||
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors
|
||||
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_MK3\n
|
||||
retract_lift_below = 209
|
||||
max_print_height = 210
|
||||
start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\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\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
|
||||
printer_model = MK3
|
||||
max_layer_height = 0.35
|
||||
min_layer_height = 0.1
|
||||
printer_variant = 0.6
|
||||
default_print_profile = 0.15mm OPTIMAL 0.6 nozzle MK3
|
||||
|
||||
# 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"
|
||||
filament="ColorFabb Brass Bronze 1.75mm";"ColorFabb HT 1.75mm";"ColorFabb nGen 1.75mm";"ColorFabb Woodfil 1.75mm";"ColorFabb XT 1.75mm";"ColorFabb XT-CF20 1.75mm";"E3D PC-ABS 1.75mm";"Fillamentum ABS 1.75mm";"Fillamentum ASA 1.75mm";"Generic ABS 1.75mm";"Generic PET 1.75mm";"Generic PLA 1.75mm";"Prusa ABS 1.75mm";"Prusa HIPS 1.75mm";"Prusa PET 1.75mm";"Prusa PLA 1.75mm";"Taulman Bridge 1.75mm";"Taulman T-Glase 1.75mm"
|
||||
filament="ColorFabb Brass Bronze 1.75mm";"ColorFabb HT 1.75mm";"ColorFabb nGen 1.75mm";"ColorFabb Woodfil 1.75mm";"ColorFabb XT 1.75mm";"ColorFabb XT-CF20 1.75mm";"E3D PC-ABS 1.75mm";"Fillamentum ABS 1.75mm";"Fillamentum ASA 1.75mm";"Generic ABS 1.75mm";"Generic PET 1.75mm";"Generic PLA 1.75mm";"Prusa ABS 1.75mm";"Prusa HIPS 1.75mm";"Prusa PET 1.75mm";"Prusa PLA 1.75mm";"Taulman Bridge 1.75mm";"Taulman T-Glase 1.75mm"
|
||||
|
@ -175,7 +175,7 @@ use Slic3r::Test;
|
||||
if ($info->{extruding} && $info->{dist_XY} > 0) {
|
||||
$cur_loop ||= [ [$self->X, $self->Y] ];
|
||||
push @$cur_loop, [ @$info{qw(new_X new_Y)} ];
|
||||
} else {
|
||||
} elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
|
||||
if ($cur_loop) {
|
||||
$has_cw_loops = 1 if Slic3r::Polygon->new(@$cur_loop)->is_clockwise;
|
||||
$cur_loop = undef;
|
||||
@ -201,7 +201,7 @@ use Slic3r::Test;
|
||||
if ($info->{extruding} && $info->{dist_XY} > 0) {
|
||||
$cur_loop ||= [ [$self->X, $self->Y] ];
|
||||
push @$cur_loop, [ @$info{qw(new_X new_Y)} ];
|
||||
} else {
|
||||
} elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
|
||||
if ($cur_loop) {
|
||||
$has_cw_loops = 1 if Slic3r::Polygon->new_scale(@$cur_loop)->is_clockwise;
|
||||
if ($self->F == $config->external_perimeter_speed*60) {
|
||||
@ -306,7 +306,7 @@ use Slic3r::Test;
|
||||
if ($info->{extruding} && $info->{dist_XY} > 0 && ($args->{F} // $self->F) == $config->perimeter_speed*60) {
|
||||
$perimeters{$self->Z}++ if !$in_loop;
|
||||
$in_loop = 1;
|
||||
} else {
|
||||
} elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
|
||||
$in_loop = 0;
|
||||
}
|
||||
});
|
||||
@ -430,7 +430,7 @@ use Slic3r::Test;
|
||||
push @seam_points, Slic3r::Point->new_scale($self->X, $self->Y);
|
||||
}
|
||||
$was_extruding = 1;
|
||||
} else {
|
||||
} elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
|
||||
$was_extruding = 0;
|
||||
}
|
||||
});
|
||||
|
@ -82,8 +82,8 @@ if(LIBNEST2D_OPTIMIZER_BACKEND STREQUAL "nlopt")
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libnest2d/optimizers/genetic.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libnest2d/optimizers/nlopt_boilerplate.hpp)
|
||||
list(APPEND LIBNEST2D_LIBRARIES ${NLopt_LIBS}
|
||||
# Threads::Threads
|
||||
)
|
||||
# Threads::Threads
|
||||
)
|
||||
list(APPEND LIBNEST2D_HEADERS ${NLopt_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
|
@ -84,7 +84,8 @@ void arrangeRectangles() {
|
||||
// {{0, 0}, {0, 20*SCALE}, {10*SCALE, 0}, {0, 0}}
|
||||
// };
|
||||
|
||||
std::vector<Item> crasher = {
|
||||
std::vector<Item> crasher =
|
||||
{
|
||||
{
|
||||
{-5000000, 8954050},
|
||||
{5000000, 8954050},
|
||||
@ -527,12 +528,12 @@ void arrangeRectangles() {
|
||||
};
|
||||
|
||||
std::vector<Item> input;
|
||||
// input.insert(input.end(), prusaParts().begin(), prusaParts().end());
|
||||
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(), rects.begin(), rects.end());
|
||||
// input.insert(input.end(), proba.begin(), proba.end());
|
||||
input.insert(input.end(), crasher.begin(), crasher.end());
|
||||
// input.insert(input.end(), crasher.begin(), crasher.end());
|
||||
|
||||
Box bin(250*SCALE, 210*SCALE);
|
||||
|
||||
@ -545,18 +546,18 @@ void arrangeRectangles() {
|
||||
|
||||
Packer::PlacementConfig pconf;
|
||||
pconf.alignment = Placer::Config::Alignment::CENTER;
|
||||
pconf.starting_point = Placer::Config::Alignment::CENTER;
|
||||
pconf.rotations = {0.0/*, Pi/2.0, Pi, 3*Pi/2*/};
|
||||
pconf.object_function = [&bin](Placer::Pile pile, double area,
|
||||
double norm, double penality) {
|
||||
|
||||
auto bb = ShapeLike::boundingBox(pile);
|
||||
|
||||
double diameter = PointLike::distance(bb.minCorner(),
|
||||
bb.maxCorner());
|
||||
|
||||
// We will optimize to the diameter of the circle around the bounding
|
||||
// box and use the norming factor to get rid of the physical dimensions
|
||||
double score = diameter / norm;
|
||||
auto& sh = pile.back();
|
||||
auto rv = Nfp::referenceVertex(sh);
|
||||
auto c = bin.center();
|
||||
auto d = PointLike::distance(rv, c);
|
||||
double score = double(d)/norm;
|
||||
|
||||
// If it does not fit into the print bed we will beat it
|
||||
// with a large penality
|
||||
@ -568,7 +569,9 @@ void arrangeRectangles() {
|
||||
Packer::SelectionConfig sconf;
|
||||
// sconf.allow_parallel = false;
|
||||
// sconf.force_parallel = false;
|
||||
// sconf.try_triplets = true;
|
||||
// sconf.try_reverse_order = true;
|
||||
// sconf.waste_increment = 0.1;
|
||||
|
||||
arrange.configure(pconf, sconf);
|
||||
|
||||
|
@ -26,11 +26,20 @@ struct NfpPConfig {
|
||||
/// Where to align the resulting packed pile
|
||||
Alignment alignment;
|
||||
|
||||
Alignment starting_point;
|
||||
|
||||
std::function<double(const Nfp::Shapes<RawShape>&, double, double, double)>
|
||||
object_function;
|
||||
|
||||
/**
|
||||
* @brief The quality of search for an optimal placement.
|
||||
* This is a compromise slider between quality and speed. Zero is the
|
||||
* fast and poor solution while 1.0 is the slowest but most accurate.
|
||||
*/
|
||||
float accuracy = 1.0;
|
||||
|
||||
NfpPConfig(): rotations({0.0, Pi/2.0, Pi, 3*Pi/2}),
|
||||
alignment(Alignment::CENTER) {}
|
||||
alignment(Alignment::CENTER), starting_point(Alignment::CENTER) {}
|
||||
};
|
||||
|
||||
// A class for getting a point on the circumference of the polygon (in log time)
|
||||
@ -39,14 +48,6 @@ template<class RawShape> class EdgeCache {
|
||||
using Coord = TCoord<Vertex>;
|
||||
using Edge = _Segment<Vertex>;
|
||||
|
||||
// enum Corners {
|
||||
// BOTTOM,
|
||||
// LEFT,
|
||||
// RIGHT,
|
||||
// TOP,
|
||||
// NUM_CORNERS
|
||||
// };
|
||||
|
||||
mutable std::vector<double> corners_;
|
||||
|
||||
std::vector<Edge> emap_;
|
||||
@ -70,49 +71,9 @@ template<class RawShape> class EdgeCache {
|
||||
void fetchCorners() const {
|
||||
if(!corners_.empty()) return;
|
||||
|
||||
// TODO Accuracy
|
||||
corners_ = distances_;
|
||||
for(auto& d : corners_) {
|
||||
d /= full_distance_;
|
||||
}
|
||||
|
||||
// corners_ = std::vector<double>(NUM_CORNERS, 0.0);
|
||||
|
||||
// std::vector<unsigned> idx_ud(emap_.size(), 0);
|
||||
// std::vector<unsigned> idx_lr(emap_.size(), 0);
|
||||
|
||||
// std::iota(idx_ud.begin(), idx_ud.end(), 0);
|
||||
// std::iota(idx_lr.begin(), idx_lr.end(), 0);
|
||||
|
||||
// std::sort(idx_ud.begin(), idx_ud.end(),
|
||||
// [this](unsigned idx1, unsigned idx2)
|
||||
// {
|
||||
// const Vertex& v1 = emap_[idx1].first();
|
||||
// const Vertex& v2 = emap_[idx2].first();
|
||||
|
||||
// auto diff = getY(v1) - getY(v2);
|
||||
// if(std::abs(diff) <= std::numeric_limits<Coord>::epsilon())
|
||||
// return getX(v1) < getX(v2);
|
||||
|
||||
// return diff < 0;
|
||||
// });
|
||||
|
||||
// std::sort(idx_lr.begin(), idx_lr.end(),
|
||||
// [this](unsigned idx1, unsigned idx2)
|
||||
// {
|
||||
// const Vertex& v1 = emap_[idx1].first();
|
||||
// const Vertex& v2 = emap_[idx2].first();
|
||||
|
||||
// auto diff = getX(v1) - getX(v2);
|
||||
// if(std::abs(diff) <= std::numeric_limits<Coord>::epsilon())
|
||||
// return getY(v1) < getY(v2);
|
||||
|
||||
// return diff < 0;
|
||||
// });
|
||||
|
||||
// corners_[BOTTOM] = distances_[idx_ud.front()]/full_distance_;
|
||||
// corners_[TOP] = distances_[idx_ud.back()]/full_distance_;
|
||||
// corners_[LEFT] = distances_[idx_lr.front()]/full_distance_;
|
||||
// corners_[RIGHT] = distances_[idx_lr.back()]/full_distance_;
|
||||
for(auto& d : corners_) d /= full_distance_;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -167,12 +128,6 @@ public:
|
||||
|
||||
inline double circumference() const BP2D_NOEXCEPT { return full_distance_; }
|
||||
|
||||
// inline double corner(Corners c) const BP2D_NOEXCEPT {
|
||||
// assert(c < NUM_CORNERS);
|
||||
// fetchCorners();
|
||||
// return corners_[c];
|
||||
// }
|
||||
|
||||
inline const std::vector<double>& corners() const BP2D_NOEXCEPT {
|
||||
fetchCorners();
|
||||
return corners_;
|
||||
@ -400,7 +355,7 @@ public:
|
||||
|
||||
opt::StopCriteria stopcr;
|
||||
stopcr.max_iterations = 1000;
|
||||
stopcr.stoplimit = 0.01;
|
||||
stopcr.stoplimit = 0.001;
|
||||
stopcr.type = opt::StopLimitType::RELATIVE;
|
||||
opt::TOptimizer<opt::Method::L_SIMPLEX> solver(stopcr);
|
||||
|
||||
@ -518,11 +473,37 @@ private:
|
||||
|
||||
void setInitialPosition(Item& item) {
|
||||
Box&& bb = item.boundingBox();
|
||||
Vertex ci, cb;
|
||||
|
||||
Vertex ci = bb.minCorner();
|
||||
Vertex cb = bin_.minCorner();
|
||||
switch(config_.starting_point) {
|
||||
case Config::Alignment::CENTER: {
|
||||
ci = bb.center();
|
||||
cb = bin_.center();
|
||||
break;
|
||||
}
|
||||
case Config::Alignment::BOTTOM_LEFT: {
|
||||
ci = bb.minCorner();
|
||||
cb = bin_.minCorner();
|
||||
break;
|
||||
}
|
||||
case Config::Alignment::BOTTOM_RIGHT: {
|
||||
ci = {getX(bb.maxCorner()), getY(bb.minCorner())};
|
||||
cb = {getX(bin_.maxCorner()), getY(bin_.minCorner())};
|
||||
break;
|
||||
}
|
||||
case Config::Alignment::TOP_LEFT: {
|
||||
ci = {getX(bb.minCorner()), getY(bb.maxCorner())};
|
||||
cb = {getX(bin_.minCorner()), getY(bin_.maxCorner())};
|
||||
break;
|
||||
}
|
||||
case Config::Alignment::TOP_RIGHT: {
|
||||
ci = bb.maxCorner();
|
||||
cb = bin_.maxCorner();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto&& d = cb - ci;
|
||||
auto d = cb - ci;
|
||||
item.translate(d);
|
||||
}
|
||||
|
||||
|
@ -41,11 +41,24 @@ public:
|
||||
struct Config {
|
||||
|
||||
/**
|
||||
* If true, the algorithm will try to place pair and driplets in all
|
||||
* possible order.
|
||||
* If true, the algorithm will try to place pair and triplets in all
|
||||
* possible order. It will have a hugely negative impact on performance.
|
||||
*/
|
||||
bool try_reverse_order = true;
|
||||
|
||||
/**
|
||||
* @brief try_pairs Whether to try pairs of items to pack. It will add
|
||||
* a quadratic component to the complexity.
|
||||
*/
|
||||
bool try_pairs = true;
|
||||
|
||||
/**
|
||||
* @brief Whether to try groups of 3 items to pack. This could be very
|
||||
* slow for large number of items (>100) as it adds a cubic component
|
||||
* to the complexity.
|
||||
*/
|
||||
bool try_triplets = false;
|
||||
|
||||
/**
|
||||
* The initial fill proportion of the bin area that will be filled before
|
||||
* trying items one by one, or pairs or triplets.
|
||||
@ -151,8 +164,8 @@ public:
|
||||
return std::any_of(wrong_pairs.begin(), wrong_pairs.end(),
|
||||
[&i1, &i2](const TPair& pair)
|
||||
{
|
||||
Item& pi1 = std::get<0>(pair), pi2 = std::get<1>(pair);
|
||||
Item& ri1 = i1, ri2 = i2;
|
||||
Item& pi1 = std::get<0>(pair), &pi2 = std::get<1>(pair);
|
||||
Item& ri1 = i1, &ri2 = i2;
|
||||
return (&pi1 == &ri1 && &pi2 == &ri2) ||
|
||||
(&pi1 == &ri2 && &pi2 == &ri1);
|
||||
});
|
||||
@ -172,7 +185,7 @@ public:
|
||||
Item& pi1 = std::get<0>(tripl);
|
||||
Item& pi2 = std::get<1>(tripl);
|
||||
Item& pi3 = std::get<2>(tripl);
|
||||
Item& ri1 = i1, ri2 = i2, ri3 = i3;
|
||||
Item& ri1 = i1, &ri2 = i2, &ri3 = i3;
|
||||
return (&pi1 == &ri1 && &pi2 == &ri2 && &pi3 == &ri3) ||
|
||||
(&pi1 == &ri1 && &pi2 == &ri3 && &pi3 == &ri2) ||
|
||||
(&pi1 == &ri2 && &pi2 == &ri1 && &pi3 == &ri3) ||
|
||||
@ -348,6 +361,10 @@ public:
|
||||
// Will be true if a succesfull pack can be made.
|
||||
bool ret = false;
|
||||
|
||||
auto area = [](const ItemListIt& it) {
|
||||
return it->get().area();
|
||||
};
|
||||
|
||||
while (it != endit && !ret) { // drill down 1st level
|
||||
|
||||
// We need to determine in each iteration the largest, second
|
||||
@ -361,7 +378,7 @@ public:
|
||||
|
||||
// Check if there is enough free area for the item and the two
|
||||
// largest item
|
||||
if(free_area - it->get().area() - area_of_two_largest > waste)
|
||||
if(free_area - area(it) - area_of_two_largest > waste)
|
||||
break;
|
||||
|
||||
// Determine the area of the two smallest item.
|
||||
@ -373,7 +390,7 @@ public:
|
||||
double area_of_two_smallest =
|
||||
smallest.area() + second_smallest.area();
|
||||
|
||||
if(it->get().area() + area_of_two_smallest > free_area) {
|
||||
if(area(it) + area_of_two_smallest > free_area) {
|
||||
it++; continue;
|
||||
}
|
||||
|
||||
@ -384,16 +401,18 @@ public:
|
||||
|
||||
it2 = not_packed.begin();
|
||||
double rem2_area = free_area - largest.area();
|
||||
double a2_sum = it->get().area() + it2->get().area();
|
||||
double a2_sum = 0;
|
||||
|
||||
while(it2 != endit && !ret &&
|
||||
rem2_area - a2_sum <= waste) { // Drill down level 2
|
||||
rem2_area - (a2_sum = area(it) + area(it2)) <= waste) {
|
||||
// Drill down level 2
|
||||
|
||||
if(a2_sum != area(it) + area(it2)) throw -1;
|
||||
|
||||
if(it == it2 || check_pair(wrong_pairs, *it, *it2)) {
|
||||
it2++; continue;
|
||||
}
|
||||
|
||||
a2_sum = it->get().area() + it2->get().area();
|
||||
if(a2_sum + smallest.area() > free_area) {
|
||||
it2++; continue;
|
||||
}
|
||||
@ -429,14 +448,13 @@ public:
|
||||
// The 'smallest' variable now could be identical with
|
||||
// it2 but we don't bother with that
|
||||
|
||||
if(!can_pack2) { it2++; continue; }
|
||||
|
||||
it3 = not_packed.begin();
|
||||
|
||||
double a3_sum = a2_sum + it3->get().area();
|
||||
double a3_sum = 0;
|
||||
|
||||
while(it3 != endit && !ret &&
|
||||
free_area - a3_sum <= waste) { // 3rd level
|
||||
free_area - (a3_sum = a2_sum + area(it3)) <= waste) {
|
||||
// 3rd level
|
||||
|
||||
if(it3 == it || it3 == it2 ||
|
||||
check_triplet(wrong_triplets, *it, *it2, *it3))
|
||||
@ -560,8 +578,11 @@ public:
|
||||
|
||||
if(do_parallel) dout() << "Parallel execution..." << "\n";
|
||||
|
||||
bool do_pairs = config_.try_pairs;
|
||||
bool do_triplets = config_.try_triplets;
|
||||
|
||||
// The DJD heuristic algorithm itself:
|
||||
auto packjob = [INITIAL_FILL_AREA, bin_area, w,
|
||||
auto packjob = [INITIAL_FILL_AREA, bin_area, w, do_triplets, do_pairs,
|
||||
&tryOneByOne,
|
||||
&tryGroupsOfTwo,
|
||||
&tryGroupsOfThree,
|
||||
@ -573,7 +594,7 @@ public:
|
||||
double waste = .0;
|
||||
bool lasttry = false;
|
||||
|
||||
while(!not_packed.empty() ) {
|
||||
while(!not_packed.empty()) {
|
||||
|
||||
{// Fill the bin up to INITIAL_FILL_PROPORTION of its capacity
|
||||
auto it = not_packed.begin();
|
||||
@ -594,26 +615,25 @@ public:
|
||||
// try pieses one by one
|
||||
while(tryOneByOne(placer, not_packed, waste, free_area,
|
||||
filled_area)) {
|
||||
if(lasttry) std::cout << "Lasttry monopack" << std::endl;
|
||||
waste = 0; lasttry = false;
|
||||
makeProgress(placer, idx, 1);
|
||||
}
|
||||
|
||||
// try groups of 2 pieses
|
||||
while(tryGroupsOfTwo(placer, not_packed, waste, free_area,
|
||||
while(do_pairs &&
|
||||
tryGroupsOfTwo(placer, not_packed, waste, free_area,
|
||||
filled_area)) {
|
||||
if(lasttry) std::cout << "Lasttry bipack" << std::endl;
|
||||
waste = 0; lasttry = false;
|
||||
makeProgress(placer, idx, 2);
|
||||
}
|
||||
|
||||
// // try groups of 3 pieses
|
||||
// while(tryGroupsOfThree(placer, not_packed, waste, free_area,
|
||||
// filled_area)) {
|
||||
// if(lasttry) std::cout << "Lasttry tripack" << std::endl;
|
||||
// waste = 0; lasttry = false;
|
||||
// makeProgress(placer, idx, 3);
|
||||
// }
|
||||
// try groups of 3 pieses
|
||||
while(do_triplets &&
|
||||
tryGroupsOfThree(placer, not_packed, waste, free_area,
|
||||
filled_area)) {
|
||||
waste = 0; lasttry = false;
|
||||
makeProgress(placer, idx, 3);
|
||||
}
|
||||
|
||||
waste += w;
|
||||
if(!lasttry && waste > free_area) lasttry = true;
|
||||
|
@ -55,6 +55,18 @@ public:
|
||||
this->progress_(--total);
|
||||
};
|
||||
|
||||
// Safety test: try to pack each item into an empty bin. If it fails
|
||||
// then it should be removed from the not_packed list
|
||||
{ auto it = store_.begin();
|
||||
while (it != store_.end()) {
|
||||
Placer p(bin);
|
||||
if(!p.pack(*it)) {
|
||||
auto itmp = it++;
|
||||
store_.erase(itmp);
|
||||
} else it++;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& item : store_ ) {
|
||||
bool was_packed = false;
|
||||
while(!was_packed) {
|
||||
|
@ -374,6 +374,12 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
||||
throw std::runtime_error(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
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 (! this->m_placeholder_parser_failed_templates.empty()) {
|
||||
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
|
||||
std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n";
|
||||
@ -403,10 +409,48 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
||||
// resets time estimator
|
||||
m_time_estimator.reset();
|
||||
m_time_estimator.set_dialect(print.config.gcode_flavor);
|
||||
// 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 && 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]);
|
||||
}
|
||||
// resets analyzer
|
||||
m_analyzer.reset();
|
||||
m_enable_analyzer = preview_data != nullptr;
|
||||
@ -569,6 +613,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
|
||||
m_cooling_buffer->set_current_extruder(initial_extruder_id);
|
||||
|
||||
// Emit machine envelope limits for the Marlin firmware.
|
||||
this->print_machine_envelope(file, print);
|
||||
|
||||
// Disable fan.
|
||||
if (! print.config.cooling.get_at(initial_extruder_id) || print.config.disable_fan_first_layers.get_at(initial_extruder_id))
|
||||
_write(file, m_writer.set_fan(0, true));
|
||||
@ -806,7 +853,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
_write(file, m_writer.postamble());
|
||||
|
||||
// calculates estimated printing time
|
||||
m_time_estimator.calculate_time();
|
||||
m_normal_time_estimator.calculate_time();
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.calculate_time();
|
||||
|
||||
// Get filament stats.
|
||||
print.filament_stats.clear();
|
||||
@ -814,13 +863,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
print.total_extruded_volume = 0.;
|
||||
print.total_weight = 0.;
|
||||
print.total_cost = 0.;
|
||||
print.estimated_print_time = m_time_estimator.get_time_hms();
|
||||
print.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms();
|
||||
print.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A";
|
||||
for (const Extruder &extruder : m_writer.extruders()) {
|
||||
double used_filament = extruder.used_filament();
|
||||
double extruded_volume = extruder.extruded_volume();
|
||||
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
|
||||
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
|
||||
print.filament_stats.insert(std::pair<size_t,float>(extruder.id(), used_filament));
|
||||
print.filament_stats.insert(std::pair<size_t, float>(extruder.id(), (float)used_filament));
|
||||
_write_format(file, "; filament used = %.1lfmm (%.1lfcm3)\n", used_filament, extruded_volume * 0.001);
|
||||
if (filament_weight > 0.) {
|
||||
print.total_weight = print.total_weight + filament_weight;
|
||||
@ -834,7 +884,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||
print.total_extruded_volume = print.total_extruded_volume + extruded_volume;
|
||||
}
|
||||
_write_format(file, "; total filament cost = %.1lf\n", print.total_cost);
|
||||
_write_format(file, "; estimated printing time = %s\n", m_time_estimator.get_time_hms().c_str());
|
||||
_write_format(file, "; estimated printing time (normal mode) = %s\n", m_normal_time_estimator.get_time_dhms().c_str());
|
||||
if (m_silent_time_estimator_enabled)
|
||||
_write_format(file, "; estimated printing time (silent mode) = %s\n", m_silent_time_estimator.get_time_dhms().c_str());
|
||||
|
||||
// Append full config.
|
||||
_write(file, "\n");
|
||||
@ -919,6 +971,35 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
|
||||
return temp_set_by_gcode;
|
||||
}
|
||||
|
||||
// Print the machine envelope G-code for the Marlin firmware based on the "machine_max_xxx" parameters.
|
||||
// Do not process this piece of G-code by the time estimator, it already knows the values through another sources.
|
||||
void GCode::print_machine_envelope(FILE *file, Print &print)
|
||||
{
|
||||
if (print.config.gcode_flavor.value == gcfMarlin) {
|
||||
fprintf(file, "M201 X%d Y%d Z%d E%d ; sets maximum accelerations, mm/sec^2\n",
|
||||
int(print.config.machine_max_acceleration_x.values.front() + 0.5),
|
||||
int(print.config.machine_max_acceleration_y.values.front() + 0.5),
|
||||
int(print.config.machine_max_acceleration_z.values.front() + 0.5),
|
||||
int(print.config.machine_max_acceleration_e.values.front() + 0.5));
|
||||
fprintf(file, "M203 X%d Y%d Z%d E%d ; sets maximum feedrates, mm/sec\n",
|
||||
int(print.config.machine_max_feedrate_x.values.front() + 0.5),
|
||||
int(print.config.machine_max_feedrate_y.values.front() + 0.5),
|
||||
int(print.config.machine_max_feedrate_z.values.front() + 0.5),
|
||||
int(print.config.machine_max_feedrate_e.values.front() + 0.5));
|
||||
fprintf(file, "M204 S%d T%d ; sets acceleration (S) and retract acceleration (T), mm/sec^2\n",
|
||||
int(print.config.machine_max_acceleration_extruding.values.front() + 0.5),
|
||||
int(print.config.machine_max_acceleration_retracting.values.front() + 0.5));
|
||||
fprintf(file, "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
|
||||
print.config.machine_max_jerk_x.values.front(),
|
||||
print.config.machine_max_jerk_y.values.front(),
|
||||
print.config.machine_max_jerk_z.values.front(),
|
||||
print.config.machine_max_jerk_e.values.front());
|
||||
fprintf(file, "M205 S%d T%d ; sets the minimum extruding and travel feed rate, mm/sec\n",
|
||||
int(print.config.machine_min_extruding_rate.values.front() + 0.5),
|
||||
int(print.config.machine_min_travel_rate.values.front() + 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
// Write 1st layer bed temperatures into the G-code.
|
||||
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
|
||||
// M140 - Set Extruder Temperature
|
||||
@ -1406,7 +1487,7 @@ void GCode::process_layer(
|
||||
if (m_pressure_equalizer)
|
||||
gcode = m_pressure_equalizer->process(gcode.c_str(), false);
|
||||
// printf("G-code after filter:\n%s\n", out.c_str());
|
||||
|
||||
|
||||
_write(file, gcode);
|
||||
}
|
||||
|
||||
@ -2073,7 +2154,9 @@ void GCode::_write(FILE* file, const char *what)
|
||||
// writes string to file
|
||||
fwrite(gcode, 1, ::strlen(gcode), file);
|
||||
// updates time estimator and gcode lines vector
|
||||
m_time_estimator.add_gcode_block(gcode);
|
||||
m_normal_time_estimator.add_gcode_block(gcode);
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.add_gcode_block(gcode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,6 +133,9 @@ public:
|
||||
m_last_height(GCodeAnalyzer::Default_Height),
|
||||
m_brim_done(false),
|
||||
m_second_layer_things_done(false),
|
||||
m_normal_time_estimator(GCodeTimeEstimator::Normal),
|
||||
m_silent_time_estimator(GCodeTimeEstimator::Silent),
|
||||
m_silent_time_estimator_enabled(false),
|
||||
m_last_obj_copy(nullptr, Point(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max()))
|
||||
{}
|
||||
~GCode() {}
|
||||
@ -303,8 +306,10 @@ protected:
|
||||
// Index of a last object copy extruded.
|
||||
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
||||
|
||||
// Time estimator
|
||||
GCodeTimeEstimator m_time_estimator;
|
||||
// Time estimators
|
||||
GCodeTimeEstimator m_normal_time_estimator;
|
||||
GCodeTimeEstimator m_silent_time_estimator;
|
||||
bool m_silent_time_estimator_enabled;
|
||||
|
||||
// Analyzer
|
||||
GCodeAnalyzer m_analyzer;
|
||||
@ -322,6 +327,7 @@ protected:
|
||||
void _write_format(FILE* file, const char* format, ...);
|
||||
|
||||
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
|
||||
void print_machine_envelope(FILE *file, Print &print);
|
||||
void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
void _print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
// this flag triggers first layer speeds
|
||||
|
@ -4,15 +4,20 @@
|
||||
|
||||
#include <Shiny/Shiny.h>
|
||||
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
|
||||
static const float MILLISEC_TO_SEC = 0.001f;
|
||||
static const float INCHES_TO_MM = 25.4f;
|
||||
|
||||
static const float DEFAULT_FEEDRATE = 1500.0f; // from Prusa Firmware (Marlin_main.cpp)
|
||||
static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
|
||||
static const float DEFAULT_RETRACT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
|
||||
static const float DEFAULT_AXIS_MAX_FEEDRATE[] = { 500.0f, 500.0f, 12.0f, 120.0f }; // Prusa Firmware 1_75mm_MK2
|
||||
static const float DEFAULT_AXIS_MAX_ACCELERATION[] = { 9000.0f, 9000.0f, 500.0f, 10000.0f }; // Prusa Firmware 1_75mm_MK2
|
||||
static const float DEFAULT_AXIS_MAX_JERK[] = { 10.0f, 10.0f, 0.2f, 2.5f }; // from Prusa Firmware (Configuration.h)
|
||||
static const float DEFAULT_AXIS_MAX_JERK[] = { 10.0f, 10.0f, 0.4f, 2.5f }; // from Prusa Firmware (Configuration.h)
|
||||
static const float DEFAULT_MINIMUM_FEEDRATE = 0.0f; // from Prusa Firmware (Configuration_adv.h)
|
||||
static const float DEFAULT_MINIMUM_TRAVEL_FEEDRATE = 0.0f; // from Prusa Firmware (Configuration_adv.h)
|
||||
static const float DEFAULT_EXTRUDE_FACTOR_OVERRIDE_PERCENTAGE = 1.0f; // 100 percent
|
||||
@ -73,6 +78,11 @@ namespace Slic3r {
|
||||
return ::sqrt(value);
|
||||
}
|
||||
|
||||
GCodeTimeEstimator::Block::Block()
|
||||
: st_synchronized(false)
|
||||
{
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::move_length() const
|
||||
{
|
||||
float length = ::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
|
||||
@ -159,63 +169,13 @@ namespace Slic3r {
|
||||
}
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
GCodeTimeEstimator::GCodeTimeEstimator()
|
||||
GCodeTimeEstimator::GCodeTimeEstimator(EMode mode)
|
||||
: _mode(mode)
|
||||
{
|
||||
reset();
|
||||
set_default();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode)
|
||||
{
|
||||
reset();
|
||||
|
||||
_parser.parse_buffer(gcode,
|
||||
[this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
|
||||
{ this->_process_gcode_line(reader, line); });
|
||||
|
||||
_calculate_time();
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
_reset_blocks();
|
||||
_reset();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::calculate_time_from_file(const std::string& file)
|
||||
{
|
||||
reset();
|
||||
|
||||
_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
||||
_calculate_time();
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
_reset_blocks();
|
||||
_reset();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::calculate_time_from_lines(const std::vector<std::string>& gcode_lines)
|
||||
{
|
||||
reset();
|
||||
|
||||
auto action = [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
|
||||
{ this->_process_gcode_line(reader, line); };
|
||||
for (const std::string& line : gcode_lines)
|
||||
_parser.parse_line(line, action);
|
||||
_calculate_time();
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
_reset_blocks();
|
||||
_reset();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::add_gcode_line(const std::string& gcode_line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
@ -239,14 +199,167 @@ namespace Slic3r {
|
||||
void GCodeTimeEstimator::calculate_time()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_reset_time();
|
||||
_set_blocks_st_synchronize(false);
|
||||
_calculate_time();
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
_reset_blocks();
|
||||
_reset();
|
||||
void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode)
|
||||
{
|
||||
reset();
|
||||
|
||||
_parser.parse_buffer(gcode,
|
||||
[this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
|
||||
{ this->_process_gcode_line(reader, line); });
|
||||
|
||||
_calculate_time();
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::calculate_time_from_file(const std::string& file)
|
||||
{
|
||||
reset();
|
||||
|
||||
_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
||||
_calculate_time();
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::calculate_time_from_lines(const std::vector<std::string>& gcode_lines)
|
||||
{
|
||||
reset();
|
||||
|
||||
auto action = [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
|
||||
{ this->_process_gcode_line(reader, line); };
|
||||
for (const std::string& line : gcode_lines)
|
||||
_parser.parse_line(line, action);
|
||||
_calculate_time();
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
bool GCodeTimeEstimator::post_process_remaining_times(const std::string& filename, float interval)
|
||||
{
|
||||
boost::nowide::ifstream in(filename);
|
||||
if (!in.good())
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for reading.\n"));
|
||||
|
||||
std::string path_tmp = filename + ".times";
|
||||
|
||||
FILE* out = boost::nowide::fopen(path_tmp.c_str(), "wb");
|
||||
if (out == nullptr)
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for writing.\n"));
|
||||
|
||||
std::string time_mask;
|
||||
switch (_mode)
|
||||
{
|
||||
default:
|
||||
case Normal:
|
||||
{
|
||||
time_mask = "M73 P%s R%s\n";
|
||||
break;
|
||||
}
|
||||
case Silent:
|
||||
{
|
||||
time_mask = "M73 Q%s S%s\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int g1_lines_count = 0;
|
||||
float last_recorded_time = 0.0f;
|
||||
std::string gcode_line;
|
||||
// buffer line to export only when greater than 64K to reduce writing calls
|
||||
std::string export_line;
|
||||
char time_line[64];
|
||||
while (std::getline(in, gcode_line))
|
||||
{
|
||||
if (!in.good())
|
||||
{
|
||||
fclose(out);
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nError while reading from file.\n"));
|
||||
}
|
||||
|
||||
gcode_line += "\n";
|
||||
|
||||
// add remaining time lines where needed
|
||||
_parser.parse_line(gcode_line,
|
||||
[this, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
if (line.cmd_is("G1"))
|
||||
{
|
||||
++g1_lines_count;
|
||||
|
||||
if (!line.has_e())
|
||||
return;
|
||||
|
||||
G1LineIdToBlockIdMap::const_iterator it = _g1_line_ids.find(g1_lines_count);
|
||||
if ((it != _g1_line_ids.end()) && (it->second < (unsigned int)_blocks.size()))
|
||||
{
|
||||
const Block& block = _blocks[it->second];
|
||||
if (block.elapsed_time != -1.0f)
|
||||
{
|
||||
float block_remaining_time = _time - block.elapsed_time;
|
||||
if (std::abs(last_recorded_time - block_remaining_time) > interval)
|
||||
{
|
||||
sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block.elapsed_time / _time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
|
||||
gcode_line += time_line;
|
||||
|
||||
last_recorded_time = block_remaining_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export_line += gcode_line;
|
||||
if (export_line.length() > 65535)
|
||||
{
|
||||
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
|
||||
if (ferror(out))
|
||||
{
|
||||
in.close();
|
||||
fclose(out);
|
||||
boost::nowide::remove(path_tmp.c_str());
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nIs the disk full?\n"));
|
||||
}
|
||||
export_line.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (export_line.length() > 0)
|
||||
{
|
||||
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
|
||||
if (ferror(out))
|
||||
{
|
||||
in.close();
|
||||
fclose(out);
|
||||
boost::nowide::remove(path_tmp.c_str());
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nIs the disk full?\n"));
|
||||
}
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
in.close();
|
||||
|
||||
boost::nowide::remove(filename.c_str());
|
||||
if (boost::nowide::rename(path_tmp.c_str(), filename.c_str()) != 0)
|
||||
throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' +
|
||||
"Is " + path_tmp + " locked?" + '\n');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_axis_position(EAxis axis, float position)
|
||||
@ -389,6 +502,21 @@ namespace Slic3r {
|
||||
return _state.e_local_positioning_type;
|
||||
}
|
||||
|
||||
int GCodeTimeEstimator::get_g1_line_id() const
|
||||
{
|
||||
return _state.g1_line_id;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::increment_g1_line_id()
|
||||
{
|
||||
++_state.g1_line_id;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::reset_g1_line_id()
|
||||
{
|
||||
_state.g1_line_id = 0;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::add_additional_time(float timeSec)
|
||||
{
|
||||
_state.additional_time += timeSec;
|
||||
@ -417,7 +545,7 @@ namespace Slic3r {
|
||||
set_minimum_feedrate(DEFAULT_MINIMUM_FEEDRATE);
|
||||
set_minimum_travel_feedrate(DEFAULT_MINIMUM_TRAVEL_FEEDRATE);
|
||||
set_extrude_factor_override_percentage(DEFAULT_EXTRUDE_FACTOR_OVERRIDE_PERCENTAGE);
|
||||
|
||||
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
EAxis axis = (EAxis)a;
|
||||
@ -429,7 +557,7 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::reset()
|
||||
{
|
||||
_time = 0.0f;
|
||||
_reset_time();
|
||||
#if ENABLE_MOVE_STATS
|
||||
_moves_stats.clear();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
@ -442,23 +570,14 @@ namespace Slic3r {
|
||||
return _time;
|
||||
}
|
||||
|
||||
std::string GCodeTimeEstimator::get_time_hms() const
|
||||
std::string GCodeTimeEstimator::get_time_dhms() const
|
||||
{
|
||||
float timeinsecs = get_time();
|
||||
int hours = (int)(timeinsecs / 3600.0f);
|
||||
timeinsecs -= (float)hours * 3600.0f;
|
||||
int minutes = (int)(timeinsecs / 60.0f);
|
||||
timeinsecs -= (float)minutes * 60.0f;
|
||||
return _get_time_dhms(get_time());
|
||||
}
|
||||
|
||||
char buffer[64];
|
||||
if (hours > 0)
|
||||
::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)timeinsecs);
|
||||
else if (minutes > 0)
|
||||
::sprintf(buffer, "%dm %ds", minutes, (int)timeinsecs);
|
||||
else
|
||||
::sprintf(buffer, "%ds", (int)timeinsecs);
|
||||
|
||||
return buffer;
|
||||
std::string GCodeTimeEstimator::get_time_minutes() const
|
||||
{
|
||||
return _get_time_minutes(get_time());
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_reset()
|
||||
@ -471,6 +590,14 @@ namespace Slic3r {
|
||||
set_axis_position(Z, 0.0f);
|
||||
|
||||
set_additional_time(0.0f);
|
||||
|
||||
reset_g1_line_id();
|
||||
_g1_line_ids.clear();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_reset_time()
|
||||
{
|
||||
_time = 0.0f;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_reset_blocks()
|
||||
@ -478,6 +605,14 @@ namespace Slic3r {
|
||||
_blocks.clear();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_set_blocks_st_synchronize(bool state)
|
||||
{
|
||||
for (Block& block : _blocks)
|
||||
{
|
||||
block.st_synchronized = state;
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_calculate_time()
|
||||
{
|
||||
_forward_pass();
|
||||
@ -486,14 +621,18 @@ namespace Slic3r {
|
||||
|
||||
_time += get_additional_time();
|
||||
|
||||
for (const Block& block : _blocks)
|
||||
for (Block& block : _blocks)
|
||||
{
|
||||
if (block.st_synchronized)
|
||||
continue;
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
float block_time = 0.0f;
|
||||
block_time += block.acceleration_time();
|
||||
block_time += block.cruise_time();
|
||||
block_time += block.deceleration_time();
|
||||
_time += block_time;
|
||||
block.elapsed_time = _time;
|
||||
|
||||
MovesStatsMap::iterator it = _moves_stats.find(block.move_type);
|
||||
if (it == _moves_stats.end())
|
||||
@ -505,6 +644,7 @@ namespace Slic3r {
|
||||
_time += block.acceleration_time();
|
||||
_time += block.cruise_time();
|
||||
_time += block.deceleration_time();
|
||||
block.elapsed_time = _time;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
}
|
||||
@ -642,6 +782,8 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processG1(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
increment_g1_line_id();
|
||||
|
||||
// updates axes positions from line
|
||||
EUnits units = get_units();
|
||||
float new_pos[Num_Axis];
|
||||
@ -690,13 +832,16 @@ namespace Slic3r {
|
||||
if (_curr.abs_axis_feedrate[a] > 0.0f)
|
||||
min_feedrate_factor = std::min(min_feedrate_factor, get_axis_max_feedrate((EAxis)a) / _curr.abs_axis_feedrate[a]);
|
||||
}
|
||||
|
||||
|
||||
block.feedrate.cruise = min_feedrate_factor * _curr.feedrate;
|
||||
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
if (min_feedrate_factor < 1.0f)
|
||||
{
|
||||
_curr.axis_feedrate[a] *= min_feedrate_factor;
|
||||
_curr.abs_axis_feedrate[a] *= min_feedrate_factor;
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
_curr.axis_feedrate[a] *= min_feedrate_factor;
|
||||
_curr.abs_axis_feedrate[a] *= min_feedrate_factor;
|
||||
}
|
||||
}
|
||||
|
||||
// calculates block acceleration
|
||||
@ -829,6 +974,7 @@ namespace Slic3r {
|
||||
|
||||
// adds block to blocks list
|
||||
_blocks.emplace_back(block);
|
||||
_g1_line_ids.insert(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)_blocks.size() - 1));
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line)
|
||||
@ -1043,7 +1189,7 @@ namespace Slic3r {
|
||||
void GCodeTimeEstimator::_simulate_st_synchronize()
|
||||
{
|
||||
_calculate_time();
|
||||
_reset_blocks();
|
||||
_set_blocks_st_synchronize(true);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_forward_pass()
|
||||
@ -1051,7 +1197,10 @@ namespace Slic3r {
|
||||
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;
|
||||
|
||||
_planner_forward_pass_kernel(_blocks[i], _blocks[i + 1]);
|
||||
}
|
||||
}
|
||||
@ -1063,6 +1212,9 @@ namespace Slic3r {
|
||||
{
|
||||
for (int i = (int)_blocks.size() - 1; i >= 1; --i)
|
||||
{
|
||||
if (_blocks[i - 1].st_synchronized || _blocks[i].st_synchronized)
|
||||
continue;
|
||||
|
||||
_planner_reverse_pass_kernel(_blocks[i - 1], _blocks[i]);
|
||||
}
|
||||
}
|
||||
@ -1115,6 +1267,9 @@ namespace Slic3r {
|
||||
|
||||
for (Block& b : _blocks)
|
||||
{
|
||||
if (b.st_synchronized)
|
||||
continue;
|
||||
|
||||
curr = next;
|
||||
next = &b;
|
||||
|
||||
@ -1144,6 +1299,33 @@ namespace Slic3r {
|
||||
}
|
||||
}
|
||||
|
||||
std::string GCodeTimeEstimator::_get_time_dhms(float time_in_secs)
|
||||
{
|
||||
int days = (int)(time_in_secs / 86400.0f);
|
||||
time_in_secs -= (float)days * 86400.0f;
|
||||
int hours = (int)(time_in_secs / 3600.0f);
|
||||
time_in_secs -= (float)hours * 3600.0f;
|
||||
int minutes = (int)(time_in_secs / 60.0f);
|
||||
time_in_secs -= (float)minutes * 60.0f;
|
||||
|
||||
char buffer[64];
|
||||
if (days > 0)
|
||||
::sprintf(buffer, "%dd %dh %dm %ds", days, hours, minutes, (int)time_in_secs);
|
||||
else if (hours > 0)
|
||||
::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)time_in_secs);
|
||||
else if (minutes > 0)
|
||||
::sprintf(buffer, "%dm %ds", minutes, (int)time_in_secs);
|
||||
else
|
||||
::sprintf(buffer, "%ds", (int)time_in_secs);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string GCodeTimeEstimator::_get_time_minutes(float time_in_secs)
|
||||
{
|
||||
return std::to_string((int)(::roundf(time_in_secs / 60.0f)));
|
||||
}
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
void GCodeTimeEstimator::_log_moves_stats() const
|
||||
{
|
||||
|
@ -17,6 +17,12 @@ namespace Slic3r {
|
||||
class GCodeTimeEstimator
|
||||
{
|
||||
public:
|
||||
enum EMode : unsigned char
|
||||
{
|
||||
Normal,
|
||||
Silent
|
||||
};
|
||||
|
||||
enum EUnits : unsigned char
|
||||
{
|
||||
Millimeters,
|
||||
@ -70,7 +76,8 @@ namespace Slic3r {
|
||||
float additional_time; // s
|
||||
float minimum_feedrate; // mm/s
|
||||
float minimum_travel_feedrate; // mm/s
|
||||
float extrude_factor_override_percentage;
|
||||
float extrude_factor_override_percentage;
|
||||
unsigned int g1_line_id;
|
||||
};
|
||||
|
||||
public:
|
||||
@ -121,7 +128,6 @@ namespace Slic3r {
|
||||
bool nominal_length;
|
||||
};
|
||||
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
EMoveType move_type;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
@ -134,6 +140,11 @@ namespace Slic3r {
|
||||
|
||||
FeedrateProfile feedrate;
|
||||
Trapezoid trapezoid;
|
||||
float elapsed_time;
|
||||
|
||||
bool st_synchronized;
|
||||
|
||||
Block();
|
||||
|
||||
// Returns the length of the move covered by this block, in mm
|
||||
float move_length() const;
|
||||
@ -187,19 +198,34 @@ namespace Slic3r {
|
||||
typedef std::map<Block::EMoveType, MoveStats> MovesStatsMap;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
typedef std::map<unsigned int, unsigned int> G1LineIdToBlockIdMap;
|
||||
|
||||
private:
|
||||
EMode _mode;
|
||||
GCodeReader _parser;
|
||||
State _state;
|
||||
Feedrates _curr;
|
||||
Feedrates _prev;
|
||||
BlocksList _blocks;
|
||||
// Map between g1 line id and blocks id, used to speed up export of remaining times
|
||||
G1LineIdToBlockIdMap _g1_line_ids;
|
||||
float _time; // s
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
MovesStatsMap _moves_stats;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
public:
|
||||
GCodeTimeEstimator();
|
||||
explicit GCodeTimeEstimator(EMode mode);
|
||||
|
||||
// Adds the given gcode line
|
||||
void add_gcode_line(const std::string& gcode_line);
|
||||
|
||||
void add_gcode_block(const char *ptr);
|
||||
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();
|
||||
|
||||
// Calculates the time estimate from the given gcode in string format
|
||||
void calculate_time_from_text(const std::string& gcode);
|
||||
@ -210,14 +236,12 @@ namespace Slic3r {
|
||||
// Calculates the time estimate from the gcode contained in given list of gcode lines
|
||||
void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
|
||||
|
||||
// Adds the given gcode line
|
||||
void add_gcode_line(const std::string& gcode_line);
|
||||
|
||||
void add_gcode_block(const char *ptr);
|
||||
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()
|
||||
void calculate_time();
|
||||
// Process the gcode contained in the file with the given filename,
|
||||
// placing in it new lines (M73) containing the remaining time, at the given interval in seconds
|
||||
// and saving the result back in the same file
|
||||
// This time estimator should have been already used to calculate the time estimate for the gcode
|
||||
// contained in the given file before to call this method
|
||||
bool post_process_remaining_times(const std::string& filename, float interval_sec);
|
||||
|
||||
// Set current position on the given axis with the given value
|
||||
void set_axis_position(EAxis axis, float position);
|
||||
@ -263,6 +287,10 @@ namespace Slic3r {
|
||||
void set_e_local_positioning_type(EPositioningType type);
|
||||
EPositioningType get_e_local_positioning_type() const;
|
||||
|
||||
int get_g1_line_id() const;
|
||||
void increment_g1_line_id();
|
||||
void reset_g1_line_id();
|
||||
|
||||
void add_additional_time(float timeSec);
|
||||
void set_additional_time(float timeSec);
|
||||
float get_additional_time() const;
|
||||
@ -275,13 +303,19 @@ namespace Slic3r {
|
||||
// Returns the estimated time, in seconds
|
||||
float get_time() const;
|
||||
|
||||
// Returns the estimated time, in format HHh MMm SSs
|
||||
std::string get_time_hms() const;
|
||||
// Returns the estimated time, in format DDd HHh MMm SSs
|
||||
std::string get_time_dhms() const;
|
||||
|
||||
// Returns the estimated time, in minutes (integer)
|
||||
std::string get_time_minutes() const;
|
||||
|
||||
private:
|
||||
void _reset();
|
||||
void _reset_time();
|
||||
void _reset_blocks();
|
||||
|
||||
void _set_blocks_st_synchronize(bool state);
|
||||
|
||||
// Calculates the time estimate
|
||||
void _calculate_time();
|
||||
|
||||
@ -353,6 +387,12 @@ namespace Slic3r {
|
||||
|
||||
void _recalculate_trapezoids();
|
||||
|
||||
// Returns the given time is seconds in format DDd HHh MMm SSs
|
||||
static std::string _get_time_dhms(float time_in_secs);
|
||||
|
||||
// Returns the given, in minutes (integer)
|
||||
static std::string _get_time_minutes(float time_in_secs);
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
void _log_moves_stats() const;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
// #include <benchmark.h>
|
||||
#include "SVG.hpp"
|
||||
#include <Eigen/Dense>
|
||||
|
||||
@ -309,7 +308,7 @@ namespace arr {
|
||||
|
||||
using namespace libnest2d;
|
||||
|
||||
std::string toString(const Model& model) {
|
||||
std::string toString(const Model& model, bool holes = true) {
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "{\n";
|
||||
@ -348,17 +347,17 @@ std::string toString(const Model& model) {
|
||||
|
||||
// Holes:
|
||||
ss << "\t\t{\n";
|
||||
// for(auto h : expoly.holes) {
|
||||
// ss << "\t\t\t{\n";
|
||||
// for(auto v : h.points) ss << "\t\t\t\t{"
|
||||
// << v.x << ", "
|
||||
// << v.y << "},\n";
|
||||
// {
|
||||
// auto v = h.points.front();
|
||||
// ss << "\t\t\t\t{" << v.x << ", " << v.y << "},\n";
|
||||
// }
|
||||
// ss << "\t\t\t},\n";
|
||||
// }
|
||||
if(holes) for(auto h : expoly.holes) {
|
||||
ss << "\t\t\t{\n";
|
||||
for(auto v : h.points) ss << "\t\t\t\t{"
|
||||
<< v.x << ", "
|
||||
<< v.y << "},\n";
|
||||
{
|
||||
auto v = h.points.front();
|
||||
ss << "\t\t\t\t{" << v.x << ", " << v.y << "},\n";
|
||||
}
|
||||
ss << "\t\t\t},\n";
|
||||
}
|
||||
ss << "\t\t},\n";
|
||||
|
||||
ss << "\t},\n";
|
||||
@ -477,58 +476,21 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
||||
// Create the arranger config
|
||||
auto min_obj_distance = static_cast<Coord>(dist/SCALING_FACTOR);
|
||||
|
||||
// Benchmark bench;
|
||||
|
||||
// std::cout << "Creating model siluett..." << std::endl;
|
||||
|
||||
// bench.start();
|
||||
// Get the 2D projected shapes with their 3D model instance pointers
|
||||
auto shapemap = arr::projectModelFromTop(model);
|
||||
// bench.stop();
|
||||
|
||||
// std::cout << "Model siluett created in " << bench.getElapsedSec()
|
||||
// << " seconds. " << "Min object distance = " << min_obj_distance << std::endl;
|
||||
|
||||
// std::cout << "{" << std::endl;
|
||||
// std::for_each(shapemap.begin(), shapemap.end(),
|
||||
// [] (ShapeData2D::value_type& it)
|
||||
// {
|
||||
// std::cout << "\t{" << std::endl;
|
||||
// Item& item = it.second;
|
||||
// for(auto& v : item) {
|
||||
// std::cout << "\t\t" << "{" << getX(v)
|
||||
// << ", " << getY(v) << "},\n";
|
||||
// }
|
||||
// std::cout << "\t}," << std::endl;
|
||||
// });
|
||||
// std::cout << "}" << std::endl;
|
||||
// return true;
|
||||
|
||||
bool hasbin = bb != nullptr && bb->defined;
|
||||
double area_max = 0;
|
||||
Item *biggest = nullptr;
|
||||
|
||||
// Copy the references for the shapes only as the arranger expects a
|
||||
// sequence of objects convertible to Item or ClipperPolygon
|
||||
std::vector<std::reference_wrapper<Item>> shapes;
|
||||
shapes.reserve(shapemap.size());
|
||||
std::for_each(shapemap.begin(), shapemap.end(),
|
||||
[&shapes, min_obj_distance, &area_max, &biggest,hasbin]
|
||||
[&shapes, min_obj_distance, &area_max, hasbin]
|
||||
(ShapeData2D::value_type& it)
|
||||
{
|
||||
if(!hasbin) {
|
||||
Item& item = it.second;
|
||||
item.addOffset(min_obj_distance);
|
||||
auto b = ShapeLike::boundingBox(item.transformedShape());
|
||||
auto a = b.width()*b.height();
|
||||
if(area_max < a) {
|
||||
area_max = static_cast<double>(a);
|
||||
biggest = &item;
|
||||
}
|
||||
}
|
||||
|
||||
shapes.push_back(std::ref(it.second));
|
||||
|
||||
});
|
||||
|
||||
Box bin;
|
||||
@ -546,9 +508,6 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
||||
static_cast<libnest2d::Coord>(bbb.max.x),
|
||||
static_cast<libnest2d::Coord>(bbb.max.y)
|
||||
});
|
||||
} else {
|
||||
// Just take the biggest item as bin... ?
|
||||
bin = ShapeLike::boundingBox(biggest->transformedShape());
|
||||
}
|
||||
|
||||
// Will use the DJD selection heuristic with the BottomLeft placement
|
||||
@ -563,20 +522,22 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
||||
// Align the arranged pile into the center of the bin
|
||||
pcfg.alignment = PConf::Alignment::CENTER;
|
||||
|
||||
// Start placing the items from the center of the print bed
|
||||
pcfg.starting_point = PConf::Alignment::CENTER;
|
||||
|
||||
// TODO cannot use rotations until multiple objects of same geometry can
|
||||
// handle different rotations
|
||||
// arranger.useMinimumBoundigBoxRotation();
|
||||
pcfg.rotations = { 0.0 };
|
||||
|
||||
// Magic: we will specify what is the goal of arrangement...
|
||||
// In this case we override the default object function because we
|
||||
// (apparently) don't care about pack efficiency and all we care is that 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.
|
||||
// As a side effect, the arrange procedure is a lot faster (we do not need
|
||||
// to calculate the convex hulls)
|
||||
pcfg.object_function = [&bin](
|
||||
// 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
|
||||
// calculate the convex hulls)
|
||||
pcfg.object_function = [bin, hasbin](
|
||||
NfpPlacer::Pile pile, // The currently arranged pile
|
||||
double /*area*/, // Sum area of items (not needed)
|
||||
double norm, // A norming factor for physical dimensions
|
||||
@ -584,14 +545,25 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
||||
{
|
||||
auto bb = ShapeLike::boundingBox(pile);
|
||||
|
||||
// We will optimize to the diameter of the circle around the bounding
|
||||
// box and use the norming factor to get rid of the physical dimensions
|
||||
double score = PointLike::distance(bb.minCorner(),
|
||||
bb.maxCorner()) / norm;
|
||||
// We get the current item that's being evaluated.
|
||||
auto& sh = pile.back();
|
||||
|
||||
// We retrieve the reference point of this item
|
||||
auto rv = Nfp::referenceVertex(sh);
|
||||
|
||||
// We get the distance of the reference point from the center of the
|
||||
// heat bed
|
||||
auto c = bin.center();
|
||||
auto d = PointLike::distance(rv, c);
|
||||
|
||||
// The score will be the normalized distance which will be minimized,
|
||||
// effectively creating a circle shaped pile of items
|
||||
double score = double(d)/norm;
|
||||
|
||||
// If it does not fit into the print bed we will beat it
|
||||
// with a large penality
|
||||
if(!NfpPlacer::wouldFit(bb, bin)) score = 2*penality - score;
|
||||
// with a large penality. If we would not do this, there would be only
|
||||
// one big pile that doesn't care whether it fits onto the print bed.
|
||||
if(hasbin && !NfpPlacer::wouldFit(bb, bin)) score = 2*penality - score;
|
||||
|
||||
return score;
|
||||
};
|
||||
@ -602,18 +574,10 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
||||
// Set the progress indicator for the arranger.
|
||||
arranger.progressIndicator(progressind);
|
||||
|
||||
// std::cout << "Arranging model..." << std::endl;
|
||||
// bench.start();
|
||||
|
||||
// Arrange and return the items with their respective indices within the
|
||||
// input sequence.
|
||||
auto result = arranger.arrangeIndexed(shapes.begin(), shapes.end());
|
||||
|
||||
// bench.stop();
|
||||
// std::cout << "Model arranged in " << bench.getElapsedSec()
|
||||
// << " seconds." << std::endl;
|
||||
|
||||
|
||||
auto applyResult = [&shapemap](ArrangeResult::value_type& group,
|
||||
Coord batch_offset)
|
||||
{
|
||||
@ -637,8 +601,6 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
||||
}
|
||||
};
|
||||
|
||||
// std::cout << "Applying result..." << std::endl;
|
||||
// bench.start();
|
||||
if(first_bin_only) {
|
||||
applyResult(result.front(), 0);
|
||||
} else {
|
||||
@ -658,9 +620,6 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
|
||||
batch_offset += stride;
|
||||
}
|
||||
}
|
||||
// bench.stop();
|
||||
// std::cout << "Result applied in " << bench.getElapsedSec()
|
||||
// << " seconds." << std::endl;
|
||||
|
||||
for(auto objptr : model.objects) objptr->invalidate_bounding_box();
|
||||
|
||||
@ -675,16 +634,11 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb,
|
||||
{
|
||||
bool ret = false;
|
||||
if(bb != nullptr && bb->defined) {
|
||||
// Despite the new arrange is able to run without a specified bin,
|
||||
// the perl testsuit still fails for this case. For now the safest
|
||||
// thing to do is to use the new arrange only when a proper bin is
|
||||
// specified.
|
||||
ret = arr::arrange(*this, dist, bb, false, progressind);
|
||||
// std::fstream out("out.cpp", std::fstream::out);
|
||||
// if(out.good()) {
|
||||
// out << "const TestData OBJECTS = \n";
|
||||
// out << arr::toString(*this);
|
||||
// }
|
||||
// out.close();
|
||||
// SVG svg("out.svg");
|
||||
// arr::toSVG(svg, *this);
|
||||
// svg.Close();
|
||||
} else {
|
||||
// get the (transformed) size of each instance so that we take
|
||||
// into account their different transformations when packing
|
||||
|
@ -236,7 +236,8 @@ public:
|
||||
PrintRegionPtrs regions;
|
||||
PlaceholderParser placeholder_parser;
|
||||
// TODO: status_cb
|
||||
std::string estimated_print_time;
|
||||
std::string estimated_normal_print_time;
|
||||
std::string estimated_silent_print_time;
|
||||
double total_used_filament, total_extruded_volume, total_cost, total_weight;
|
||||
std::map<size_t, float> filament_stats;
|
||||
PrintState<PrintStep, psCount> state;
|
||||
|
@ -291,11 +291,11 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->enum_values.push_back("hilbertcurve");
|
||||
def->enum_values.push_back("archimedeanchords");
|
||||
def->enum_values.push_back("octagramspiral");
|
||||
def->enum_labels.push_back("Rectilinear");
|
||||
def->enum_labels.push_back("Concentric");
|
||||
def->enum_labels.push_back("Hilbert Curve");
|
||||
def->enum_labels.push_back("Archimedean Chords");
|
||||
def->enum_labels.push_back("Octagram Spiral");
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Concentric"));
|
||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||
// solid_fill_pattern is an obsolete equivalent to external_fill_pattern.
|
||||
def->aliases.push_back("solid_fill_pattern");
|
||||
def->default_value = new ConfigOptionEnum<InfillPattern>(ipRectilinear);
|
||||
@ -651,19 +651,19 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->enum_values.push_back("hilbertcurve");
|
||||
def->enum_values.push_back("archimedeanchords");
|
||||
def->enum_values.push_back("octagramspiral");
|
||||
def->enum_labels.push_back("Rectilinear");
|
||||
def->enum_labels.push_back("Grid");
|
||||
def->enum_labels.push_back("Triangles");
|
||||
def->enum_labels.push_back("Stars");
|
||||
def->enum_labels.push_back("Cubic");
|
||||
def->enum_labels.push_back("Line");
|
||||
def->enum_labels.push_back("Concentric");
|
||||
def->enum_labels.push_back("Honeycomb");
|
||||
def->enum_labels.push_back("3D Honeycomb");
|
||||
def->enum_labels.push_back("Gyroid");
|
||||
def->enum_labels.push_back("Hilbert Curve");
|
||||
def->enum_labels.push_back("Archimedean Chords");
|
||||
def->enum_labels.push_back("Octagram Spiral");
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Grid"));
|
||||
def->enum_labels.push_back(L("Triangles"));
|
||||
def->enum_labels.push_back(L("Stars"));
|
||||
def->enum_labels.push_back(L("Cubic"));
|
||||
def->enum_labels.push_back(L("Line"));
|
||||
def->enum_labels.push_back(L("Concentric"));
|
||||
def->enum_labels.push_back(L("Honeycomb"));
|
||||
def->enum_labels.push_back(L("3D Honeycomb"));
|
||||
def->enum_labels.push_back(L("Gyroid"));
|
||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||
def->default_value = new ConfigOptionEnum<InfillPattern>(ipStars);
|
||||
|
||||
def = this->add("first_layer_acceleration", coFloat);
|
||||
@ -771,8 +771,8 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->enum_labels.push_back("Mach3/LinuxCNC");
|
||||
def->enum_labels.push_back("Machinekit");
|
||||
def->enum_labels.push_back("Smoothie");
|
||||
def->enum_labels.push_back("No extrusion");
|
||||
def->default_value = new ConfigOptionEnum<GCodeFlavor>(gcfMarlin);
|
||||
def->enum_labels.push_back(L("No extrusion"));
|
||||
def->default_value = new ConfigOptionEnum<GCodeFlavor>(gcfRepRap);
|
||||
|
||||
def = this->add("infill_acceleration", coFloat);
|
||||
def->label = L("Infill");
|
||||
@ -892,6 +892,12 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(0.3);
|
||||
|
||||
def = this->add("silent_mode", coBool);
|
||||
def->label = L("Support silent mode");
|
||||
def->tooltip = L("Set silent mode for the G-code flavor");
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
const int machine_limits_opt_width = 70;
|
||||
{
|
||||
struct AxisDefault {
|
||||
std::string name;
|
||||
@ -901,75 +907,82 @@ PrintConfigDef::PrintConfigDef()
|
||||
};
|
||||
std::vector<AxisDefault> axes {
|
||||
// name, max_feedrate, max_acceleration, max_jerk
|
||||
{ "x", { 200., 200. }, { 1000., 1000. }, { 10., 10. } },
|
||||
{ "y", { 200., 200. }, { 1000., 1000. }, { 10., 10. } },
|
||||
{ "z", { 12., 12. }, { 200., 200. }, { 0.4, 0.4 } },
|
||||
{ "e", { 120., 120. }, { 5000., 5000. }, { 2.5, 2.5 } }
|
||||
{ "x", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } },
|
||||
{ "y", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } },
|
||||
{ "z", { 12., 12. }, { 500., 200. }, { 0.2, 0.4 } },
|
||||
{ "e", { 120., 120. }, { 10000., 5000. }, { 2.5, 2.5 } }
|
||||
};
|
||||
for (const AxisDefault &axis : axes) {
|
||||
std::string axis_upper = boost::to_upper_copy<std::string>(axis.name);
|
||||
// Add the machine feedrate limits for XYZE axes. (M203)
|
||||
def = this->add("machine_max_feedrate_" + axis.name, coFloats);
|
||||
def->label = (boost::format(L("Maximum feedrate %1%")) % axis_upper).str();
|
||||
def->full_label = (boost::format(L("Maximum feedrate %1%")) % axis_upper).str();
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = (boost::format(L("Maximum feedrate of the %1% axis")) % axis_upper).str();
|
||||
def->sidetext = L("mm/s");
|
||||
def->min = 0;
|
||||
def->width = machine_limits_opt_width;
|
||||
def->default_value = new ConfigOptionFloats(axis.max_feedrate);
|
||||
// Add the machine acceleration limits for XYZE axes (M201)
|
||||
def = this->add("machine_max_acceleration_" + axis.name, coFloats);
|
||||
def->label = (boost::format(L("Maximum acceleration %1%")) % axis_upper).str();
|
||||
def->full_label = (boost::format(L("Maximum acceleration %1%")) % axis_upper).str();
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = (boost::format(L("Maximum acceleration of the %1% axis")) % axis_upper).str();
|
||||
def->sidetext = L("mm/s²");
|
||||
def->min = 0;
|
||||
def->width = machine_limits_opt_width;
|
||||
def->default_value = new ConfigOptionFloats(axis.max_acceleration);
|
||||
// Add the machine jerk limits for XYZE axes (M205)
|
||||
def = this->add("machine_max_jerk_" + axis.name, coFloats);
|
||||
def->label = (boost::format(L("Maximum jerk %1%")) % axis_upper).str();
|
||||
def->full_label = (boost::format(L("Maximum jerk %1%")) % axis_upper).str();
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = (boost::format(L("Maximum jerk of the %1% axis")) % axis_upper).str();
|
||||
def->sidetext = L("mm/s");
|
||||
def->min = 0;
|
||||
def->width = machine_limits_opt_width;
|
||||
def->default_value = new ConfigOptionFloats(axis.max_jerk);
|
||||
}
|
||||
}
|
||||
|
||||
// M205 S... [mm/sec]
|
||||
def = this->add("machine_min_extruding_rate", coFloats);
|
||||
def->label = L("Minimum feedrate when extruding");
|
||||
def->full_label = L("Minimum feedrate when extruding");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = L("Minimum feedrate when extruding") + " (M205 S)";
|
||||
def->sidetext = L("mm/s");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats(0., 0.);
|
||||
def->width = machine_limits_opt_width;
|
||||
def->default_value = new ConfigOptionFloats{ 0., 0. };
|
||||
|
||||
// M205 T... [mm/sec]
|
||||
def = this->add("machine_min_travel_rate", coFloats);
|
||||
def->label = L("Minimum travel feedrate");
|
||||
def->full_label = L("Minimum travel feedrate");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = L("Minimum travel feedrate") + " (M205 T)";
|
||||
def->sidetext = L("mm/s");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats(0., 0.);
|
||||
def->width = machine_limits_opt_width;
|
||||
def->default_value = new ConfigOptionFloats{ 0., 0. };
|
||||
|
||||
// M204 S... [mm/sec^2]
|
||||
def = this->add("machine_max_acceleration_extruding", coFloats);
|
||||
def->label = L("Maximum acceleration when extruding");
|
||||
def->full_label = L("Maximum acceleration when extruding");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = L("Maximum acceleration when extruding") + " (M204 S)";
|
||||
def->sidetext = L("mm/s²");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats(1250., 1250.);
|
||||
def->width = machine_limits_opt_width;
|
||||
def->default_value = new ConfigOptionFloats{ 1500., 1250. };
|
||||
|
||||
// M204 T... [mm/sec^2]
|
||||
def = this->add("machine_max_acceleration_retracting", coFloats);
|
||||
def->label = L("Maximum acceleration when retracting");
|
||||
def->full_label = L("Maximum acceleration when retracting");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = L("Maximum acceleration when retracting") + " (M204 T)";
|
||||
def->sidetext = L("mm/s²");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats(1250., 1250.);
|
||||
def->width = machine_limits_opt_width;
|
||||
def->default_value = new ConfigOptionFloats{ 1500., 1250. };
|
||||
|
||||
def = this->add("max_fan_speed", coInts);
|
||||
def->label = L("Max");
|
||||
@ -1392,10 +1405,10 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->enum_values.push_back("nearest");
|
||||
def->enum_values.push_back("aligned");
|
||||
def->enum_values.push_back("rear");
|
||||
def->enum_labels.push_back("Random");
|
||||
def->enum_labels.push_back("Nearest");
|
||||
def->enum_labels.push_back("Aligned");
|
||||
def->enum_labels.push_back("Rear");
|
||||
def->enum_labels.push_back(L("Random"));
|
||||
def->enum_labels.push_back(L("Nearest"));
|
||||
def->enum_labels.push_back(L("Aligned"));
|
||||
def->enum_labels.push_back(L("Rear"));
|
||||
def->default_value = new ConfigOptionEnum<SeamPosition>(spAligned);
|
||||
|
||||
#if 0
|
||||
@ -1608,7 +1621,7 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->label = L("Single Extruder Multi Material");
|
||||
def->tooltip = L("The printer multiplexes filaments into a single hot end.");
|
||||
def->cli = "single-extruder-multi-material!";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("support_material", coBool);
|
||||
def->label = L("Generate support material");
|
||||
@ -1658,8 +1671,8 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->min = 0;
|
||||
def->enum_values.push_back("0");
|
||||
def->enum_values.push_back("0.2");
|
||||
def->enum_labels.push_back("0 (soluble)");
|
||||
def->enum_labels.push_back("0.2 (detachable)");
|
||||
def->enum_labels.push_back((boost::format("0 (%1%)") % L("soluble")).str());
|
||||
def->enum_labels.push_back((boost::format("0.2 (%1%)") % L("detachable")).str());
|
||||
def->default_value = new ConfigOptionFloat(0.2);
|
||||
|
||||
def = this->add("support_material_enforce_layers", coInt);
|
||||
@ -1748,9 +1761,9 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->enum_values.push_back("rectilinear");
|
||||
def->enum_values.push_back("rectilinear-grid");
|
||||
def->enum_values.push_back("honeycomb");
|
||||
def->enum_labels.push_back("rectilinear");
|
||||
def->enum_labels.push_back("rectilinear grid");
|
||||
def->enum_labels.push_back("honeycomb");
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Rectilinear grid"));
|
||||
def->enum_labels.push_back(L("Honeycomb"));
|
||||
def->default_value = new ConfigOptionEnum<SupportMaterialPattern>(smpRectilinear);
|
||||
|
||||
def = this->add("support_material_spacing", coFloat);
|
||||
|
@ -562,9 +562,9 @@ public:
|
||||
ConfigOptionFloat cooling_tube_retraction;
|
||||
ConfigOptionFloat cooling_tube_length;
|
||||
ConfigOptionFloat parking_pos_retraction;
|
||||
ConfigOptionBool silent_mode;
|
||||
ConfigOptionFloat extra_loading_move;
|
||||
|
||||
|
||||
std::string get_extrusion_axis() const
|
||||
{
|
||||
return
|
||||
@ -623,6 +623,7 @@ protected:
|
||||
OPT_PTR(cooling_tube_retraction);
|
||||
OPT_PTR(cooling_tube_length);
|
||||
OPT_PTR(parking_pos_retraction);
|
||||
OPT_PTR(silent_mode);
|
||||
OPT_PTR(extra_loading_move);
|
||||
}
|
||||
};
|
||||
@ -676,6 +677,7 @@ public:
|
||||
ConfigOptionString output_filename_format;
|
||||
ConfigOptionFloat perimeter_acceleration;
|
||||
ConfigOptionStrings post_process;
|
||||
ConfigOptionString printer_model;
|
||||
ConfigOptionString printer_notes;
|
||||
ConfigOptionFloat resolution;
|
||||
ConfigOptionFloats retract_before_travel;
|
||||
@ -746,6 +748,7 @@ protected:
|
||||
OPT_PTR(output_filename_format);
|
||||
OPT_PTR(perimeter_acceleration);
|
||||
OPT_PTR(post_process);
|
||||
OPT_PTR(printer_model);
|
||||
OPT_PTR(printer_notes);
|
||||
OPT_PTR(resolution);
|
||||
OPT_PTR(retract_before_travel);
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#define SLIC3R_FORK_NAME "Slic3r Prusa Edition"
|
||||
#define SLIC3R_VERSION "1.40.1"
|
||||
#define SLIC3R_VERSION "1.41.0-alpha"
|
||||
#define SLIC3R_BUILD "UNKNOWN"
|
||||
|
||||
typedef int32_t coord_t;
|
||||
|
@ -1686,7 +1686,7 @@ bool _3DScene::LegendTexture::generate(const GCodePreviewData& preview_data, con
|
||||
m_data.clear();
|
||||
|
||||
// collects items to render
|
||||
auto title = GUI::L_str(preview_data.get_legend_title());
|
||||
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();
|
||||
|
@ -45,6 +45,22 @@ namespace Slic3r { namespace GUI {
|
||||
set_undo_bitmap(&bmp);
|
||||
set_undo_to_sys_bitmap(&bmp);
|
||||
|
||||
switch (m_opt.type)
|
||||
{
|
||||
case coPercents:
|
||||
case coFloats:
|
||||
case coStrings:
|
||||
case coBools:
|
||||
case coInts: {
|
||||
auto tag_pos = m_opt_id.find("#");
|
||||
if (tag_pos != std::string::npos)
|
||||
m_opt_idx = stoi(m_opt_id.substr(tag_pos + 1, m_opt_id.size()));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
BUILD();
|
||||
}
|
||||
|
||||
@ -77,7 +93,7 @@ namespace Slic3r { namespace GUI {
|
||||
wxString Field::get_tooltip_text(const wxString& default_string)
|
||||
{
|
||||
wxString tooltip_text("");
|
||||
wxString tooltip = L_str(m_opt.tooltip);
|
||||
wxString tooltip = _(m_opt.tooltip);
|
||||
if (tooltip.length() > 0)
|
||||
tooltip_text = tooltip + "(" + _(L("default")) + ": " +
|
||||
(boost::iends_with(m_opt_id, "_gcode") ? "\n" : "") +
|
||||
@ -161,10 +177,10 @@ namespace Slic3r { namespace GUI {
|
||||
case coFloat:
|
||||
{
|
||||
double val = m_opt.type == coFloats ?
|
||||
static_cast<const ConfigOptionFloats*>(m_opt.default_value)->get_at(0) :
|
||||
static_cast<const ConfigOptionFloats*>(m_opt.default_value)->get_at(m_opt_idx) :
|
||||
m_opt.type == coFloat ?
|
||||
m_opt.default_value->getFloat() :
|
||||
static_cast<const ConfigOptionPercents*>(m_opt.default_value)->get_at(0);
|
||||
static_cast<const ConfigOptionPercents*>(m_opt.default_value)->get_at(m_opt_idx);
|
||||
text_value = double_to_string(val);
|
||||
break;
|
||||
}
|
||||
@ -174,10 +190,8 @@ namespace Slic3r { namespace GUI {
|
||||
case coStrings:
|
||||
{
|
||||
const ConfigOptionStrings *vec = static_cast<const ConfigOptionStrings*>(m_opt.default_value);
|
||||
if (vec == nullptr || vec->empty()) break;
|
||||
if (vec->size() > 1)
|
||||
break;
|
||||
text_value = vec->values.at(0);
|
||||
if (vec == nullptr || vec->empty()) break; //for the case of empty default value
|
||||
text_value = vec->get_at(m_opt_idx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -259,7 +273,7 @@ void CheckBox::BUILD() {
|
||||
|
||||
bool check_value = m_opt.type == coBool ?
|
||||
m_opt.default_value->getBool() : m_opt.type == coBools ?
|
||||
static_cast<ConfigOptionBools*>(m_opt.default_value)->values.at(0) :
|
||||
static_cast<ConfigOptionBools*>(m_opt.default_value)->get_at(m_opt_idx) :
|
||||
false;
|
||||
|
||||
auto temp = new wxCheckBox(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size);
|
||||
@ -365,7 +379,7 @@ void Choice::BUILD() {
|
||||
}
|
||||
else{
|
||||
for (auto el : m_opt.enum_labels.empty() ? m_opt.enum_values : m_opt.enum_labels){
|
||||
const wxString& str = m_opt_id == "support" ? L_str(el) : el;
|
||||
const wxString& str = _(el);//m_opt_id == "support" ? _(el) : el;
|
||||
temp->Append(str);
|
||||
}
|
||||
set_selection();
|
||||
@ -418,7 +432,7 @@ void Choice::set_selection()
|
||||
break;
|
||||
}
|
||||
case coStrings:{
|
||||
text_value = static_cast<const ConfigOptionStrings*>(m_opt.default_value)->values.at(0);
|
||||
text_value = static_cast<const ConfigOptionStrings*>(m_opt.default_value)->get_at(m_opt_idx);
|
||||
|
||||
size_t idx = 0;
|
||||
for (auto el : m_opt.enum_values)
|
||||
@ -582,7 +596,7 @@ void ColourPicker::BUILD()
|
||||
if (m_opt.height >= 0) size.SetHeight(m_opt.height);
|
||||
if (m_opt.width >= 0) size.SetWidth(m_opt.width);
|
||||
|
||||
wxString clr(static_cast<ConfigOptionStrings*>(m_opt.default_value)->values.at(0));
|
||||
wxString clr(static_cast<ConfigOptionStrings*>(m_opt.default_value)->get_at(m_opt_idx));
|
||||
auto temp = new wxColourPickerCtrl(m_parent, wxID_ANY, clr, wxDefaultPosition, size);
|
||||
|
||||
// // recast as a wxWindow to fit the calling convention
|
||||
@ -675,6 +689,22 @@ boost::any& PointCtrl::get_value()
|
||||
return m_value = ret_point;
|
||||
}
|
||||
|
||||
void StaticText::BUILD()
|
||||
{
|
||||
auto size = wxSize(wxDefaultSize);
|
||||
if (m_opt.height >= 0) size.SetHeight(m_opt.height);
|
||||
if (m_opt.width >= 0) size.SetWidth(m_opt.width);
|
||||
|
||||
wxString legend(static_cast<ConfigOptionString*>(m_opt.default_value)->value);
|
||||
auto temp = new wxStaticText(m_parent, wxID_ANY, legend, wxDefaultPosition, size);
|
||||
temp->SetFont(bold_font());
|
||||
|
||||
// // recast as a wxWindow to fit the calling convention
|
||||
window = dynamic_cast<wxWindow*>(temp);
|
||||
|
||||
temp->SetToolTip(get_tooltip_text(legend));
|
||||
}
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
|
@ -95,6 +95,7 @@ public:
|
||||
/// Copy of ConfigOption for deduction purposes
|
||||
const ConfigOptionDef m_opt {ConfigOptionDef()};
|
||||
const t_config_option_key m_opt_id;//! {""};
|
||||
int m_opt_idx = 0;
|
||||
|
||||
/// Sets a value for this control.
|
||||
/// subclasses should overload with a specific version
|
||||
@ -384,6 +385,34 @@ public:
|
||||
wxSizer* getSizer() override { return sizer; }
|
||||
};
|
||||
|
||||
class StaticText : public Field {
|
||||
using Field::Field;
|
||||
public:
|
||||
StaticText(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
||||
StaticText(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
||||
~StaticText() {}
|
||||
|
||||
wxWindow* window{ nullptr };
|
||||
void BUILD() override;
|
||||
|
||||
void set_value(const std::string& value, bool change_event = false) {
|
||||
m_disable_change_event = !change_event;
|
||||
dynamic_cast<wxStaticText*>(window)->SetLabel(value);
|
||||
m_disable_change_event = false;
|
||||
}
|
||||
void set_value(const boost::any& value, bool change_event = false) {
|
||||
m_disable_change_event = !change_event;
|
||||
dynamic_cast<wxStaticText*>(window)->SetLabel(boost::any_cast<wxString>(value));
|
||||
m_disable_change_event = false;
|
||||
}
|
||||
|
||||
boost::any& get_value()override { return m_value; }
|
||||
|
||||
void enable() override { dynamic_cast<wxColourPickerCtrl*>(window)->Enable(); };
|
||||
void disable() override{ dynamic_cast<wxColourPickerCtrl*>(window)->Disable(); };
|
||||
wxWindow* getWindow() override { return window; }
|
||||
};
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
|
@ -56,8 +56,9 @@
|
||||
|
||||
#include "../Utils/PresetUpdater.hpp"
|
||||
#include "../Config/Snapshot.hpp"
|
||||
#include "libslic3r/I18N.hpp"
|
||||
|
||||
#include "3DScene.hpp"
|
||||
#include "libslic3r/I18N.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
@ -110,6 +111,7 @@ wxNotebook *g_wxTabPanel = nullptr;
|
||||
AppConfig *g_AppConfig = nullptr;
|
||||
PresetBundle *g_PresetBundle= nullptr;
|
||||
PresetUpdater *g_PresetUpdater = nullptr;
|
||||
_3DScene *g_3DScene = nullptr;
|
||||
wxColour g_color_label_modified;
|
||||
wxColour g_color_label_sys;
|
||||
wxColour g_color_label_default;
|
||||
@ -118,6 +120,9 @@ std::vector<Tab *> g_tabs_list;
|
||||
|
||||
wxLocale* g_wxLocale;
|
||||
|
||||
wxFont g_small_font;
|
||||
wxFont g_bold_font;
|
||||
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup;
|
||||
double m_brim_width = 0.0;
|
||||
wxButton* g_wiping_dialog_button = nullptr;
|
||||
@ -150,6 +155,16 @@ void update_label_colours_from_appconfig()
|
||||
}
|
||||
}
|
||||
|
||||
static void init_fonts()
|
||||
{
|
||||
g_small_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
g_bold_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold();
|
||||
#ifdef __WXMAC__
|
||||
g_small_font.SetPointSize(11);
|
||||
g_bold_font.SetPointSize(13);
|
||||
#endif /*__WXMAC__*/
|
||||
}
|
||||
|
||||
static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); }
|
||||
|
||||
void set_wxapp(wxApp *app)
|
||||
@ -158,6 +173,7 @@ void set_wxapp(wxApp *app)
|
||||
// Let the libslic3r know the callback, which will translate messages on demand.
|
||||
Slic3r::I18N::set_translate_callback(libslic3r_translate_callback);
|
||||
init_label_colours();
|
||||
init_fonts();
|
||||
}
|
||||
|
||||
void set_main_frame(wxFrame *main_frame)
|
||||
@ -185,6 +201,11 @@ void set_preset_updater(PresetUpdater *updater)
|
||||
g_PresetUpdater = updater;
|
||||
}
|
||||
|
||||
void set_3DScene(_3DScene *scene)
|
||||
{
|
||||
g_3DScene = scene;
|
||||
}
|
||||
|
||||
std::vector<Tab *>& get_tabs_list()
|
||||
{
|
||||
return g_tabs_list;
|
||||
@ -675,6 +696,14 @@ void set_label_clr_sys(const wxColour& clr) {
|
||||
g_AppConfig->save();
|
||||
}
|
||||
|
||||
const wxFont& small_font(){
|
||||
return g_small_font;
|
||||
}
|
||||
|
||||
const wxFont& bold_font(){
|
||||
return g_bold_font;
|
||||
}
|
||||
|
||||
const wxColour& get_label_clr_default() {
|
||||
return g_color_label_default;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
class wxApp;
|
||||
class wxWindow;
|
||||
class wxFrame;
|
||||
class wxWindow;
|
||||
class wxFont;
|
||||
class wxMenuBar;
|
||||
class wxNotebook;
|
||||
class wxComboCtrl;
|
||||
@ -32,6 +32,7 @@ class AppConfig;
|
||||
class PresetUpdater;
|
||||
class DynamicPrintConfig;
|
||||
class TabIface;
|
||||
class _3DScene;
|
||||
|
||||
#define _(s) Slic3r::GUI::I18N::translate((s))
|
||||
|
||||
@ -90,6 +91,7 @@ void set_tab_panel(wxNotebook *tab_panel);
|
||||
void set_app_config(AppConfig *app_config);
|
||||
void set_preset_bundle(PresetBundle *preset_bundle);
|
||||
void set_preset_updater(PresetUpdater *updater);
|
||||
void set_3DScene(_3DScene *scene);
|
||||
|
||||
AppConfig* get_app_config();
|
||||
wxApp* get_app();
|
||||
@ -102,6 +104,9 @@ unsigned get_colour_approx_luma(const wxColour &colour);
|
||||
void set_label_clr_modified(const wxColour& clr);
|
||||
void set_label_clr_sys(const wxColour& clr);
|
||||
|
||||
const wxFont& small_font();
|
||||
const wxFont& bold_font();
|
||||
|
||||
extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change);
|
||||
|
||||
// This is called when closing the application, when loading a config file or when starting the config wizard
|
||||
|
@ -31,6 +31,8 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
|
||||
m_fields.emplace(id, STDMOVE(Choice::Create<Choice>(parent(), opt, id)));
|
||||
} else if (opt.gui_type.compare("slider") == 0) {
|
||||
} else if (opt.gui_type.compare("i_spin") == 0) { // Spinctrl
|
||||
} else if (opt.gui_type.compare("legend") == 0) { // StaticText
|
||||
m_fields.emplace(id, STDMOVE(StaticText::Create<StaticText>(parent(), opt, id)));
|
||||
} else {
|
||||
switch (opt.type) {
|
||||
case coFloatOrPercent:
|
||||
@ -86,7 +88,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
|
||||
if (!this->m_disabled)
|
||||
this->back_to_sys_value(opt_id);
|
||||
};
|
||||
if (!m_is_tab_opt) {
|
||||
if (!m_show_modified_btns) {
|
||||
field->m_Undo_btn->Hide();
|
||||
field->m_Undo_to_sys_btn->Hide();
|
||||
}
|
||||
@ -199,7 +201,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** colored_Label/*
|
||||
ConfigOptionDef option = opt.opt;
|
||||
// add label if any
|
||||
if (option.label != "") {
|
||||
wxString str_label = L_str(option.label);
|
||||
wxString str_label = _(option.label);
|
||||
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
||||
// wxString str_label = (option.label == "Top" || option.label == "Bottom") ?
|
||||
// wxGETTEXT_IN_CONTEXT("Layers", wxString(option.label.c_str()):
|
||||
@ -220,7 +222,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** colored_Label/*
|
||||
|
||||
// add sidetext if any
|
||||
if (option.sidetext != "") {
|
||||
auto sidetext = new wxStaticText(parent(), wxID_ANY, L_str(option.sidetext), wxDefaultPosition, wxDefaultSize);
|
||||
auto sidetext = new wxStaticText(parent(), wxID_ANY, _(option.sidetext), wxDefaultPosition, wxDefaultSize);
|
||||
sidetext->SetFont(sidetext_font);
|
||||
sizer->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4);
|
||||
}
|
||||
@ -242,7 +244,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** colored_Label/*
|
||||
}
|
||||
|
||||
Line OptionsGroup::create_single_option_line(const Option& option) const {
|
||||
Line retval{ L_str(option.opt.label), L_str(option.opt.tooltip) };
|
||||
Line retval{ _(option.opt.label), _(option.opt.tooltip) };
|
||||
Option tmp(option);
|
||||
tmp.opt.label = std::string("");
|
||||
retval.append_option(tmp);
|
||||
|
@ -127,9 +127,15 @@ public:
|
||||
inline void enable() { for (auto& field : m_fields) field.second->enable(); }
|
||||
inline void disable() { for (auto& field : m_fields) field.second->disable(); }
|
||||
|
||||
void set_show_modified_btns_val(bool show) {
|
||||
m_show_modified_btns = show;
|
||||
}
|
||||
|
||||
OptionsGroup(wxWindow* _parent, const wxString& title, bool is_tab_opt=false) :
|
||||
m_parent(_parent), title(title), m_is_tab_opt(is_tab_opt), staticbox(title!="") {
|
||||
sizer = (staticbox ? new wxStaticBoxSizer(new wxStaticBox(_parent, wxID_ANY, title), wxVERTICAL) : new wxBoxSizer(wxVERTICAL));
|
||||
m_parent(_parent), title(title), m_show_modified_btns(is_tab_opt), staticbox(title!="") {
|
||||
auto stb = new wxStaticBox(_parent, wxID_ANY, title);
|
||||
stb->SetFont(bold_font());
|
||||
sizer = (staticbox ? new wxStaticBoxSizer(stb/*new wxStaticBox(_parent, wxID_ANY, title)*/, wxVERTICAL) : new wxBoxSizer(wxVERTICAL));
|
||||
auto num_columns = 1U;
|
||||
if (label_width != 0) num_columns++;
|
||||
if (extra_column != nullptr) num_columns++;
|
||||
@ -156,7 +162,7 @@ protected:
|
||||
bool m_disabled {false};
|
||||
wxGridSizer* m_grid_sizer {nullptr};
|
||||
// "true" if option is created in preset tabs
|
||||
bool m_is_tab_opt{ false };
|
||||
bool m_show_modified_btns{ false };
|
||||
|
||||
// This panel is needed for correct showing of the ToolTips for Button, StaticText and CheckBox
|
||||
// Tooltips on GTK doesn't work inside wxStaticBoxSizer unless you insert a panel
|
||||
|
@ -327,6 +327,11 @@ const std::vector<std::string>& Preset::printer_options()
|
||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
|
||||
"cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "max_print_height", "default_print_profile", "inherits",
|
||||
"silent_mode", "machine_max_acceleration_extruding", "machine_max_acceleration_retracting",
|
||||
"machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
|
||||
"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
|
||||
"machine_min_extruding_rate", "machine_min_travel_rate",
|
||||
"machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e"
|
||||
};
|
||||
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
|
||||
}
|
||||
@ -505,6 +510,9 @@ Preset& PresetCollection::load_external_preset(
|
||||
// Insert a new profile.
|
||||
Preset &preset = this->load_preset(path, new_name, std::move(cfg), select);
|
||||
preset.is_external = true;
|
||||
if (&this->get_selected_preset() == &preset)
|
||||
this->get_edited_preset().is_external = true;
|
||||
|
||||
return preset;
|
||||
}
|
||||
|
||||
|
@ -353,10 +353,6 @@ public:
|
||||
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
|
||||
std::string path_from_name(const std::string &new_name) const;
|
||||
|
||||
// update m_edited_preset.is_external value after loading preset for .ini, .gcode, .amf, .3mf
|
||||
void update_edited_preset_is_external(bool is_external) {
|
||||
m_edited_preset.is_external = is_external; }
|
||||
|
||||
protected:
|
||||
// Select a preset, if it exists. If it does not exist, select an invalid (-1) index.
|
||||
// This is a temporary state, which shall be fixed immediately by the following step.
|
||||
|
@ -565,12 +565,11 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
size_t idx = (i_group == 0) ? 0 : num_extruders + 1;
|
||||
inherits = inherits_values[idx];
|
||||
compatible_printers_condition = compatible_printers_condition_values[idx];
|
||||
if (is_external) {
|
||||
if (is_external)
|
||||
presets.load_external_preset(name_or_path, name,
|
||||
config.opt_string((i_group == 0) ? "print_settings_id" : "printer_settings_id", true),
|
||||
config);
|
||||
presets.update_edited_preset_is_external(true);
|
||||
} else
|
||||
else
|
||||
presets.load_preset(presets.path_from_name(name), name, config).save();
|
||||
}
|
||||
|
||||
@ -583,10 +582,9 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
// Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets.
|
||||
inherits = inherits_values[1];
|
||||
compatible_printers_condition = compatible_printers_condition_values[1];
|
||||
if (is_external) {
|
||||
if (is_external)
|
||||
this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config);
|
||||
this->filaments.update_edited_preset_is_external(true);
|
||||
} else
|
||||
else
|
||||
this->filaments.load_preset(this->filaments.path_from_name(name), name, config).save();
|
||||
this->filament_presets.clear();
|
||||
this->filament_presets.emplace_back(name);
|
||||
@ -615,12 +613,11 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
cfg.opt_string("inherits", true) = inherits_values[i + 1];
|
||||
// Load all filament presets, but only select the first one in the preset dialog.
|
||||
Preset *loaded = nullptr;
|
||||
if (is_external) {
|
||||
if (is_external)
|
||||
loaded = &this->filaments.load_external_preset(name_or_path, name,
|
||||
(i < old_filament_profile_names->values.size()) ? old_filament_profile_names->values[i] : "",
|
||||
std::move(cfg), i == 0);
|
||||
this->filaments.update_edited_preset_is_external(true);
|
||||
} else {
|
||||
else {
|
||||
// Used by the config wizard when creating a custom setup.
|
||||
// Therefore this block should only be called for a single extruder.
|
||||
char suffix[64];
|
||||
|
@ -1605,6 +1605,22 @@ void TabPrinter::build()
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Firmware")));
|
||||
optgroup->append_single_option_line("gcode_flavor");
|
||||
optgroup->append_single_option_line("silent_mode");
|
||||
|
||||
optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value){
|
||||
wxTheApp->CallAfter([this, opt_key, value](){
|
||||
if (opt_key.compare("silent_mode") == 0) {
|
||||
bool val = boost::any_cast<bool>(value);
|
||||
if (m_use_silent_mode != val) {
|
||||
m_rebuild_kinematics_page = true;
|
||||
m_use_silent_mode = val;
|
||||
}
|
||||
}
|
||||
build_extruder_pages();
|
||||
update_dirty();
|
||||
on_value_change(opt_key, value);
|
||||
});
|
||||
};
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Advanced")));
|
||||
optgroup->append_single_option_line("use_relative_e_distances");
|
||||
@ -1686,8 +1702,94 @@ void TabPrinter::extruders_count_changed(size_t extruders_count){
|
||||
on_value_change("extruders_count", extruders_count);
|
||||
}
|
||||
|
||||
void TabPrinter::build_extruder_pages(){
|
||||
void TabPrinter::append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key)
|
||||
{
|
||||
auto option = optgroup->get_option(opt_key, 0);
|
||||
auto line = Line{ option.opt.full_label, "" };
|
||||
line.append_option(option);
|
||||
if (m_use_silent_mode)
|
||||
line.append_option(optgroup->get_option(opt_key, 1));
|
||||
optgroup->append_line(line);
|
||||
}
|
||||
|
||||
PageShp TabPrinter::build_kinematics_page()
|
||||
{
|
||||
auto page = add_options_page(_(L("Machine limits")), "cog.png", true);
|
||||
|
||||
if (m_use_silent_mode) {
|
||||
// Legend for OptionsGroups
|
||||
auto optgroup = page->new_optgroup(_(L("")));
|
||||
optgroup->set_show_modified_btns_val(false);
|
||||
optgroup->label_width = 230;
|
||||
auto line = Line{ "", "" };
|
||||
|
||||
ConfigOptionDef def;
|
||||
def.type = coString;
|
||||
def.width = 150;
|
||||
def.gui_type = "legend";
|
||||
def.tooltip = L("Values in this column are for Full Power mode");
|
||||
def.default_value = new ConfigOptionString{ L("Full Power") };
|
||||
|
||||
auto option = Option(def, "full_power_legend");
|
||||
line.append_option(option);
|
||||
|
||||
def.tooltip = L("Values in this column are for Silent mode");
|
||||
def.default_value = new ConfigOptionString{ L("Silent") };
|
||||
option = Option(def, "silent_legend");
|
||||
line.append_option(option);
|
||||
|
||||
optgroup->append_line(line);
|
||||
}
|
||||
|
||||
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")));
|
||||
for (const std::string &axis : axes) {
|
||||
append_option_line(optgroup, "machine_max_feedrate_" + axis);
|
||||
}
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Starting Acceleration")));
|
||||
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");
|
||||
for (const std::string &axis : axes) {
|
||||
append_option_line(optgroup, "machine_max_jerk_" + axis);
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
void TabPrinter::build_extruder_pages()
|
||||
{
|
||||
size_t n_before_extruders = 2; // Count of pages before Extruder pages
|
||||
bool is_marlin_flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlin;
|
||||
|
||||
// Add/delete Kinematics page according to is_marlin_flavor
|
||||
size_t existed_page = 0;
|
||||
for (int i = n_before_extruders; i < m_pages.size(); ++i) // first make sure it's not there already
|
||||
if (m_pages[i]->title().find(_(L("Machine limits"))) != std::string::npos) {
|
||||
if (!is_marlin_flavor || m_rebuild_kinematics_page)
|
||||
m_pages.erase(m_pages.begin() + i);
|
||||
else
|
||||
existed_page = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (existed_page < n_before_extruders && is_marlin_flavor){
|
||||
auto page = build_kinematics_page();
|
||||
m_pages.insert(m_pages.begin() + n_before_extruders, page);
|
||||
}
|
||||
|
||||
if (is_marlin_flavor)
|
||||
n_before_extruders++;
|
||||
size_t n_after_single_extruder_MM = 2; // Count of pages after single_extruder_multi_material page
|
||||
|
||||
if (m_extruders_count_old == m_extruders_count ||
|
||||
@ -1796,6 +1898,24 @@ void TabPrinter::update(){
|
||||
get_field("toolchange_gcode")->toggle(have_multiple_extruders);
|
||||
get_field("single_extruder_multi_material")->toggle(have_multiple_extruders);
|
||||
|
||||
bool is_marlin_flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlin;
|
||||
|
||||
{
|
||||
Field *sm = get_field("silent_mode");
|
||||
if (! is_marlin_flavor)
|
||||
// Disable silent mode for non-marlin firmwares.
|
||||
get_field("silent_mode")->toggle(false);
|
||||
if (is_marlin_flavor)
|
||||
sm->enable();
|
||||
else
|
||||
sm->disable();
|
||||
}
|
||||
|
||||
if (m_use_silent_mode != m_config->opt_bool("silent_mode")) {
|
||||
m_rebuild_kinematics_page = true;
|
||||
m_use_silent_mode = m_config->opt_bool("silent_mode");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_extruders_count; ++i) {
|
||||
bool have_retract_length = m_config->opt_float("retract_length", i) > 0;
|
||||
|
||||
@ -1914,7 +2034,8 @@ void Tab::rebuild_page_tree()
|
||||
auto itemId = m_treectrl->AppendItem(rootItem, p->title(), p->iconID());
|
||||
m_treectrl->SetItemTextColour(itemId, p->get_item_colour());
|
||||
if (p->title() == selected) {
|
||||
m_disable_tree_sel_changed_event = 1;
|
||||
if (!(p->title() == _(L("Machine limits")) || p->title() == _(L("Single extruder MM setup")))) // These Pages have to be updated inside OnTreeSelChange
|
||||
m_disable_tree_sel_changed_event = 1;
|
||||
m_treectrl->SelectItem(itemId);
|
||||
m_disable_tree_sel_changed_event = 0;
|
||||
have_selection = 1;
|
||||
|
@ -316,6 +316,9 @@ public:
|
||||
class TabPrinter : public Tab
|
||||
{
|
||||
bool m_has_single_extruder_MM_page = false;
|
||||
bool m_use_silent_mode = false;
|
||||
void append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key);
|
||||
bool m_rebuild_kinematics_page = false;
|
||||
public:
|
||||
wxButton* m_serial_test_btn;
|
||||
wxButton* m_octoprint_host_test_btn;
|
||||
@ -333,6 +336,7 @@ public:
|
||||
void update() override;
|
||||
void update_serial_ports();
|
||||
void extruders_count_changed(size_t extruders_count);
|
||||
PageShp build_kinematics_page();
|
||||
void build_extruder_pages();
|
||||
void on_preset_loaded() override;
|
||||
void init_options_list() override;
|
||||
|
@ -101,3 +101,6 @@ void desktop_open_datadir_folder()
|
||||
|
||||
void fix_model_by_win10_sdk_gui(ModelObject *model_object_src, Print *print, Model *model_dst)
|
||||
%code%{ Slic3r::fix_model_by_win10_sdk_gui(*model_object_src, *print, *model_dst); %};
|
||||
|
||||
void set_3DScene(SV *scene)
|
||||
%code%{ Slic3r::GUI::set_3DScene((_3DScene *)wxPli_sv_2_object(aTHX_ scene, "Slic3r::Model::3DScene") ); %};
|
||||
|
@ -145,8 +145,10 @@ _constant()
|
||||
%code%{ RETVAL = &THIS->skirt; %};
|
||||
Ref<ExtrusionEntityCollection> brim()
|
||||
%code%{ RETVAL = &THIS->brim; %};
|
||||
std::string estimated_print_time()
|
||||
%code%{ RETVAL = THIS->estimated_print_time; %};
|
||||
std::string estimated_normal_print_time()
|
||||
%code%{ RETVAL = THIS->estimated_normal_print_time; %};
|
||||
std::string estimated_silent_print_time()
|
||||
%code%{ RETVAL = THIS->estimated_silent_print_time; %};
|
||||
|
||||
PrintObjectPtrs* objects()
|
||||
%code%{ RETVAL = &THIS->objects; %};
|
||||
|
Loading…
x
Reference in New Issue
Block a user