Fixed conflicts after merge with master

This commit is contained in:
enricoturri1966 2023-03-30 08:52:20 +02:00
commit 6084a92d9b
191 changed files with 13248 additions and 4361 deletions

View File

@ -87,6 +87,7 @@ src/slic3r/GUI/UpdateDialogs.cpp
src/slic3r/GUI/WipeTowerDialog.cpp src/slic3r/GUI/WipeTowerDialog.cpp
src/slic3r/GUI/wxExtensions.cpp src/slic3r/GUI/wxExtensions.cpp
src/slic3r/Utils/AstroBox.cpp src/slic3r/Utils/AstroBox.cpp
src/slic3r/Utils/AppUpdater.cpp
src/slic3r/Utils/Duet.cpp src/slic3r/Utils/Duet.cpp
src/slic3r/Utils/FixModelByWin10.cpp src/slic3r/Utils/FixModelByWin10.cpp
src/slic3r/Utils/FlashAir.cpp src/slic3r/Utils/FlashAir.cpp
@ -101,6 +102,7 @@ src/libslic3r/ExtrusionEntity.cpp
src/libslic3r/Flow.cpp src/libslic3r/Flow.cpp
src/libslic3r/Format/3mf.cpp src/libslic3r/Format/3mf.cpp
src/libslic3r/Format/AMF.cpp src/libslic3r/Format/AMF.cpp
src/libslic3r/Format/SLAArchiveReader.cpp
src/libslic3r/GCode/PostProcessor.cpp src/libslic3r/GCode/PostProcessor.cpp
src/libslic3r/miniz_extension.cpp src/libslic3r/miniz_extension.cpp
src/libslic3r/Preset.cpp src/libslic3r/Preset.cpp
@ -113,3 +115,4 @@ src/libslic3r/PrintBase.cpp
src/libslic3r/PrintConfig.cpp src/libslic3r/PrintConfig.cpp
src/libslic3r/Zipper.cpp src/libslic3r/Zipper.cpp
src/libslic3r/PrintObject.cpp src/libslic3r/PrintObject.cpp
src/libslic3r/PrintObjectSlice.cpp

View File

@ -1,3 +1,5 @@
min_slic3r_version = 2.6.0-alpha4
1.1.1 Initial official version
1.0.1 Initial Version
min_slic3r_version = 2.6.0-alpha1 min_slic3r_version = 2.6.0-alpha1
1.0.1 Disabled thick bridges.
1.0.0 Initial Version 1.0.0 Initial Version

View File

@ -1,14 +1,14 @@
# Print profiles for the AnkerMake printers. # Print profiles for the AnkerMake printers.
# https://github.com/prusa3d/PrusaSlicer/pull/9075 by @just-trey
[vendor] [vendor]
# Vendor name will be shown by the Config Wizard. # Vendor name will be shown by the Config Wizard.
name = Anker name = AnkerMake
# Configuration version of this file. Config file will only be installed, if the config_version differs. # Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded. # This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.0.1 config_version = 1.1.1
# Where to get the updates from? # Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Anker/ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Anker/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
# The printer models will be shown by the Configuration Wizard in this order, # The printer models will be shown by the Configuration Wizard in this order,
# also the first model installed & the first nozzle installed will be activated after install. # also the first model installed & the first nozzle installed will be activated after install.
@ -20,8 +20,9 @@ variants = 0.4
technology = FFF technology = FFF
family = AnkerMake family = AnkerMake
bed_model = M5-bed.stl bed_model = M5-bed.stl
bed_texture = M5-texture.svg bed_texture = M5-texture_v2.svg
default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER; Generic ABS @ANKER thumbnail = M5_thumbnail_v2.png
default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER; Generic ABS @ANKER;
# All presets starting with asterisk, for example *common*, are intermediate and they will # All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface. # not make it into the user interface.
@ -31,8 +32,8 @@ default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER;
avoid_crossing_perimeters = 0 avoid_crossing_perimeters = 0
bridge_acceleration = 2500 bridge_acceleration = 2500
bridge_angle = 0 bridge_angle = 0
bridge_flow_ratio = 0.95 bridge_flow_ratio = 1
bridge_speed = 150 bridge_speed = 50
brim_separation = 0.1 brim_separation = 0.1
brim_type = outer_only brim_type = outer_only
brim_width = 0 brim_width = 0
@ -40,32 +41,36 @@ clip_multipart_objects = 1
complete_objects = 0 complete_objects = 0
default_acceleration = 2500 default_acceleration = 2500
dont_support_bridges = 1 dont_support_bridges = 1
elefant_foot_compensation = 0.1 elefant_foot_compensation = 0.2
ensure_vertical_shell_thickness = 1 ensure_vertical_shell_thickness = 1
external_perimeter_speed = 150 external_perimeter_speed = 150
external_perimeters_first = 0 external_perimeters_first = 0
extra_perimeters = 0 extra_perimeters = 0
extruder_clearance_height = 30 extruder_clearance_height = 30
extruder_clearance_radius = 45 extruder_clearance_radius = 45
extrusion_width = 0.4
external_perimeter_extrusion_width = 0.44
fill_angle = 45 fill_angle = 45
fill_density = 15% fill_density = 10%
fill_pattern = cubic fill_pattern = grid
first_layer_acceleration = 2500 first_layer_acceleration = 2500
first_layer_acceleration_over_raft = 0 first_layer_acceleration_over_raft = 0
first_layer_extrusion_width = 200% first_layer_extrusion_width = 0.4
first_layer_speed = 50% first_layer_speed = 50%
first_layer_speed_over_raft = 30 first_layer_speed_over_raft = 30
gap_fill_enabled = 1 gap_fill_enabled = 1
gap_fill_speed = 150 gap_fill_speed = 150
gcode_comments = 0 gcode_comments = 0
infill_acceleration = 2500 infill_acceleration = 2500
infill_anchor = 600% infill_anchor = 2.5
infill_anchor_max = 50 infill_anchor_max = 12
infill_every_layers = 1 infill_every_layers = 1
infill_extruder = 1 infill_extruder = 1
infill_first = 0 infill_first = 0
infill_extrusion_width = 0.4
infill_only_where_needed = 0 infill_only_where_needed = 0
infill_overlap = 23% infill_overlap = 10%
infill_speed = 250 infill_speed = 250
interface_shells = 0 interface_shells = 0
max_print_speed = 250 max_print_speed = 250
@ -76,18 +81,18 @@ min_skirt_length = 4
notes = notes =
only_retract_when_crossing_perimeters = 0 only_retract_when_crossing_perimeters = 0
ooze_prevention = 0 ooze_prevention = 0
output_filename_format = {input_filename_base}_{digits(layer_height,1,2)}mm_{filament_type[0]}_{printer_model}.gcode output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}.gcode
overhangs = 1 overhangs = 1
perimeter_acceleration = 2500 perimeter_acceleration = 2500
perimeter_extruder = 1 perimeter_extruder = 1
perimeter_extrusion_width = 0 perimeter_extrusion_width = 0.4
perimeter_generator = arachne perimeter_generator = classic
perimeter_speed = 250 perimeter_speed = 250
perimeters = 3 perimeters = 3
post_process = post_process =
print_settings_id = print_settings_id =
raft_layers = 0 raft_layers = 0
resolution = 0 resolution = 0.01
seam_position = aligned seam_position = aligned
single_extruder_multi_material_priming = 0 single_extruder_multi_material_priming = 0
skirt_distance = 3 skirt_distance = 3
@ -97,32 +102,37 @@ small_perimeter_speed = 150
solid_infill_below_area = 0 solid_infill_below_area = 0
solid_infill_every_layers = 0 solid_infill_every_layers = 0
solid_infill_extruder = 1 solid_infill_extruder = 1
solid_infill_speed = 175 solid_infill_extrusion_width = 0.4
solid_infill_speed = 250
spiral_vase = 0 spiral_vase = 0
standby_temperature_delta = -5 standby_temperature_delta = -5
support_material_auto = 0
support_material = 0 support_material = 0
support_material_angle = 0 support_material_angle = 0
support_material_buildplate_only = 0 support_material_buildplate_only = 0
support_material_contact_distance = 0.15 support_material_contact_distance = 0.1
support_material_enforce_layers = 0 support_material_enforce_layers = 0
support_material_extruder = 0 support_material_extruder = 0
support_material_interface_contact_loops = 0 support_material_interface_contact_loops = 0
support_material_interface_extruder = 0 support_material_interface_extruder = 0
support_material_interface_layers = 2 support_material_interface_layers = 2
support_material_interface_spacing = 0.2 support_material_interface_spacing = 0.2
support_material_interface_speed = 100% support_material_interface_speed = 80%
support_material_pattern = rectilinear support_material_pattern = rectilinear
support_material_spacing = 2 support_material_spacing = 2
support_material_speed = 125 support_material_speed = 150
support_material_synchronize_layers = 0 support_material_synchronize_layers = 0
support_material_threshold = 40 support_material_threshold = 55
support_material_with_sheath = 0 support_material_with_sheath = 0
support_material_xy_spacing = 60% support_material_xy_spacing = 50%
thick_bridges = 0 thick_bridges = 0
thin_walls = 0 thin_walls = 0
top_solid_infill_speed = 150 top_solid_infill_speed = 150
travel_speed = 300 top_infill_extrusion_width = 0.4
travel_speed_z = 10 top_fill_pattern = rectilinear
bottom_fill_pattern = rectilinear
travel_speed = 250
travel_speed_z = 0
wipe_tower = 0 wipe_tower = 0
wipe_tower_bridging = 10 wipe_tower_bridging = 10
wipe_tower_rotation_angle = 0 wipe_tower_rotation_angle = 0
@ -131,86 +141,49 @@ wipe_tower_x = 170
wipe_tower_y = 140 wipe_tower_y = 140
xy_size_compensation = 0 xy_size_compensation = 0
[print:*0.08mm*]
inherits = *common*
layer_height = 0.08
first_layer_height = 0.12
bottom_solid_layers = 9
top_solid_layers = 11
bridge_flow_ratio = 0.70
[print:*0.10mm*] [print:*0.10mm*]
inherits = *common* inherits = *common*
layer_height = 0.10 layer_height = 0.10
first_layer_height = 0.14 first_layer_height = 0.10
bottom_solid_layers = 7 bottom_solid_layers = 7
top_solid_layers = 9 top_solid_layers = 9
bridge_flow_ratio = 0.70 bridge_flow_ratio = 1
[print:*0.12mm*]
inherits = *common*
layer_height = 0.12
first_layer_height = 0.16
bottom_solid_layers = 6
top_solid_layers = 7
bridge_flow_ratio = 0.70
[print:*0.16mm*]
inherits = *common*
layer_height = 0.16
first_layer_height = 0.20
bottom_solid_layers = 5
top_solid_layers = 7
bridge_flow_ratio = 0.85
[print:*0.20mm*] [print:*0.20mm*]
inherits = *common* inherits = *common*
layer_height = 0.20 layer_height = 0.20
first_layer_height = 0.24 first_layer_height = 0.14
bottom_solid_layers = 4 bottom_solid_layers = 4
top_solid_layers = 5 top_solid_layers = 5
[print:*0.24mm*] [print:*0.30mm*]
inherits = *common* inherits = *common*
layer_height = 0.24 layer_height = 0.30
first_layer_height = 0.28 first_layer_height = 0.21
bottom_solid_layers = 3 bottom_solid_layers = 3
top_solid_layers = 4 top_solid_layers = 4
[print:*0.28mm*]
inherits = *common*
layer_height = 0.28
first_layer_height = 0.28
bottom_solid_layers = 3
top_solid_layers = 4
[print:0.08 mm SUPERDETAIL (0.4 mm nozzle) @ANKER]
inherits = *0.08mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.10 mm HIGHDETAIL (0.4 mm nozzle) @ANKER] [print:0.10 mm HIGHDETAIL (0.4 mm nozzle) @ANKER]
inherits = *0.10mm* inherits = *0.10mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.12 mm DETAIL (0.4 mm nozzle) @ANKER]
inherits = *0.12mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.16 mm OPTIMAL (0.4 mm nozzle) @ANKER]
inherits = *0.16mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.20 mm NORMAL (0.4 mm nozzle) @ANKER] [print:0.20 mm NORMAL (0.4 mm nozzle) @ANKER]
inherits = *0.20mm* inherits = *0.20mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.24 mm DRAFT (0.4 mm nozzle) @ANKER]
inherits = *0.24mm* [print:0.30 mm SUPERDRAFT (0.4 mm nozzle) @ANKER]
inherits = *0.30mm*
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4
[print:0.28 mm SUPERDRAFT (0.4 mm nozzle) @ANKER] # When submitting new filaments please print the following temperature tower at 0.1mm layer height:
inherits = *0.28mm* # https://www.thingiverse.com/thing:2615842
compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 # Pay particular attention to bridging, overhangs and retractions.
# Also print the following bed adhesion test at 0.1 layer height as well:
# https://www.prusaprinters.org/prints/4634-bed-adhesion-warp-test
# At least for PLA, please keep bed temp at 60, as many Creality printers do not have any ABL
# So having some leeway to get good bed adhesion is not a luxury for many users
[filament:*common*] [filament:*common*]
cooling = 0 cooling = 0
@ -235,47 +208,47 @@ filament_type = PLA
filament_density = 1.24 filament_density = 1.24
filament_cost = 20 filament_cost = 20
first_layer_bed_temperature = 60 first_layer_bed_temperature = 60
first_layer_temperature = 210 first_layer_temperature = 230
fan_always_on = 1 fan_always_on = 1
max_fan_speed = 100 max_fan_speed = 100
min_fan_speed = 100 min_fan_speed = 100
bridge_fan_speed = 100 bridge_fan_speed = 100
disable_fan_first_layers = 2 disable_fan_first_layers = 1
temperature = 205 temperature = 200
[filament:*PLA+*] [filament:*PLA+*]
inherits = *common* inherits = *common*
bed_temperature = 60 bed_temperature = 60
fan_below_layer_time = 100 fan_below_layer_time = 100
filament_colour = #DDDDDD filament_colour = #DDDDDD
filament_type = PLA filament_type = PLA+
filament_density = 1.24 filament_density = 1.24
filament_cost = 20 filament_cost = 20
first_layer_bed_temperature = 60 first_layer_bed_temperature = 60
first_layer_temperature = 220 first_layer_temperature = 230
fan_always_on = 1 fan_always_on = 1
max_fan_speed = 100 max_fan_speed = 100
min_fan_speed = 100 min_fan_speed = 100
bridge_fan_speed = 100 bridge_fan_speed = 100
disable_fan_first_layers = 2 disable_fan_first_layers = 1
temperature = 210 temperature = 200
[filament:*PET*] [filament:*PET*]
inherits = *common* inherits = *common*
bed_temperature = 70 bed_temperature = 80
disable_fan_first_layers = 2 disable_fan_first_layers = 2
fan_below_layer_time = 20 fan_below_layer_time = 20
filament_colour = #DDDDDD filament_colour = #DDDDDD
filament_type = PETG filament_type = PETG
filament_density = 1.27 filament_density = 1.27
filament_cost = 30 filament_cost = 30
first_layer_bed_temperature = 70 first_layer_bed_temperature = 80
first_layer_temperature = 240 first_layer_temperature = 260
fan_always_on = 1 fan_always_on = 1
max_fan_speed = 50 max_fan_speed = 50
min_fan_speed = 50 min_fan_speed = 50
bridge_fan_speed = 100 bridge_fan_speed = 100
temperature = 240 temperature = 260
[filament:*ABS*] [filament:*ABS*]
inherits = *common* inherits = *common*
@ -286,14 +259,14 @@ filament_colour = #DDDDDD
filament_type = ABS filament_type = ABS
filament_density = 1.04 filament_density = 1.04
filament_cost = 20 filament_cost = 20
first_layer_bed_temperature = 100 first_layer_bed_temperature = 90
first_layer_temperature = 245 first_layer_temperature = 260
fan_always_on = 0 fan_always_on = 0
max_fan_speed = 0 max_fan_speed = 0
min_fan_speed = 0 min_fan_speed = 0
bridge_fan_speed = 30 bridge_fan_speed = 30
top_fan_speed = 0 top_fan_speed = 0
temperature = 245 temperature = 260
[filament:Generic PLA @ANKER] [filament:Generic PLA @ANKER]
inherits = *PLA* inherits = *PLA*
@ -324,8 +297,8 @@ deretract_speed = 60
extruder_colour = #FCE94F extruder_colour = #FCE94F
extruder_offset = 0x0 extruder_offset = 0x0
gcode_flavor = marlin gcode_flavor = marlin
silent_mode = 0 silent_mode = 1
remaining_times = 0 remaining_times = 1
machine_max_acceleration_e = 2500 machine_max_acceleration_e = 2500
machine_max_acceleration_extruding = 2500 machine_max_acceleration_extruding = 2500
machine_max_acceleration_retracting = 2500 machine_max_acceleration_retracting = 2500
@ -338,8 +311,8 @@ machine_max_feedrate_x = 300
machine_max_feedrate_y = 300 machine_max_feedrate_y = 300
machine_max_feedrate_z = 20 machine_max_feedrate_z = 20
machine_max_jerk_e = 3 machine_max_jerk_e = 3
machine_max_jerk_x = 30 machine_max_jerk_x = 15
machine_max_jerk_y = 30 machine_max_jerk_y = 15
machine_max_jerk_z = 0.3 machine_max_jerk_z = 0.3
machine_min_extruding_rate = 0 machine_min_extruding_rate = 0
machine_min_travel_rate = 0 machine_min_travel_rate = 0
@ -347,10 +320,10 @@ layer_gcode = ;AFTER_LAYER_CHANGE\n;{layer_z}
max_print_height = 250 max_print_height = 250
printer_notes = printer_notes =
printer_settings_id = printer_settings_id =
retract_before_travel = 2 retract_before_travel = 3
retract_before_wipe = 70% retract_before_wipe = 0
retract_layer_change = 1 retract_layer_change = 1
retract_length_toolchange = 1 retract_length_toolchange = 4
retract_lift = 0 retract_lift = 0
retract_lift_above = 0 retract_lift_above = 0
retract_lift_below = 0 retract_lift_below = 0
@ -365,10 +338,10 @@ use_firmware_retraction = 0
use_relative_e_distances = 0 use_relative_e_distances = 0
use_volumetric_e = 0 use_volumetric_e = 0
variable_layer_height = 1 variable_layer_height = 1
wipe = 1 wipe = 0
z_offset = 0 z_offset = 0
default_filament_profile = "Generic PLA+ @ANKER" default_filament_profile = Generic PLA+ @ANKER
start_gcode = M104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; set and wait for nozzle temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG28 ;Home\nG1 E10 F3600; push out retracted filament(fix for over retraction after prime) start_gcode = M104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; set and wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG28 ;Home\nM420 S1; restore saved Auto Bed Leveling data\nG1 E10 F3600; push out retracted filament(fix for over retraction after prime)
end_gcode = M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84 end_gcode = M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84
[printer:*M5*] [printer:*M5*]
@ -376,12 +349,12 @@ inherits = *common*
bed_shape = 0x0,235-0,235x235,0x235 bed_shape = 0x0,235-0,235x235,0x235
max_print_height = 250 max_print_height = 250
printer_model = M5 printer_model = M5
retract_length = 1.25 retract_length = 3
retract_speed = 60 retract_speed = 60
deretract_speed = 60 deretract_speed = 60
retract_before_travel = 1 retract_before_travel = 3
retract_before_wipe = 0% retract_before_wipe = 0%
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_ANKERMAKE\nPRINTER_MODEL_M5 printer_notes = Don not 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_ANKERMAKE\nPRINTER_MODEL_M5
[printer:AnkerMake M5 (0.4 mm nozzle)] [printer:AnkerMake M5 (0.4 mm nozzle)]
inherits = *M5* inherits = *M5*
@ -389,5 +362,5 @@ nozzle_diameter = 0.4
printer_variant = 0.4 printer_variant = 0.4
min_layer_height = 0.08 min_layer_height = 0.08
max_layer_height = 0.32 max_layer_height = 0.32
retract_lift_above = 0.2 retract_lift_above = 0
default_print_profile = "0.16 mm OPTIMAL (0.4 mm nozzle) @ANKER" default_print_profile = 0.2 mm OPTIMAL (0.4 mm nozzle) @ANKER

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,231 +1,246 @@
min_slic3r_version = 2.6.0-alpha1 min_slic3r_version = 2.6.0-alpha5
1.7.0-alpha0 Added profiles for Print With Smile filaments. 1.9.0-alpha1 Added profiles for Original Prusa MK4.
1.6.0-alpha2 Added profile for Prusament PETG Carbon Fiber and Fiberthree F3 PA-GF30 Pro. Updated acceleration settings for Prusa MINI. 1.9.0-alpha0 Updated output filename format.
1.6.0-alpha1 Updated FW version notification. Decreased min layer time for PLA. 1.7.0-alpha2 Updated compatibility condition in some filament profiles (Prusa XL).
1.6.0-alpha0 Default top fill set to monotonic lines. Updated infill/perimeter overlap values. Updated output filename format. Enabled dynamic overhang speeds. 1.7.0-alpha1 Added profiles for Original Prusa XL. Added filament profile for Prusament PETG Tungsten 75%.
min_slic3r_version = 2.5.0-alpha0 min_slic3r_version = 2.6.0-alpha1
1.5.7 Added filament profile for Prusament PETG Carbon Fiber and Fiberthree F3 PA-GF30 Pro. 1.7.0-alpha0 Added profiles for Print With Smile filaments.
1.5.6 Updated FW version notification (MK2.5/MK3 family). Added filament profile for Kimya PEBA-S. 1.6.0-alpha2 Added profile for Prusament PETG Carbon Fiber and Fiberthree F3 PA-GF30 Pro. Updated acceleration settings for Prusa MINI.
1.5.5 Added new Prusament Resin material profiles. Enabled g-code thumbnails for MK2.5 family printers. 1.6.0-alpha1 Updated FW version notification. Decreased min layer time for PLA.
1.5.4 Added material profiles for Prusament Resin BioBased60. 1.6.0-alpha0 Default top fill set to monotonic lines. Updated infill/perimeter overlap values. Updated output filename format. Enabled dynamic overhang speeds.
1.5.3 Added filament profiles for ColorFabb VarioShore TPU, FormFutura PP, NinjaTek NinjaFlex/Cheetah TPU and for multiple Eolas Prints filaments. Updated bridging settings in 50um and 70um profiles. min_slic3r_version = 2.5.1-rc0
1.5.2 Added SLA material profiles. 1.6.3 Added SLA materials.
1.5.1 Renamed filament type "NYLON" to "PA". Updated Adura X profile. Updated PETG fan settings for Prusa MINI (removed fan ramp up). 1.6.2 Updated compatibility condition in some filament profiles (Prusa XL).
1.5.0 Updated arachne parameters. Added profiles for Jessie filaments. 1.6.1 Added filament profile for Prusament PETG Tungsten 75%. Updated Prusa XL profiles.
1.5.0-alpha1 Added filament profile for Prusament PA11 Carbon Fiber. Added profiles for multiple 3D-Fuel filaments. 1.6.0 Added Original Prusa XL profiles. Updated acceleration settings for Prusa MINI. Updated infill/perimeter overlap values.
1.5.0-alpha0 Added parameters for Arachne perimeter generator. Changed default seam position. Updated output filename format. min_slic3r_version = 2.5.0-alpha0
min_slic3r_version = 2.4.0-rc 1.5.9 Added SLA materials.
1.4.9 Updated FW version notification. 1.5.8 Added filament profile for Prusament PETG Tungsten 75%. Updated FW version notification.
1.4.8 Added filament and SLA material profiles. Updated settings. 1.5.7 Added filament profile for Prusament PETG Carbon Fiber and Fiberthree F3 PA-GF30 Pro.
1.4.7 Added filament profile for Prusament PA11 Carbon Fiber. Added profiles for multiple 3D-Fuel filaments. 1.5.6 Updated FW version notification (MK2.5/MK3 family). Added filament profile for Kimya PEBA-S.
1.4.6 Added SLA materials. Updated filament profiles. 1.5.5 Added new Prusament Resin material profiles. Enabled g-code thumbnails for MK2.5 family printers.
1.4.5 Added MMU2/S profiles for 0.25mm nozzle. Updated FW version. Enabled g-code thumbnails for MK3 family printers. Updated end g-code. 1.5.4 Added material profiles for Prusament Resin BioBased60.
1.4.4 Added multiple Fiberlogy filament profiles. Updated Extrudr filament profiles. 1.5.3 Added filament profiles for ColorFabb VarioShore TPU, FormFutura PP, NinjaTek NinjaFlex/Cheetah TPU and for multiple Eolas Prints filaments. Updated bridging settings in 50um and 70um profiles.
1.4.3 Added new filament profiles and SLA materials. 1.5.2 Added SLA material profiles.
1.4.2 Added SLA material profiles. 1.5.1 Renamed filament type "NYLON" to "PA". Updated Adura X profile. Updated PETG fan settings for Prusa MINI (removed fan ramp up).
1.4.1 Updated firmware version. 1.5.0 Updated arachne parameters. Added profiles for Jessie filaments.
1.4.0 Updated for the PrusaSlicer 2.4.0-rc release. Updated SLA material colors. 1.5.0-alpha1 Added filament profile for Prusament PA11 Carbon Fiber. Added profiles for multiple 3D-Fuel filaments.
min_slic3r_version = 2.4.0-beta2 1.5.0-alpha0 Added parameters for Arachne perimeter generator. Changed default seam position. Updated output filename format.
1.4.0-beta3 Added material profiles for Prusament Resins. min_slic3r_version = 2.4.0-rc
1.4.0-beta2 Added SLA material colors. Updated BASF filament profiles. 1.4.10 Updated FW version notification.
min_slic3r_version = 2.4.0-beta0 1.4.9 Updated FW version notification.
1.4.0-beta1 Updated pad wall slope angle for SLA printers. Updated Filatech Filacarbon profile for Prusa MINI. 1.4.8 Added filament and SLA material profiles. Updated settings.
1.4.0-beta0 Added multiple Filatech and BASF filament profiles. Added material profiles for SL1S. 1.4.7 Added filament profile for Prusament PA11 Carbon Fiber. Added profiles for multiple 3D-Fuel filaments.
min_slic3r_version = 2.4.0-alpha0 1.4.6 Added SLA materials. Updated filament profiles.
1.4.0-alpha8 Added material profiles for Prusament Resin. Detect bridging perimeters enabled by default. 1.4.5 Added MMU2/S profiles for 0.25mm nozzle. Updated FW version. Enabled g-code thumbnails for MK3 family printers. Updated end g-code.
1.4.0-alpha7 Updated brim_separation value. Updated Prusa MINI end g-code. Added Filamentworld filament profiles. 1.4.4 Added multiple Fiberlogy filament profiles. Updated Extrudr filament profiles.
1.4.0-alpha6 Added nozzle priming after M600. Added nozzle diameter checks for 0.8 nozzle printer profiles. Updated FW version. Increased number of top solid infill layers (0.2 layer height). 1.4.3 Added new filament profiles and SLA materials.
1.4.0-alpha5 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S). 1.4.2 Added SLA material profiles.
1.4.0-alpha4 Decreased Area Fill (SL1S). 1.4.1 Updated firmware version.
1.4.0-alpha3 Updated SL1S tilt times. 1.4.0 Updated for the PrusaSlicer 2.4.0-rc release. Updated SLA material colors.
1.4.0-alpha2 Updated Prusa MINI machine limits. min_slic3r_version = 2.4.0-beta2
1.4.0-alpha1 Added new SL1S resin profiles. 1.4.0-beta3 Added material profiles for Prusament Resins.
1.4.0-alpha0 Bumped up config version. 1.4.0-beta2 Added SLA material colors. Updated BASF filament profiles.
1.3.0-alpha2 Added SL1S SPEED profiles. min_slic3r_version = 2.4.0-beta0
1.3.0-alpha1 Added Prusament PCCF. Increased travel acceleration for Prusa MINI. Updated start g-code for Prusa MINI. Added multiple add:north and Extrudr filament profiles. Updated Z travel speed values. 1.4.0-beta1 Updated pad wall slope angle for SLA printers. Updated Filatech Filacarbon profile for Prusa MINI.
1.3.0-alpha0 Disabled thick bridges, updated support settings. 1.4.0-beta0 Added multiple Filatech and BASF filament profiles. Added material profiles for SL1S.
min_slic3r_version = 2.3.2-alpha0 min_slic3r_version = 2.4.0-alpha0
1.3.8 Updated FW version notification. 1.4.0-alpha8 Added material profiles for Prusament Resin. Detect bridging perimeters enabled by default.
1.3.7 Updated firmware version. 1.4.0-alpha7 Updated brim_separation value. Updated Prusa MINI end g-code. Added Filamentworld filament profiles.
1.3.6 Updated firmware version. 1.4.0-alpha6 Added nozzle priming after M600. Added nozzle diameter checks for 0.8 nozzle printer profiles. Updated FW version. Increased number of top solid infill layers (0.2 layer height).
1.3.5 Added material profiles for Prusament Resins. 1.4.0-alpha5 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
1.3.4 Added material profiles for new Prusament Resins. Added profiles for multiple BASF filaments. 1.4.0-alpha4 Decreased Area Fill (SL1S).
1.3.3 Added multiple profiles for Filatech filaments. Added material profiles for SL1S SPEED. Updated SLA print settings. 1.4.0-alpha3 Updated SL1S tilt times.
1.3.2 Added material profiles for Prusament Resin. 1.4.0-alpha2 Updated Prusa MINI machine limits.
1.3.1 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S). 1.4.0-alpha1 Added new SL1S resin profiles.
1.3.0 Added SL1S SPEED profiles. 1.4.0-alpha0 Bumped up config version.
min_slic3r_version = 2.3.0-rc1 1.3.0-alpha2 Added SL1S SPEED profiles.
1.2.13 Updated FW version notification. 1.3.0-alpha1 Added Prusament PCCF. Increased travel acceleration for Prusa MINI. Updated start g-code for Prusa MINI. Added multiple add:north and Extrudr filament profiles. Updated Z travel speed values.
1.2.12 Updated firmware version. 1.3.0-alpha0 Disabled thick bridges, updated support settings.
1.2.11 Updated firmware version. min_slic3r_version = 2.3.2-alpha0
1.2.10 Added multiple profiles for Filatech filaments. Updated SLA print settings (pad wall slope angle). 1.3.9 Updated FW version notification.
1.2.9 Added material profiles for Prusament Resin. 1.3.8 Updated FW version notification.
1.2.8 Added multiple add:north and Extrudr filament profiles. 1.3.7 Updated firmware version.
1.2.7 Updated "Prusament PC Blend Carbon Fiber" profile for Prusa MINI. 1.3.6 Updated firmware version.
1.2.6 Added filament profile for "Prusament PC Blend Carbon Fiber". 1.3.5 Added material profiles for Prusament Resins.
1.2.5 Updated firmware version. Added filament profiles. Various improvements. 1.3.4 Added material profiles for new Prusament Resins. Added profiles for multiple BASF filaments.
1.2.4 Updated cost/density values in filament settings. Various changes in print settings. 1.3.3 Added multiple profiles for Filatech filaments. Added material profiles for SL1S SPEED. Updated SLA print settings.
1.2.3 Updated firmware version. Updated end g-code in MMU2 printer profiles. 1.3.2 Added material profiles for Prusament Resin.
1.2.2 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles. 1.3.1 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
1.2.1 Updated FW version for MK2.5 family printers. 1.3.0 Added SL1S SPEED profiles.
1.2.0 Added full_fan_speed_layer value for PETG. Increased support interface spacing for 0.6mm nozzle profiles. Updated firmware version. min_slic3r_version = 2.3.0-rc1
min_slic3r_version = 2.3.0-beta2 1.2.14 Updated FW version notification.
1.2.0-beta1 Updated end g-code. Added full_fan_speed_layer values. 1.2.13 Updated FW version notification.
min_slic3r_version = 2.3.0-beta0 1.2.12 Updated firmware version.
1.2.0-beta0 Adjusted infill anchor limits. Added filament spool weights. 1.2.11 Updated firmware version.
min_slic3r_version = 2.3.0-alpha4 1.2.10 Added multiple profiles for Filatech filaments. Updated SLA print settings (pad wall slope angle).
1.2.0-alpha1 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles. 1.2.9 Added material profiles for Prusament Resin.
1.2.0-alpha0 Added filament spool weights 1.2.8 Added multiple add:north and Extrudr filament profiles.
min_slic3r_version = 2.2.0-alpha3 1.2.7 Updated "Prusament PC Blend Carbon Fiber" profile for Prusa MINI.
1.1.17 Updated FW version notification. 1.2.6 Added filament profile for "Prusament PC Blend Carbon Fiber".
1.1.16 Updated firmware version. 1.2.5 Updated firmware version. Added filament profiles. Various improvements.
1.1.15 Updated firmware version. 1.2.4 Updated cost/density values in filament settings. Various changes in print settings.
1.1.14 Updated firmware version. 1.2.3 Updated firmware version. Updated end g-code in MMU2 printer profiles.
1.1.13 Updated firmware version. Updated end g-code in MMU2 printer profiles. 1.2.2 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles.
1.1.12 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles. 1.2.1 Updated FW version for MK2.5 family printers.
1.1.11 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles. 1.2.0 Added full_fan_speed_layer value for PETG. Increased support interface spacing for 0.6mm nozzle profiles. Updated firmware version.
1.1.10 Updated firmware version. min_slic3r_version = 2.3.0-beta2
1.1.9 Updated K values in filament profiles (linear advance). Added new filament profiles and SLA materials. 1.2.0-beta1 Updated end g-code. Added full_fan_speed_layer values.
1.1.8 Updated start/end g-code scripts for MK3 family printer profiles (reduced extruder motor current for some print profiles). Added new filament and SLA material profiles. min_slic3r_version = 2.3.0-beta0
1.1.7 Updated end g-code for MMU2 Single printer profiles. Added/updated filament and SLA material profiles. 1.2.0-beta0 Adjusted infill anchor limits. Added filament spool weights.
1.1.6 Updated firmware version for MK2.5/S and MK3/S. min_slic3r_version = 2.3.0-alpha4
1.1.5 Updated MMU1 specific retraction settings for Prusament PC Blend 1.2.0-alpha1 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
1.1.4 Added Prusament PC Blend filament profile. 1.2.0-alpha0 Added filament spool weights
1.1.3 Added SLA material and filament profile min_slic3r_version = 2.2.0-alpha3
1.1.2 Added renamed_from fields for PETG filaments to indicate that they were renamed from PET. 1.1.17 Updated FW version notification.
1.1.1 Added Verbatim and Fiberlogy PETG filament profiles. Updated auto cooling settings for ABS. 1.1.16 Updated firmware version.
1.1.1-beta Updated for PrusaSlicer 2.2.0-beta 1.1.15 Updated firmware version.
1.1.1-alpha4 Extended list of default filaments to be installed, top/bottom_solid_min_thickness defined, infill_acceleration changed etc 1.1.14 Updated firmware version.
1.1.1-alpha3 Print bed textures are now configurable from the Preset Bundle. Requires PrusaSlicer 2.2.0-alpha3 and newer. 1.1.13 Updated firmware version. Updated end g-code in MMU2 printer profiles.
# The following line (max_slic3r_version) forces the users of PrusaSlicer 2.2.0-alpha3 and newer to update the profiles to 1.1.1-alpha3 and newer, 1.1.12 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles.
# so they will see the print bed. 1.1.11 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
max_slic3r_version = 2.2.0-alpha2 1.1.10 Updated firmware version.
min_slic3r_version = 2.2.0-alpha0 1.1.9 Updated K values in filament profiles (linear advance). Added new filament profiles and SLA materials.
1.1.1-alpha2 Bumped up config version, so our in house customer will get updated profiles. 1.1.8 Updated start/end g-code scripts for MK3 family printer profiles (reduced extruder motor current for some print profiles). Added new filament and SLA material profiles.
1.1.0 Filament aliases, Creality profiles and other goodies for PrusaSlicer 2.2.0-alpha0 1.1.7 Updated end g-code for MMU2 Single printer profiles. Added/updated filament and SLA material profiles.
min_slic3r_version = 2.1.1-beta0 1.1.6 Updated firmware version for MK2.5/S and MK3/S.
1.0.13 Updated FW version notification. 1.1.5 Updated MMU1 specific retraction settings for Prusament PC Blend
1.0.12 Updated firmware version. 1.1.4 Added Prusament PC Blend filament profile.
1.0.11 Updated firmware version. 1.1.3 Added SLA material and filament profile
1.0.10 Updated firmware version for MK2.5/S and MK3/S. 1.1.2 Added renamed_from fields for PETG filaments to indicate that they were renamed from PET.
1.0.9 Updated firmware version for MK2.5/S and MK3/S. 1.1.1 Added Verbatim and Fiberlogy PETG filament profiles. Updated auto cooling settings for ABS.
1.0.8 Various changes in FFF profiles, new filaments/materials added. See changelog. 1.1.1-beta Updated for PrusaSlicer 2.2.0-beta
1.0.7 Updated layer height limits for MINI 1.1.1-alpha4 Extended list of default filaments to be installed, top/bottom_solid_min_thickness defined, infill_acceleration changed etc
1.0.6 Added Prusa MINI profiles 1.1.1-alpha3 Print bed textures are now configurable from the Preset Bundle. Requires PrusaSlicer 2.2.0-alpha3 and newer.
min_slic3r_version = 2.1.0-alpha0 # The following line (max_slic3r_version) forces the users of PrusaSlicer 2.2.0-alpha3 and newer to update the profiles to 1.1.1-alpha3 and newer,
1.0.5 Added SLA materials # so they will see the print bed.
1.0.4 Updated firmware version and 0.25mm nozzle profiles max_slic3r_version = 2.2.0-alpha2
1.0.3 Added filament profiles min_slic3r_version = 2.2.0-alpha0
1.0.2 Added SLA materials 1.1.1-alpha2 Bumped up config version, so our in house customer will get updated profiles.
1.0.1 Updated MK3 firmware version check to 3.8.0, new soluble support profiles for 0.6mm nozzle diameter MMU2S printers. 1.1.0 Filament aliases, Creality profiles and other goodies for PrusaSlicer 2.2.0-alpha0
1.0.0 Updated end G-code for the MMU2 profiles to lift the extruder at the end of print. Wipe tower bridging distance was made smaller for soluble supports. min_slic3r_version = 2.1.1-beta0
1.0.0-beta1 Updated color for the ASA filaments to differ from the other filaments. Single extruder printers now have no extruder color assigned, obects and toolpaths will be colored with the color of the active filament. 1.0.13 Updated FW version notification.
1.0.0-beta0 Printer model checks in start G-codes, ASA filament profiles, limits on min / max SL1 exposition times 1.0.12 Updated firmware version.
1.0.0-alpha2 Printer model and nozzle diameter check 1.0.11 Updated firmware version.
1.0.0-alpha1 Added Prusament ASA profile 1.0.10 Updated firmware version for MK2.5/S and MK3/S.
1.0.0-alpha0 Filament specific retract for PET and similar copolymers, and for FLEX 1.0.9 Updated firmware version for MK2.5/S and MK3/S.
min_slic3r_version = 1.42.0-alpha6 1.0.8 Various changes in FFF profiles, new filaments/materials added. See changelog.
0.8.11 Updated firmware version. 1.0.7 Updated layer height limits for MINI
0.8.10 Updated firmware version. 1.0.6 Added Prusa MINI profiles
0.8.9 Updated firmware version for MK2.5/S and MK3/S. min_slic3r_version = 2.1.0-alpha0
0.8.8 Updated firmware version for MK2.5/S and MK3/S. 1.0.5 Added SLA materials
0.8.7 Updated firmware version 1.0.4 Updated firmware version and 0.25mm nozzle profiles
0.8.6 Updated firmware version for MK2.5/S and MK3/S 1.0.3 Added filament profiles
0.8.5 Updated SL1 printer and material settings 1.0.2 Added SLA materials
0.8.4 Added Prusament ASA profile 1.0.1 Updated MK3 firmware version check to 3.8.0, new soluble support profiles for 0.6mm nozzle diameter MMU2S printers.
0.8.3 FW version and SL1 materials update 1.0.0 Updated end G-code for the MMU2 profiles to lift the extruder at the end of print. Wipe tower bridging distance was made smaller for soluble supports.
0.8.2 FFF and SL1 settings update 1.0.0-beta1 Updated color for the ASA filaments to differ from the other filaments. Single extruder printers now have no extruder color assigned, obects and toolpaths will be colored with the color of the active filament.
0.8.1 Output settings and SLA materials update 1.0.0-beta0 Printer model checks in start G-codes, ASA filament profiles, limits on min / max SL1 exposition times
0.8.0 Updated for the PrusaSlicer 2.0.0 final release 1.0.0-alpha2 Printer model and nozzle diameter check
0.8.0-rc2 Updated firmware versions for MK2.5/S and MK3/S 1.0.0-alpha1 Added Prusament ASA profile
0.8.0-rc1 Updated SLA profiles 1.0.0-alpha0 Filament specific retract for PET and similar copolymers, and for FLEX
0.8.0-rc Updated for the PrusaSlicer 2.0.0-rc release min_slic3r_version = 1.42.0-alpha6
0.8.0-beta4 Updated SLA profiles 0.8.11 Updated firmware version.
0.8.0-beta3 Updated SLA profiles 0.8.10 Updated firmware version.
0.8.0-beta2 Updated SLA profiles 0.8.9 Updated firmware version for MK2.5/S and MK3/S.
0.8.0-beta1 Updated SLA profiles 0.8.8 Updated firmware version for MK2.5/S and MK3/S.
0.8.0-beta Updated SLA profiles 0.8.7 Updated firmware version
0.8.0-alpha9 Updated SLA and FFF profiles 0.8.6 Updated firmware version for MK2.5/S and MK3/S
0.8.0-alpha8 Updated SLA profiles 0.8.5 Updated SL1 printer and material settings
0.8.0-alpha7 Updated SLA profiles 0.8.4 Added Prusament ASA profile
0.8.0-alpha6 Updated SLA profiles 0.8.3 FW version and SL1 materials update
min_slic3r_version = 1.42.0-alpha 0.8.2 FFF and SL1 settings update
0.8.0-alpha Updated SLA profiles 0.8.1 Output settings and SLA materials update
0.4.0-alpha4 Updated SLA profiles 0.8.0 Updated for the PrusaSlicer 2.0.0 final release
0.4.0-alpha3 Update of SLA profiles 0.8.0-rc2 Updated firmware versions for MK2.5/S and MK3/S
0.4.0-alpha2 First SLA profiles 0.8.0-rc1 Updated SLA profiles
min_slic3r_version = 1.41.3-alpha 0.8.0-rc Updated for the PrusaSlicer 2.0.0-rc release
0.4.12 Updated firmware version for MK2.5/S and MK3/S. 0.8.0-beta4 Updated SLA profiles
0.4.11 Updated firmware version for MK2.5/S and MK3/S. 0.8.0-beta3 Updated SLA profiles
0.4.10 Updated firmware version 0.8.0-beta2 Updated SLA profiles
0.4.9 Updated firmware version for MK2.5/S and MK3/S 0.8.0-beta1 Updated SLA profiles
0.4.8 MK2.5/3/S FW update 0.8.0-beta Updated SLA profiles
0.4.7 MK2/S/MMU FW update 0.8.0-alpha9 Updated SLA and FFF profiles
0.4.6 Updated firmware versions for MK2.5/S and MK3/S 0.8.0-alpha8 Updated SLA profiles
0.4.5 Enabled remaining time support for MK2/S/MMU1 0.8.0-alpha7 Updated SLA profiles
0.4.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt 0.8.0-alpha6 Updated SLA profiles
0.4.3 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt min_slic3r_version = 1.42.0-alpha
0.4.2 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt 0.8.0-alpha Updated SLA profiles
0.4.1 New MK2.5S and MK3S FW versions 0.4.0-alpha4 Updated SLA profiles
0.4.0 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt 0.4.0-alpha3 Update of SLA profiles
min_slic3r_version = 1.41.1 0.4.0-alpha2 First SLA profiles
0.3.11 Updated firmware version for MK2.5/S and MK3/S. min_slic3r_version = 1.41.3-alpha
0.3.10 Updated firmware version 0.4.12 Updated firmware version for MK2.5/S and MK3/S.
0.3.9 Updated firmware version for MK2.5/S and MK3/S 0.4.11 Updated firmware version for MK2.5/S and MK3/S.
0.3.8 MK2.5/3/S FW update 0.4.10 Updated firmware version
0.3.7 MK2/S/MMU FW update 0.4.9 Updated firmware version for MK2.5/S and MK3/S
0.3.6 Updated firmware versions for MK2.5 and MK3 0.4.8 MK2.5/3/S FW update
0.3.5 New MK2.5 and MK3 FW versions 0.4.7 MK2/S/MMU FW update
0.3.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt 0.4.6 Updated firmware versions for MK2.5/S and MK3/S
0.3.3 Prusament PETG released 0.4.5 Enabled remaining time support for MK2/S/MMU1
0.3.2 New MK2.5 and MK3 FW versions 0.4.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
0.3.1 New MK2.5 and MK3 FW versions 0.4.3 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
0.3.0 New MK2.5 and MK3 FW version 0.4.2 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
min_slic3r_version = 1.41.0-alpha 0.4.1 New MK2.5S and MK3S FW versions
0.2.9 New MK2.5 and MK3 FW versions 0.4.0 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
0.2.8 New MK2.5 and MK3 FW version min_slic3r_version = 1.41.1
min_slic3r_version = 1.41.1 0.3.11 Updated firmware version for MK2.5/S and MK3/S.
0.2.7 New MK2.5 and MK3 FW version 0.3.10 Updated firmware version
0.2.6 Added MMU2 MK2.5 settings 0.3.9 Updated firmware version for MK2.5/S and MK3/S
min_slic3r_version = 1.41.0-alpha 0.3.8 MK2.5/3/S FW update
0.2.5 Prusament is out - added prusament settings 0.3.7 MK2/S/MMU FW update
0.2.4 Added soluble support profiles for MMU2 0.3.6 Updated firmware versions for MK2.5 and MK3
0.2.3 Added materials for MMU2 single mode, edited MK3 xy stealth feedrate limit 0.3.5 New MK2.5 and MK3 FW versions
0.2.2 Edited MMU2 Single mode purge line 0.3.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
0.2.1 Added PET and BVOH settings for MMU2 0.3.3 Prusament PETG released
0.2.0-beta5 Fixed MMU1 ramming parameters 0.3.2 New MK2.5 and MK3 FW versions
0.2.0-beta4 Added filament loading speed at start, increased minimal purge on wipe tower 0.3.1 New MK2.5 and MK3 FW versions
0.2.0-beta3 Edited ramming parameters and filament cooling moves for MMU2 0.3.0 New MK2.5 and MK3 FW version
0.2.0-beta2 Edited first layer speed and wipe tower position min_slic3r_version = 1.41.0-alpha
0.2.0-beta Removed limit on the MK3MMU2 height, added legacy M204 S T format to the MK2 profiles 0.2.9 New MK2.5 and MK3 FW versions
0.2.0-alpha8 Added filament_load/unload_time for the PLA/ABS MMU2 filament presets. 0.2.8 New MK2.5 and MK3 FW version
0.2.0-alpha7 Vojtech's fix the incorrect *MK3* references min_slic3r_version = 1.41.1
0.2.0-alpha6 Jindra's way to fix the 0.2.0-alpha5 version 0.2.7 New MK2.5 and MK3 FW version
0.2.0-alpha5 Bumped up firmware versions for MK2.5/MK3 to 3.3.1, disabled priming areas for MK3MMU2 0.2.6 Added MMU2 MK2.5 settings
0.2.0-alpha4 Extended the custom start/end G-codes of the MMU2.0 printers for no priming towers. min_slic3r_version = 1.41.0-alpha
0.2.0-alpha3 Adjusted machine limits for time estimates, added filament density and cost 0.2.5 Prusament is out - added prusament settings
0.2.0-alpha2 Renamed the key MK3SMMU to MK3MMU2, added a generic PLA MMU2 material 0.2.4 Added soluble support profiles for MMU2
0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0 0.2.3 Added materials for MMU2 single mode, edited MK3 xy stealth feedrate limit
0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters 0.2.2 Edited MMU2 Single mode purge line
min_slic3r_version = 1.40.0 0.2.1 Added PET and BVOH settings for MMU2
0.1.18 Updated firmware version 0.2.0-beta5 Fixed MMU1 ramming parameters
0.1.17 Updated firmware version for MK2.5/S and MK3/S 0.2.0-beta4 Added filament loading speed at start, increased minimal purge on wipe tower
0.1.16 MK2.5/3/S FW update 0.2.0-beta3 Edited ramming parameters and filament cooling moves for MMU2
0.1.15 MK2/S/MMU FW update 0.2.0-beta2 Edited first layer speed and wipe tower position
0.1.14 Updated firmware versions for MK2.5 and MK3 0.2.0-beta Removed limit on the MK3MMU2 height, added legacy M204 S T format to the MK2 profiles
0.1.13 New MK2.5 and MK3 FW versions 0.2.0-alpha8 Added filament_load/unload_time for the PLA/ABS MMU2 filament presets.
0.1.12 New MK2.5 and MK3 FW versions 0.2.0-alpha7 Vojtech's fix the incorrect *MK3* references
0.1.11 fw version changed to 3.3.1 0.2.0-alpha6 Jindra's way to fix the 0.2.0-alpha5 version
0.1.10 MK3 jerk and acceleration update 0.2.0-alpha5 Bumped up firmware versions for MK2.5/MK3 to 3.3.1, disabled priming areas for MK3MMU2
0.1.9 edited support extrusion width for 0.25 and 0.6 nozzles 0.2.0-alpha4 Extended the custom start/end G-codes of the MMU2.0 printers for no priming towers.
0.1.8 extrusion width for 0,25, 0.6 and variable layer height fixes 0.2.0-alpha3 Adjusted machine limits for time estimates, added filament density and cost
0.1.7 Fixed errors in 0.25mm and 0.6mm profiles 0.2.0-alpha2 Renamed the key MK3SMMU to MK3MMU2, added a generic PLA MMU2 material
0.1.6 Split the MK2.5 profile from the MK2S 0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0
min_slic3r_version = 1.40.0-beta 0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters
0.1.5 fixed printer_variant fields for the i3 MK3 0.25 and 0.6mm nozzles min_slic3r_version = 1.40.0
0.1.4 edited fw version, added z-raise after print 0.1.18 Updated firmware version
min_slic3r_version = 1.40.0-alpha 0.1.17 Updated firmware version for MK2.5/S and MK3/S
0.1.3 Fixed an incorrect position of the max_print_height parameter 0.1.16 MK2.5/3/S FW update
0.1.2 Wipe tower changes 0.1.15 MK2/S/MMU FW update
0.1.1 Minor print speed adjustments 0.1.14 Updated firmware versions for MK2.5 and MK3
0.1.0 Initial 0.1.13 New MK2.5 and MK3 FW versions
0.1.12 New MK2.5 and MK3 FW versions
0.1.11 fw version changed to 3.3.1
0.1.10 MK3 jerk and acceleration update
0.1.9 edited support extrusion width for 0.25 and 0.6 nozzles
0.1.8 extrusion width for 0,25, 0.6 and variable layer height fixes
0.1.7 Fixed errors in 0.25mm and 0.6mm profiles
0.1.6 Split the MK2.5 profile from the MK2S
min_slic3r_version = 1.40.0-beta
0.1.5 fixed printer_variant fields for the i3 MK3 0.25 and 0.6mm nozzles
0.1.4 edited fw version, added z-raise after print
min_slic3r_version = 1.40.0-alpha
0.1.3 Fixed an incorrect position of the max_print_height parameter
0.1.2 Wipe tower changes
0.1.1 Minor print speed adjustments
0.1.0 Initial

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="svg3128" xmlns="http://www.w3.org/2000/svg" width="710.1" height="596.7" viewBox="0 0 710.1 596.7">
<line id="line2794" x1=".7" y1=".7" x2=".7" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2796" x1="142.4" y1=".7" x2="142.4" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2798" x1="284.2" y1=".7" x2="284.2" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2800" x1="709.4" y1="596" x2="709.4" y2=".7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2802" x1="1.2" y1="581.8" x2="709.4" y2="581.8" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2804" x1=".7" y1="596" x2="709.4" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2806" x1="1.2" y1="440.1" x2="709.4" y2="440.1" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2808" x1="1.2" y1="298.4" x2="709.4" y2="298.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2810" x1="1.2" y1="156.6" x2="709.4" y2="156.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2812" x1="1.2" y1="14.9" x2="709.4" y2="14.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2814" x1="709.4" y1=".7" x2=".7" y2=".7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2816" x1="425.9" y1=".7" x2="425.9" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2818" x1="425.9" y1="522.5" x2="425.9" y2="595.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2820" x1="567.6" y1=".7" x2="567.6" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2822" x1="567.6" y1="522.5" x2="567.6" y2="527.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2824" x1="567.6" y1="548.6" x2="567.6" y2="595.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
<line id="line2826" x1="85.8" y1=".7" x2="85.8" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2828" x1="114.1" y1=".7" x2="114.1" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2830" x1="170.8" y1=".7" x2="170.8" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2832" x1="199.1" y1=".7" x2="199.1" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2834" x1="227.5" y1=".7" x2="227.5" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2836" x1="255.8" y1=".7" x2="255.8" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2838" x1="312.5" y1=".7" x2="312.5" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2840" x1="340.9" y1=".7" x2="340.9" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2842" x1="681" y1=".7" x2="681" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2844" x1="29.1" y1=".7" x2="29.1" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2846" x1="57.4" y1=".7" x2="57.4" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2848" x1="1.5" y1="468.4" x2="709.4" y2="468.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2850" x1="1.5" y1="496.8" x2="709.4" y2="496.8" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2852" x1="1.5" y1="525.1" x2="709.4" y2="525.1" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2854" x1="1.5" y1="553.5" x2="709.4" y2="553.5" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2856" x1="1.5" y1="411.7" x2="709.4" y2="411.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2858" x1="1.5" y1="383.4" x2="709.4" y2="383.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2860" x1="1.5" y1="355" x2="709.4" y2="355" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2862" x1="1.5" y1="326.7" x2="709.4" y2="326.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2864" x1="1.5" y1="270" x2="709.4" y2="270" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2866" x1="1.5" y1="241.6" x2="709.4" y2="241.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2868" x1="1.5" y1="213.3" x2="709.4" y2="213.3" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2870" x1="1.5" y1="185" x2="709.4" y2="185" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2872" x1="1.5" y1="128.3" x2="709.4" y2="128.3" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2874" x1="1.5" y1="99.9" x2="709.4" y2="99.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2876" x1="1.5" y1="71.6" x2="709.4" y2="71.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2878" x1="1.5" y1="43.2" x2="709.4" y2="43.2" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2880" x1="369.2" y1=".7" x2="369.2" y2="522.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2882" x1="369.2" y1="522.6" x2="369.2" y2="595.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2884" x1="397.6" y1=".7" x2="397.6" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2886" x1="397.5" y1="522.6" x2="397.5" y2="595.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2888" x1="454.2" y1=".7" x2="454.2" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2890" x1="454.3" y1="522.6" x2="454.3" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2892" x1="482.6" y1=".7" x2="482.6" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2894" x1="482.6" y1="522.6" x2="482.6" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2896" x1="510.9" y1=".7" x2="510.9" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2898" x1="510.9" y1="522.6" x2="510.9" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2900" x1="539.3" y1=".7" x2="539.3" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2902" x1="539.3" y1="522.6" x2="539.3" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2904" x1="596" y1=".7" x2="596" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2906" x1="624.3" y1=".7" x2="624.3" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2908" x1="652.7" y1=".7" x2="652.7" y2="522.5" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2910" x1="652.7" y1="522.5" x2="652.7" y2="527.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2912" x1="652.6" y1="548.3" x2="652.6" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2914" x1="624.3" y1="522.5" x2="624.3" y2="527.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2916" x1="624.3" y1="548.3" x2="624.3" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2918" x1="596" y1="522.5" x2="596" y2="527.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<line id="line2920" x1="596" y1="548.3" x2="596" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
<path id="path3098" d="m548.6,532h2.1v4.8h0c.1-.2.3-.4.5-.6.2-.2.4-.3.7-.5.2-.1.5-.2.8-.3.3,0,.5-.1.8,0,.7,0,1.3.1,1.9.4.5.2,1,.6,1.4,1.1.4.5.6,1,.8,1.6.2.6.3,1.3.3,1.9,0,.6,0,1.2-.2,1.8-.2.6-.4,1.1-.7,1.6-.7,1-1.8,1.5-3,1.5-.3,0-.6,0-1,0-.3,0-.6-.1-.9-.2-.3-.1-.5-.3-.8-.5-.2-.2-.4-.5-.6-.8h0v1.3h-2v-12.9Zm7.2,8.2c0-.4,0-.8-.2-1.2-.1-.4-.3-.7-.5-1-.2-.3-.5-.6-.8-.7-.3-.2-.7-.3-1.1-.3-.8,0-1.5.3-2,.9-.5.7-.7,1.6-.7,2.4,0,.4,0,.9.2,1.3.1.4.3.7.5,1,.2.3.5.5.8.7.3.2.7.3,1.1.2.4,0,.8,0,1.2-.3.3-.2.6-.4.8-.7.2-.3.4-.7.5-1,0-.4.1-.8.1-1.2Z" style="fill: #fff;"/>
<path id="path3100" d="m558.5,535.6h2.2l2.4,7h0l2.4-7h2.1l-3.6,9.8c-.2.4-.3.8-.5,1.2-.2.4-.4.7-.6,1-.2.3-.5.5-.9.7-.4.2-.9.3-1.3.3-.5,0-1,0-1.4-.1v-1.7h.5c.2,0,.3,0,.5,0,.2,0,.4,0,.6,0,.1,0,.3-.1.4-.3.1-.1.2-.3.3-.4,0-.2.1-.4.2-.5l.2-.7-3.5-9.2Z" style="fill: #fff;"/>
<path id="path3102" d="m581.1,540.8c0,.5,0,1.1-.1,1.6,0,.5-.3,1-.6,1.4-.3.4-.8.8-1.3,1-.7.3-1.5.4-2.2.4-.6,0-1.2,0-1.7-.3-.5-.2-.9-.5-1.2-.9-.3-.4-.6-.8-.7-1.3-.1-.5-.2-1.1-.2-1.6v-.7h2.2v.7c0,.6,0,1.2.4,1.7.3.4.9.7,1.4.6.3,0,.6,0,.9-.2.2-.1.4-.3.6-.5.1-.2.2-.5.3-.8,0-.4,0-.7,0-1.1v-8.8h2.2v8.7Z" style="fill: #fff;"/>
<path id="path3104" d="m587.8,545.1c-.7,0-1.4-.1-2-.4-.6-.2-1.1-.6-1.5-1-.4-.4-.7-1-.9-1.5-.2-.6-.3-1.3-.3-2,0-.7,0-1.4.3-2,.2-.6.5-1.1.9-1.5.4-.4.9-.8,1.5-1,1.3-.5,2.7-.5,4,0,.6.2,1.1.6,1.5,1,.4.4.7,1,.9,1.5.2.6.3,1.3.3,2,0,.7,0,1.4-.3,2-.2.6-.5,1.1-.9,1.5-.4.4-.9.8-1.5,1-.6.3-1.3.4-2,.4Zm0-1.6c.4,0,.8,0,1.2-.3.3-.2.6-.4.8-.8.2-.3.4-.7.5-1.1.1-.4.2-.8.2-1.2,0-.4,0-.8-.2-1.2,0-.4-.3-.7-.5-1-.2-.3-.5-.6-.8-.8-.7-.4-1.6-.4-2.4,0-.3.2-.6.4-.8.8-.2.3-.4.6-.5,1,0,.4-.1.8-.2,1.2,0,.4,0,.8.2,1.2,0,.4.3.7.5,1.1.2.3.5.6.8.8.4.2.8.3,1.2.3h0Z" style="fill: #fff;"/>
<path id="path3106" d="m595.7,541.9c0,.5.3,1,.7,1.3.4.2.9.4,1.4.4.2,0,.4,0,.7,0,.2,0,.5,0,.7-.2.2,0,.4-.2.5-.4.3-.4.2-.9,0-1.3-.2-.2-.4-.3-.7-.4-.3-.1-.7-.2-1-.3l-1.1-.2c-.4,0-.7-.2-1.1-.3-.4-.1-.7-.3-1-.5-.3-.2-.5-.5-.6-.9-.2-.4-.3-.8-.2-1.2,0-.5.1-.9.4-1.3.2-.3.6-.6.9-.8.4-.2.8-.4,1.3-.4.4,0,.9-.1,1.3-.1.5,0,.9,0,1.4.2.4,0,.8.3,1.2.5.4.2.7.5.9.9.2.4.4.9.4,1.3h-2.1c0-.4-.3-.8-.7-1-.4-.2-.8-.3-1.2-.2-.2,0-.3,0-.5,0-.2,0-.4,0-.6.1-.2,0-.3.2-.4.3-.1.1-.2.3-.2.5,0,.2,0,.5.3.6.2.2.4.3.7.4.3.1.7.2,1,.3l1.1.2c.4,0,.7.2,1.1.3.4.1.7.3,1,.5.3.2.5.5.7.8.2.4.3.8.3,1.2,0,.5-.1,1-.4,1.4-.3.4-.6.7-1,.9-.4.2-.9.4-1.3.5-.5.1-1,.2-1.5.2-.5,0-1.1,0-1.6-.2-.5-.1-.9-.3-1.3-.6-.4-.3-.7-.6-.9-1-.2-.4-.3-.9-.3-1.4h2Z" style="fill: #fff;"/>
<path id="path3108" d="m605.1,540.8c0,.3,0,.7.2,1,0,.3.3.6.5.9.2.3.5.5.8.6.4.2.7.2,1.1.2.5,0,1.1,0,1.5-.3.4-.3.7-.7.8-1.2h1.9c0,.5-.3.9-.6,1.3-.3.4-.6.7-1,1-.4.3-.8.5-1.2.6-.5.1-1,.2-1.5.2-.7,0-1.3-.1-1.9-.4-.5-.2-1-.6-1.4-1-.4-.4-.7-1-.9-1.5-.2-.6-.3-1.3-.3-2,0-.6.1-1.3.3-1.9.2-.6.5-1.1.9-1.6.8-1,2-1.5,3.3-1.5.7,0,1.4.1,2,.5.6.3,1.1.7,1.5,1.2.4.5.7,1.1.8,1.7.2.7.2,1.3.1,2h-6.9Zm4.8-1.3c0-.3,0-.6-.2-.9-.1-.3-.3-.6-.5-.8-.2-.2-.4-.4-.7-.5-.3-.1-.6-.2-.9-.2-.3,0-.7,0-1,.2-.3.1-.5.3-.8.5-.2.2-.4.5-.5.8-.1.3-.2.7-.2,1h4.8Z" style="fill: #fff;"/>
<path id="path3110" d="m612.6,535.6h1.5v-.8c0-.5,0-1,.2-1.4.1-.3.3-.6.6-.8.2-.2.5-.3.8-.4.3,0,.7-.1,1,0,.5,0,.9,0,1.4,0v1.6c-.1,0-.3,0-.4,0h-.5c-.3,0-.5,0-.7.2-.2.2-.3.5-.3.8v1h1.7v1.5h-1.7v7.8h-2v-7.8h-1.5v-1.5Z" style="fill: #fff;"/>
<path id="path3112" d="m624.5,532h5.7c.8,0,1.5.1,2.2.4.5.2,1,.6,1.3,1,.3.4.5.8.6,1.3.1.4.2.9.2,1.3,0,.4,0,.9-.2,1.3-.1.5-.3.9-.6,1.3-.4.4-.8.8-1.3,1-.7.3-1.5.4-2.2.4h-3.4v4.9h-2.2v-12.9Zm2.2,6.1h3.3c.3,0,.5,0,.8-.1.3,0,.5-.2.7-.3.2-.2.4-.4.5-.7.1-.3.2-.7.2-1,0-.3,0-.7-.2-1-.2-.5-.7-.9-1.2-1-.3,0-.6,0-.8,0h-3.3v4.2Z" style="fill: #fff;"/>
<path id="path3114" d="m636.2,535.6h1.9v1.8h0c0-.3.2-.5.4-.7.2-.2.4-.5.6-.7.2-.2.5-.4.8-.5.3-.1.6-.2.9-.2h.8v2h-.4c-.1,0-.3,0-.5,0-.7,0-1.3.3-1.8.8-.2.3-.4.6-.5,1-.1.4-.2.9-.2,1.4v4.4h-2v-9.3Z" style="fill: #fff;"/>
<path id="path3116" d="m650.7,544.9h-2v-1.3h0c-.3.5-.7.9-1.1,1.1-.5.3-1,.4-1.5.4-1,0-1.9-.2-2.7-.9-.6-.8-.9-1.8-.8-2.7v-5.9h2v5.7c0,.6.1,1.2.5,1.7.3.3.8.5,1.3.5.4,0,.7,0,1.1-.2.3-.1.5-.3.7-.5.2-.2.3-.5.4-.8,0-.3.1-.7.1-1v-5.4h2v9.3Z" style="fill: #fff;"/>
<path id="path3118" d="m654.4,541.9c0,.5.3,1,.7,1.2.4.2.9.4,1.4.4.2,0,.4,0,.7,0,.2,0,.5,0,.7-.2.2,0,.4-.2.5-.4.1-.2.2-.4.2-.6,0-.2-.1-.5-.3-.7-.2-.2-.4-.3-.7-.4-.3-.1-.7-.2-1-.3l-1.1-.2c-.4,0-.7-.2-1.1-.3-.4-.1-.7-.3-1-.5-.3-.2-.5-.5-.7-.8-.2-.4-.3-.8-.3-1.2,0-.5.1-.9.4-1.3.2-.3.6-.6.9-.8.4-.2.8-.4,1.3-.4.4,0,.9-.1,1.3-.1.5,0,.9,0,1.4.2.4.1.8.3,1.2.5.4.2.7.5.9.9.2.4.4.9.4,1.3h-2.1c0-.4-.3-.8-.7-1-.4-.2-.8-.3-1.2-.2-.2,0-.3,0-.5,0-.2,0-.4,0-.5.1-.2,0-.3.2-.4.3-.1.1-.2.3-.2.5,0,.2,0,.5.3.6.2.2.4.3.7.4.3.1.7.2,1,.3l1.1.2c.4,0,.7.2,1.1.3.4.1.7.3,1,.5.3.2.5.5.7.8.2.4.3.8.3,1.2,0,.5-.1,1-.4,1.4-.3.4-.6.7-1,.9-.4.2-.9.4-1.3.5-.5.1-1,.2-1.5.2-.6,0-1.1,0-1.6-.2-.5-.1-.9-.3-1.3-.6-.4-.3-.7-.6-.9-1-.2-.4-.3-.9-.3-1.4h2.1Z" style="fill: #fff;"/>
<path id="path3120" d="m670,542.8c0,.2,0,.4,0,.5,0,.1.2.2.4.2h.5v1.4h-.3c0,0-.3.2-.3.2h-.4c-.1,0-.2,0-.3,0-.3,0-.7,0-1-.2-.3-.2-.5-.5-.5-.9-.4.4-.9.7-1.5.9-.6.2-1.1.3-1.7.3-.4,0-.8,0-1.2-.2-.4-.1-.7-.3-1-.5-.3-.2-.5-.5-.7-.8-.2-.4-.3-.8-.3-1.2,0-.5,0-1,.3-1.4.2-.3.5-.6.8-.8.4-.2.7-.4,1.2-.4.4,0,.9-.2,1.3-.2.3,0,.7-.1,1.1-.2.3,0,.6,0,.9-.2.2,0,.4-.2.6-.3.2-.2.2-.4.2-.7,0-.2,0-.5-.2-.7-.1-.2-.3-.3-.5-.4-.2,0-.4-.2-.6-.2-.2,0-.4,0-.7,0-.5,0-1,.1-1.4.4-.4.3-.6.7-.6,1.1h-2c0-.5.2-1,.4-1.5.3-.4.6-.7,1-1,.4-.2.9-.4,1.3-.5.5-.1,1-.2,1.5-.2.5,0,.9,0,1.3.2.4,0,.8.2,1.2.5.3.2.6.5.8.8.2.4.3.8.3,1.2v4.8Zm-2.2-2.6c-.3.2-.7.3-1.2.4-.5,0-.9.1-1.4.2-.2,0-.4,0-.6.2-.2,0-.4.1-.5.3-.2.1-.3.3-.4.5,0,.2-.1.4-.1.7,0,.2,0,.4.2.6.1.2.3.3.5.4.2,0,.4.2.6.2.2,0,.4,0,.6,0,.2,0,.5,0,.7,0,.3,0,.5-.2.8-.3.2-.1.4-.3.6-.5.2-.2.2-.5.2-.8v-1.5Z" style="fill: #fff;"/>
<g>
<path d="m385.6,511.3c0-1.3.2-2.6.6-3.7s1-2.1,1.7-3c.7-.9,1.7-1.5,2.8-2,1.1-.5,2.3-.7,3.7-.7s2.6.2,3.7.7c1.1.5,2,1.2,2.8,2s1.3,1.8,1.7,3,.6,2.4.6,3.7-.2,2.5-.6,3.6-1,2.1-1.7,2.9c-.7.8-1.7,1.5-2.8,2-1.1.5-2.3.7-3.7.7s-2.6-.2-3.7-.7c-1.1-.5-2-1.1-2.8-2-.7-.8-1.3-1.8-1.7-2.9-.4-1.1-.6-2.3-.6-3.6Zm3.9,0c0,.7.1,1.5.3,2.2.2.7.4,1.3.9,1.9.4.6.9,1,1.5,1.4s1.4.5,2.2.5,1.6-.2,2.2-.5,1.1-.8,1.5-1.4c.4-.6.6-1.2.9-1.9.2-.7.3-1.4.3-2.2s-.1-1.5-.3-2.3c-.2-.7-.4-1.4-.9-1.9-.4-.6-.9-1-1.5-1.4-.6-.3-1.4-.5-2.2-.5s-1.6.2-2.2.5c-.6.3-1.1.8-1.5,1.4s-.6,1.2-.9,1.9c-.2.7-.3,1.5-.3,2.3Z" style="fill: #959998;"/>
<path d="m404.8,502.3h9.6c.8,0,1.5.1,2.1.4.6.3,1.2.6,1.6,1.1.4.4.8,1,1.1,1.6.2.6.4,1.2.4,1.9,0,1.1-.2,1.9-.6,2.7-.4.7-1.2,1.4-2.1,1.7h0c.5.2.9.4,1.2.6s.6.6.8,1c.2.4.3.8.4,1.2s.2.9.2,1.3,0,.6,0,1,0,.8.1,1.2c0,.4.1.8.2,1.1.1.4.2.7.4.9h-3.9c-.1-.3-.2-.6-.3-.9,0-.3-.1-.7-.1-1.1s0-.7-.1-1.2c0-.4,0-.7-.1-1.1-.1-.9-.4-1.6-.9-2s-1.1-.6-2.1-.6h-3.9v6.9h-3.9v-17.7Zm3.9,8.1h4.3c.9,0,1.6-.2,2-.6.4-.4.7-1.1.7-1.9s-.2-1.5-.7-1.9-1.1-.6-2-.6h-4.3v5Z" style="fill: #959998;"/>
<path d="m421.8,502.3h3.9v17.8h-3.9v-17.8Z" style="fill: #959998;"/>
<path d="m441,518.1c-.7.9-1.5,1.5-2.3,1.9s-1.7.5-2.6.5c-1.4,0-2.6-.2-3.7-.7-1.1-.5-2-1.1-2.8-2-.7-.8-1.3-1.8-1.7-2.9-.4-1.1-.6-2.3-.6-3.6s.2-2.6.6-3.7,1-2.1,1.7-3c.7-.9,1.7-1.5,2.8-2,1.1-.5,2.3-.7,3.7-.7s1.8.1,2.7.4c.9.3,1.6.7,2.3,1.2s1.3,1.2,1.7,2,.7,1.7.9,2.7h-3.7c-.2-1-.7-1.7-1.4-2.2s-1.5-.7-2.4-.7-1.6.2-2.2.5-1.1.8-1.5,1.4c-.4.6-.6,1.2-.9,1.9-.2.7-.3,1.5-.3,2.3s.1,1.5.3,2.2c.2.7.4,1.3.9,1.9.4.6.9,1,1.5,1.4.6.3,1.4.5,2.2.5,1.3,0,2.3-.3,3-1s1.1-1.6,1.3-2.9h-3.9v-2.9h7.5v9.6h-2.5l-.4-2Z" style="fill: #959998;"/>
<path d="m446.3,502.3h3.9v17.8h-3.9v-17.8Z" style="fill: #959998;"/>
<path d="m452.7,502.3h3.9l7.4,11.9h0v-11.9h3.7v17.8h-3.9l-7.4-11.9h0v11.9h-3.7v-17.8Z" style="fill: #959998;"/>
<path d="m475.1,502.3h4l6.6,17.8h-4l-1.4-3.9h-6.6l-1.4,3.9h-3.9l6.7-17.8Zm-.4,10.9h4.6l-2.2-6.5h0l-2.3,6.5Z" style="fill: #959998;"/>
<path d="m486.5,502.3h3.9v14.5h8.6v3.3h-12.6v-17.8h0Z" style="fill: #959998;"/>
</g>
<g>
<path d="m506.9,502.3h8c1.1,0,2.1.2,2.8.5s1.4.7,1.9,1.3c.5.5.9,1.2,1.1,1.8.2.7.3,1.4.3,2.1s-.1,1.4-.3,2.1-.6,1.3-1.1,1.8c-.5.5-1.1,1-1.9,1.3s-1.7.5-2.8.5h-4.1v6.4h-3.9v-17.8Zm3.9,8.4h3c.4,0,.9,0,1.3-.1.4,0,.8-.2,1.1-.4.3-.2.6-.5.7-.8.2-.3.3-.8.3-1.4s-.1-1-.3-1.4c-.2-.3-.4-.6-.7-.8-.3-.2-.7-.3-1.1-.4s-.9-.1-1.3-.1h-3v5.3Z" style="fill: #fff;"/>
<path d="m522.2,502.3h9.6c.8,0,1.5.1,2.1.4.6.3,1.2.6,1.6,1.1.4.4.8,1,1.1,1.6.2.6.4,1.2.4,1.9,0,1.1-.2,1.9-.6,2.7-.4.7-1.2,1.4-2.1,1.7h0c.5.2.9.4,1.2.6s.6.6.8,1c.2.4.3.8.4,1.2s.2.9.2,1.3,0,.6,0,1,0,.8.1,1.2c0,.4.1.8.2,1.1.1.4.2.7.4.9h-3.9c-.1-.3-.2-.6-.3-.9,0-.3-.1-.7-.1-1.1s0-.7-.1-1.2c0-.4,0-.7-.1-1.1-.1-.9-.4-1.6-.9-2s-1.1-.6-2.1-.6h-3.9v6.9h-3.9v-17.7Zm3.9,8.1h4.3c.9,0,1.5-.2,2-.6.4-.4.7-1.1.7-1.9s-.2-1.5-.7-1.9-1.1-.6-2-.6h-4.3v5Z" style="fill: #fff;"/>
<path d="m554.1,513.3c0,2.4-.7,4.2-2,5.4-1.4,1.2-3.2,1.8-5.6,1.8s-4.3-.6-5.6-1.8c-1.3-1.2-2-3-2-5.4v-11.1h3.9v11.1c0,.5,0,1,.1,1.4,0,.5.3.9.5,1.3.3.4.6.6,1.1.9.5.2,1.1.3,1.9.3,1.4,0,2.3-.3,2.9-.9s.8-1.6.8-2.9v-11.1h3.9v11h0Z" style="fill: #fff;"/>
<path d="m559.1,514.2c0,.6.1,1.1.3,1.5.2.4.5.7.9,1s.8.4,1.3.6,1,.2,1.5.2.7,0,1.1-.1.8-.2,1.1-.3.6-.4.9-.7c.2-.3.3-.6.3-1.1s-.2-.9-.5-1.2-.7-.5-1.2-.7c-.5-.2-1.1-.4-1.7-.5s-1.3-.3-1.9-.5c-.7-.2-1.3-.4-1.9-.6-.6-.2-1.2-.5-1.7-.9s-.9-.9-1.2-1.4c-.3-.6-.5-1.3-.5-2.1s.2-1.7.6-2.4.9-1.2,1.5-1.7,1.4-.8,2.1-1,1.6-.3,2.4-.3,1.8.1,2.7.3,1.6.5,2.3,1,1.2,1.1,1.6,1.8.6,1.6.6,2.6h-3.8c0-.5-.1-1-.3-1.3s-.4-.6-.7-.8-.7-.3-1.1-.4-.9-.1-1.3-.1-.6,0-1,.1c-.3,0-.6.2-.9.3-.3.2-.5.4-.6.6s-.2.6-.2.9,0,.6.2.9c.1.2.4.4.8.6s.9.4,1.6.5c.7.2,1.6.4,2.7.7.2,0,.5.1.9.2.3.1.7.2,1.1.4.4.2.8.4,1.2.6.4.2.7.5,1.1.9.3.4.6.8.8,1.3.2.5.3,1.1.3,1.8s-.2,1.6-.5,2.3c-.3.7-.8,1.3-1.4,1.8s-1.4.9-2.3,1.2c-.9.3-2,.4-3.2.4s-1.9-.1-2.9-.4-1.7-.6-2.4-1.2-1.3-1.2-1.7-2c-.4-.8-.6-1.7-.6-2.8h3.8Z" style="fill: #fff;"/>
<path d="m576.5,502.3h4l6.6,17.8h-4l-1.4-3.9h-6.6l-1.4,3.9h-3.9l6.7-17.8Zm-.4,10.9h4.6l-2.2-6.5h0l-2.3,6.5Z" style="fill: #fff;"/>
</g>
<g>
<path d="m594.3,502.3h5.5l4.1,12.2h0l3.9-12.2h5.5v17.8h-3.7v-12.6h0l-4.4,12.6h-3l-4.4-12.5h0v12.5h-3.7v-17.8h0Z" style="fill: #ed6b21;"/>
<path d="m616,502.3h3.9v7.4l6.9-7.4h4.9l-6.9,7,7.6,10.7h-4.9l-5.3-8-2.2,2.3v5.7h-3.9v-17.8Z" style="fill: #ed6b21;"/>
<path d="m638.4,516.1h-7.4v-3.2l7.6-10.2h3.2v10.5h2.3v2.9h-2.3v4h-3.4v-4h0Zm0-9h0l-4.5,6.1h4.6v-6.1Z" style="fill: #ed6b21;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="360mm" height="360mm" viewBox="0 0 1020.5 1020.5">
<rect width="1020.5" height="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 5.7px;"/>
<g>
<rect width="1020.5" height="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="992.1" x2="1020.5" y2="992.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="954" y1="963.8" x2="1020.5" y2="963.8" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="963.8" x2="576.3" y2="963.8" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="935.4" x2="1020.5" y2="935.4" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="907.1" x2="1020.5" y2="907.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="878.7" x2="1020.5" y2="878.7" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="850.4" x2="1020.5" y2="850.4" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="822" x2="1020.5" y2="822" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="793.7" x2="1020.5" y2="793.7" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="765.4" x2="1020.5" y2="765.4" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="737" x2="1020.5" y2="737" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="708.7" x2="1020.5" y2="708.7" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="680.3" x2="1020.5" y2="680.3" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="652" x2="1020.5" y2="652" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="623.6" x2="1020.5" y2="623.6" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="595.3" x2="1020.5" y2="595.3" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="566.9" x2="1020.5" y2="566.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="538.6" x2="1020.5" y2="538.6" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="510.2" x2="1020.5" y2="510.2" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="481.9" x2="1020.5" y2="481.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="453.5" x2="1020.5" y2="453.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="425.2" x2="1020.5" y2="425.2" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="396.9" x2="1020.5" y2="396.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="368.5" x2="1020.5" y2="368.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="340.2" x2="1020.5" y2="340.2" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="311.8" x2="1020.5" y2="311.8" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="283.5" x2="1020.5" y2="283.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="255.1" x2="1020.5" y2="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="226.8" x2="1020.5" y2="226.8" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="198.4" x2="1020.5" y2="198.4" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="170.1" x2="1020.5" y2="170.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="141.7" x2="1020.5" y2="141.7" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="113.4" x2="1020.5" y2="113.4" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="85" x2="1020.5" y2="85" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="56.7" x2="1020.5" y2="56.7" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line y1="28.3" x2="1020.5" y2="28.3" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="992.1" x2="992.1" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="963.8" x2="963.8" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="935.4" y1="984.3" x2="935.4" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="935.4" x2="935.4" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="907.1" y1="984.3" x2="907.1" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="907.1" x2="907.1" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="878.8" y1="984.3" x2="878.7" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="878.7" x2="878.7" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="850.5" y1="984.3" x2="850.4" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="850.4" x2="850.4" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="822.1" y1="984.3" x2="822" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="822" x2="822" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="793.8" y1="984.3" x2="793.7" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="793.7" x2="793.7" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="765.4" x2="765.4" y2="935.4" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="737" y1="984.2" x2="737" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="737" x2="737" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="708.7" y1="984.2" x2="708.7" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="708.7" x2="708.7" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="680.3" y1="984.2" x2="680.3" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="680.3" x2="680.3" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="652" y1="984.2" x2="652" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="652" x2="652" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="623.6" y1="984.2" x2="623.6" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="623.6" x2="623.6" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="595.3" y1="984.2" x2="595.3" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="595.3" x2="595.3" y2="944.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="566.9" x2="566.9" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="538.6" x2="538.6" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="510.2" x2="510.2" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="481.9" x2="481.9" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="453.5" x2="453.5" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="425.2" x2="425.2" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="396.9" x2="396.9" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="368.5" x2="368.5" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="340.2" x2="340.2" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="311.8" x2="311.8" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="283.5" x2="283.5" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="255.1" x2="255.1" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="226.8" x2="226.8" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="198.4" x2="198.4" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="170.1" x2="170.1" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="141.7" x2="141.7" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="113.4" x2="113.4" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="85" x2="85" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="56.7" x2="56.7" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
<line x1="28.3" x2="28.3" y2="1020.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: .7px;"/>
</g>
<rect y="765.4" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="255.1" y="765.4" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<polyline points="765.4 992.1 765.4 1020.5 510.2 1020.5 510.2 765.4 765.4 765.4 765.4 935.4" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<polyline points="765.4 944.9 765.4 765.4 1020.5 765.4 1020.5 1020.5 765.4 1020.5 765.4 984.2" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect y="510.2" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="255.1" y="510.2" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="510.2" y="510.2" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="765.4" y="510.2" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect y="255.1" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="255.1" y="255.1" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="510.2" y="255.1" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="765.4" y="255.1" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="255.1" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="510.2" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<rect x="765.4" width="255.1" height="255.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 1.4px;"/>
<g>
<path d="m584.3,964.3c0-1.9.3-3.7.9-5.3.6-1.7,1.4-3.1,2.5-4.3,1.1-1.2,2.4-2.2,4-2.9,1.6-.7,3.3-1,5.3-1s3.8.3,5.3,1c1.6.7,2.9,1.7,4,2.9,1.1,1.2,1.9,2.7,2.5,4.3.6,1.7.9,3.4.9,5.3s-.3,3.6-.9,5.2c-.6,1.6-1.4,3-2.5,4.2-1.1,1.2-2.4,2.1-4,2.8-1.6.7-3.3,1-5.3,1s-3.8-.3-5.3-1c-1.6-.7-2.9-1.6-4-2.8-1.1-1.2-1.9-2.6-2.5-4.2-.6-1.6-.9-3.4-.9-5.2Zm5.7,0c0,1.1.1,2.1.4,3.2s.7,1.9,1.2,2.8c.6.8,1.3,1.5,2.2,2,.9.5,2,.7,3.2.7s2.4-.2,3.2-.7c.9-.5,1.6-1.1,2.2-2,.6-.8,1-1.7,1.2-2.8s.4-2.1.4-3.2-.1-2.2-.4-3.3c-.3-1.1-.7-2-1.2-2.8s-1.3-1.5-2.2-2c-.9-.5-2-.7-3.2-.7s-2.4.2-3.2.7c-.9.5-1.6,1.2-2.2,2-.6.8-1,1.8-1.2,2.8-.3,1.1-.4,2.1-.4,3.3Z" style="fill: #fff;"/>
<path d="m613.4,951.3h13.9c1.2,0,2.2.2,3.1.6.9.4,1.7.9,2.4,1.5.7.6,1.2,1.4,1.5,2.3.3.9.5,1.8.5,2.7,0,1.5-.3,2.8-1,3.9-.6,1.1-1.7,1.9-3.1,2.5h0c.7.3,1.3.6,1.7,1,.5.4.8.9,1.1,1.4.3.6.5,1.1.6,1.8.1.6.2,1.3.3,1.9,0,.4,0,.9,0,1.4,0,.6,0,1.1.1,1.7,0,.6.2,1.1.3,1.6.1.5.3,1,.6,1.3h-5.7c-.2-.4-.3-.9-.4-1.3,0-.5-.2-1-.2-1.5,0-.5-.1-1.1-.1-1.7,0-.6,0-1.1-.2-1.6-.2-1.3-.6-2.3-1.2-3-.6-.6-1.6-.9-3.1-.9h-5.7v10h-5.7v-25.7Zm5.7,11.6h6.2c1.3,0,2.2-.3,2.9-.9.7-.6,1-1.5,1-2.8s-.3-2.2-1-2.7c-.7-.6-1.6-.8-2.9-.8h-6.2v7.2Z" style="fill: #fff;"/>
<path d="m639.4,951.3h5.7v25.7h-5.7v-25.7Z" style="fill: #fff;"/>
<path d="m668.6,974.1c-1,1.3-2.1,2.2-3.3,2.7-1.2.5-2.5.8-3.7.8-2,0-3.8-.3-5.3-1-1.6-.7-2.9-1.6-4-2.8-1.1-1.2-1.9-2.6-2.5-4.2-.6-1.6-.9-3.4-.9-5.2s.3-3.7.9-5.3c.6-1.7,1.4-3.1,2.5-4.3,1.1-1.2,2.4-2.2,4-2.9,1.6-.7,3.3-1,5.3-1s2.6.2,3.8.6c1.2.4,2.3,1,3.3,1.7,1,.8,1.8,1.7,2.5,2.8s1.1,2.4,1.2,3.9h-5.4c-.3-1.4-1-2.5-2-3.2-1-.7-2.1-1.1-3.5-1.1s-2.4.2-3.2.7c-.9.5-1.6,1.2-2.2,2-.6.8-1,1.8-1.2,2.8-.3,1.1-.4,2.1-.4,3.3s.1,2.1.4,3.2.7,1.9,1.2,2.8c.6.8,1.3,1.5,2.2,2,.9.5,2,.7,3.2.7,1.8,0,3.3-.5,4.3-1.4,1-.9,1.6-2.3,1.8-4.1h-5.7v-4.2h10.8v13.9h-3.6l-.6-2.9Z" style="fill: #fff;"/>
<path d="m677.4,951.3h5.7v25.7h-5.7v-25.7Z" style="fill: #fff;"/>
<path d="m688,951.3h5.6l10.7,17.2h0v-17.2h5.3v25.7h-5.7l-10.7-17.2h0v17.2h-5.3v-25.7Z" style="fill: #fff;"/>
<path d="m721.7,951.3h5.8l9.6,25.7h-5.9l-1.9-5.7h-9.6l-2,5.7h-5.7l9.8-25.7Zm-.5,15.8h6.7l-3.2-9.4h0l-3.3,9.4Z" style="fill: #fff;"/>
<path d="m739.3,951.3h5.7v21h12.5v4.8h-18.2v-25.7Z" style="fill: #fff;"/>
<path d="m770.7,951.3h11.6c1.6,0,3,.2,4.1.7s2,1.1,2.8,1.9c.7.8,1.2,1.7,1.5,2.6.3,1,.5,2,.5,3s-.2,2.1-.5,3.1c-.3,1-.8,1.9-1.5,2.6-.7.8-1.6,1.4-2.8,1.9s-2.5.7-4.1.7h-5.9v9.2h-5.7v-25.7Zm5.7,12.1h4.4c.6,0,1.3,0,1.9-.1.6,0,1.1-.3,1.6-.6.5-.3.8-.7,1.1-1.2.3-.5.4-1.2.4-2s-.1-1.5-.4-2c-.3-.5-.6-.9-1.1-1.2-.5-.3-1-.5-1.6-.6-.6,0-1.2-.1-1.9-.1h-4.4v7.7Z" style="fill: #fff;"/>
<path d="m794.7,951.3h13.9c1.2,0,2.2.2,3.1.6.9.4,1.7.9,2.4,1.5.7.6,1.2,1.4,1.5,2.3.3.9.5,1.8.5,2.7,0,1.5-.3,2.8-1,3.9-.6,1.1-1.7,1.9-3.1,2.5h0c.7.3,1.3.6,1.7,1,.5.4.8.9,1.1,1.4.3.6.5,1.1.6,1.8.1.6.2,1.3.3,1.9,0,.4,0,.9,0,1.4,0,.6,0,1.1.1,1.7,0,.6.2,1.1.3,1.6.1.5.3,1,.6,1.3h-5.7c-.2-.4-.3-.9-.4-1.3s-.2-1-.2-1.5c0-.5-.1-1.1-.1-1.7,0-.6,0-1.1-.2-1.6-.2-1.3-.6-2.3-1.2-3-.6-.6-1.6-.9-3.1-.9h-5.7v10h-5.7v-25.7Zm5.7,11.6h6.2c1.3,0,2.2-.3,2.9-.9.7-.6,1-1.5,1-2.8s-.3-2.2-1-2.7c-.7-.6-1.6-.8-2.9-.8h-6.2v7.2Z" style="fill: #fff;"/>
<path d="m842.5,967.3c0,3.5-1,6.1-2.9,7.8-1.9,1.7-4.6,2.6-8.1,2.6s-6.2-.8-8.1-2.5c-1.9-1.7-2.9-4.3-2.9-7.8v-16h5.7v16c0,.7,0,1.4.2,2.1s.4,1.3.8,1.8c.4.5.9.9,1.6,1.3.7.3,1.6.5,2.8.5,2,0,3.4-.5,4.2-1.4.8-.9,1.2-2.3,1.2-4.2v-16h5.7v16Z" style="fill: #fff;"/>
<path d="m851.2,968.5c0,.9.2,1.6.5,2.2.3.6.7,1.1,1.2,1.5.5.4,1.1.6,1.8.8.7.2,1.4.3,2.2.3s1,0,1.6-.1c.6,0,1.1-.2,1.6-.5s.9-.6,1.3-1c.3-.4.5-1,.5-1.6s-.2-1.3-.7-1.7c-.4-.4-1-.8-1.7-1.1-.7-.3-1.5-.6-2.4-.8-.9-.2-1.8-.4-2.8-.7-1-.2-1.9-.5-2.8-.9-.9-.3-1.7-.8-2.4-1.3-.7-.6-1.3-1.2-1.7-2.1-.4-.8-.7-1.8-.7-3s.3-2.5.8-3.4c.6-1,1.3-1.8,2.2-2.4.9-.6,1.9-1.1,3.1-1.4,1.2-.3,2.3-.5,3.5-.5s2.6.2,3.9.5c1.2.3,2.3.8,3.3,1.5,1,.7,1.7,1.5,2.3,2.6.6,1,.8,2.3.8,3.8h-5.5c0-.8-.2-1.4-.5-1.9s-.6-.9-1.1-1.2c-.5-.3-1-.5-1.6-.6-.6-.1-1.2-.2-1.9-.2s-.9,0-1.4.1c-.5,0-.9.3-1.2.5-.4.2-.7.5-.9.9-.2.4-.4.8-.4,1.4s0,.9.3,1.2c.2.3.6.6,1.1.8.6.3,1.3.5,2.3.8,1,.3,2.3.6,3.9,1,.3,0,.7.2,1.2.3.5.1,1,.3,1.6.5.6.2,1.1.5,1.7.9.6.4,1.1.8,1.5,1.3.5.5.8,1.2,1.1,1.9.3.7.4,1.6.4,2.5s-.2,2.3-.7,3.3c-.5,1-1.1,1.9-2,2.6-.9.7-2,1.3-3.3,1.7-1.3.4-2.9.6-4.6.6s-2.8-.2-4.1-.5c-1.3-.4-2.5-.9-3.5-1.7-1-.7-1.8-1.7-2.4-2.8-.6-1.2-.9-2.5-.9-4.1h5.5Z" style="fill: #fff;"/>
<path d="m877.7,951.3h5.8l9.6,25.7h-5.9l-1.9-5.7h-9.6l-2,5.7h-5.7l9.8-25.7Zm-.5,15.8h6.7l-3.2-9.4h0l-3.3,9.4Z" style="fill: #fff;"/>
<path d="m911.7,963.6l-8.3-12.2h6.6l5,8.2,5.2-8.2h6.2l-8.2,12.3,9,13.4h-6.7l-5.6-8.9-5.7,8.9h-6.4l9-13.5Z" style="fill: #fff;"/>
<path d="m929.4,951.3h5.7v21h12.5v4.8h-18.2v-25.7Z" style="fill: #fff;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

View File

@ -871,7 +871,7 @@ template<class P> auto rcend(const P& p) -> decltype(_backward(cbegin(p)))
template<class P> TPoint<P> front(const P& p) { return *shapelike::cbegin(p); } template<class P> TPoint<P> front(const P& p) { return *shapelike::cbegin(p); }
template<class P> TPoint<P> back (const P& p) { template<class P> TPoint<P> back (const P& p) {
return *backward(shapelike::cend(p)); return *std::prev(shapelike::cend(p));
} }
// Optional, does nothing by default // Optional, does nothing by default

View File

@ -70,6 +70,7 @@ class _Item {
int binid_{BIN_ID_UNSET}, priority_{0}; int binid_{BIN_ID_UNSET}, priority_{0};
bool fixed_{false}; bool fixed_{false};
std::function<void(_Item&)> on_packed_;
public: public:
@ -205,6 +206,23 @@ public:
sl::vertex(sh_, idx) = v; sl::vertex(sh_, idx) = v;
} }
void setShape(RawShape rsh)
{
sh_ = std::move(rsh);
invalidateCache();
}
void setOnPackedFn(std::function<void(_Item&)> onpackedfn)
{
on_packed_ = onpackedfn;
}
void onPacked()
{
if (on_packed_)
on_packed_(*this);
}
/** /**
* @brief Calculate the shape area. * @brief Calculate the shape area.
* *

View File

@ -157,26 +157,34 @@ template<class RawShape> class EdgeCache {
void createCache(const RawShape& sh) { void createCache(const RawShape& sh) {
{ // For the contour { // For the contour
auto first = shapelike::cbegin(sh); auto first = sl::cbegin(sh);
auto next = std::next(first); auto endit = sl::cend(sh);
auto endit = shapelike::cend(sh); auto next = first == endit ? endit : std::next(first);
contour_.distances.reserve(shapelike::contourVertexCount(sh)); contour_.distances.reserve(sl::contourVertexCount(sh));
while(next != endit) { while(next != endit) {
contour_.emap.emplace_back(*(first++), *(next++)); contour_.emap.emplace_back(*(first++), *(next++));
contour_.full_distance += length(contour_.emap.back()); contour_.full_distance += length(contour_.emap.back());
contour_.distances.emplace_back(contour_.full_distance); contour_.distances.emplace_back(contour_.full_distance);
} }
if constexpr (ClosureTypeV<RawShape> == Closure::OPEN) {
if (sl::contourVertexCount(sh) > 0) {
contour_.emap.emplace_back(sl::back(sh), sl::front(sh));
contour_.full_distance += length(contour_.emap.back());
contour_.distances.emplace_back(contour_.full_distance);
}
}
} }
for(auto& h : shapelike::holes(sh)) { // For the holes for(auto& h : shapelike::holes(sh)) { // For the holes
auto first = h.begin(); auto first = sl::cbegin(h);
auto next = std::next(first); auto endit = sl::cend(h);
auto endit = h.end(); auto next = first == endit ? endit :std::next(first);
ContourCache hc; ContourCache hc;
hc.distances.reserve(endit - first); hc.distances.reserve(sl::contourVertexCount(h));
while(next != endit) { while(next != endit) {
hc.emap.emplace_back(*(first++), *(next++)); hc.emap.emplace_back(*(first++), *(next++));
@ -184,6 +192,14 @@ template<class RawShape> class EdgeCache {
hc.distances.emplace_back(hc.full_distance); hc.distances.emplace_back(hc.full_distance);
} }
if constexpr (ClosureTypeV<RawShape> == Closure::OPEN) {
if (sl::contourVertexCount(h) > 0) {
hc.emap.emplace_back(sl::back(sh), sl::front(sh));
hc.full_distance += length(hc.emap.back());
hc.distances.emplace_back(hc.full_distance);
}
}
holes_.emplace_back(std::move(hc)); holes_.emplace_back(std::move(hc));
} }
} }
@ -206,7 +222,6 @@ template<class RawShape> class EdgeCache {
contour_.corners.reserve(N / S + 1); contour_.corners.reserve(N / S + 1);
contour_.corners.emplace_back(0.0); contour_.corners.emplace_back(0.0);
auto N_1 = N-1; auto N_1 = N-1;
contour_.corners.emplace_back(0.0);
for(size_t i = 0; i < N_1; i += S) { for(size_t i = 0; i < N_1; i += S) {
contour_.corners.emplace_back( contour_.corners.emplace_back(
contour_.distances.at(i) / contour_.full_distance); contour_.distances.at(i) / contour_.full_distance);
@ -886,6 +901,7 @@ public:
if(can_pack) { if(can_pack) {
ret = PackResult(item); ret = PackResult(item);
item.onPacked();
merged_pile_ = nfp::merge(merged_pile_, item.transformedShape()); merged_pile_ = nfp::merge(merged_pile_, item.transformedShape());
} else { } else {
ret = PackResult(best_overfit); ret = PackResult(best_overfit);

View File

@ -165,9 +165,9 @@ inline std::vector<std::pair<VectorType, size_t>> get_intersections_with_line(si
// Epsilon is applied to the bounding boxes of the AABB Tree to cope with numeric inaccuracies // Epsilon is applied to the bounding boxes of the AABB Tree to cope with numeric inaccuracies
// during tree traversal. // during tree traversal.
template<typename LineType> template<typename LineType>
inline AABBTreeIndirect::Tree<2, typename LineType::Scalar> build_aabb_tree_over_indexed_lines(const std::vector<LineType> &lines) inline AABBTreeIndirect::Tree<LineType::Dim, typename LineType::Scalar> build_aabb_tree_over_indexed_lines(const std::vector<LineType> &lines)
{ {
using TreeType = AABBTreeIndirect::Tree<2, typename LineType::Scalar>; using TreeType = AABBTreeIndirect::Tree<LineType::Dim, typename LineType::Scalar>;
// using CoordType = typename TreeType::CoordType; // using CoordType = typename TreeType::CoordType;
using VectorType = typename TreeType::VectorType; using VectorType = typename TreeType::VectorType;
using BoundingBox = typename TreeType::BoundingBox; using BoundingBox = typename TreeType::BoundingBox;

View File

@ -340,12 +340,6 @@ std::string AppConfig::load(const std::string &path)
// Error while parsing config file. We'll customize the error message and rethrow to be displayed. // Error while parsing config file. We'll customize the error message and rethrow to be displayed.
// ! But to avoid the use of _utf8 (related to use of wxWidgets) // ! But to avoid the use of _utf8 (related to use of wxWidgets)
// we will rethrow this exception from the place of load() call, if returned value wouldn't be empty // we will rethrow this exception from the place of load() call, if returned value wouldn't be empty
/*
throw Slic3r::RuntimeError(
_utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. "
"Try to manually delete the file to recover from the error. Your user profiles will not be affected.")) +
"\n\n" + AppConfig::config_path() + "\n\n" + ex.what());
*/
return ex.what(); return ex.what();
} }
} }

View File

@ -522,44 +522,6 @@ static bool has_missing_twin_edge(const SkeletalTrapezoidationGraph &graph)
return false; return false;
} }
inline static std::unordered_map<Point, Point, PointHash> try_to_fix_degenerated_voronoi_diagram_by_rotation(
Geometry::VoronoiDiagram &voronoi_diagram,
const Polygons &polys,
Polygons &polys_rotated,
std::vector<SkeletalTrapezoidation::Segment> &segments,
const double fix_angle)
{
std::unordered_map<Point, Point, PointHash> vertex_mapping;
for (Polygon &poly : polys_rotated)
poly.rotate(fix_angle);
assert(polys_rotated.size() == polys.size());
for (size_t poly_idx = 0; poly_idx < polys.size(); ++poly_idx) {
assert(polys_rotated[poly_idx].size() == polys[poly_idx].size());
for (size_t point_idx = 0; point_idx < polys[poly_idx].size(); ++point_idx)
vertex_mapping.insert({polys_rotated[poly_idx][point_idx], polys[poly_idx][point_idx]});
}
segments.clear();
for (size_t poly_idx = 0; poly_idx < polys_rotated.size(); poly_idx++)
for (size_t point_idx = 0; point_idx < polys_rotated[poly_idx].size(); point_idx++)
segments.emplace_back(&polys_rotated, poly_idx, point_idx);
voronoi_diagram.clear();
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);
#ifdef ARACHNE_DEBUG_VORONOI
{
static int iRun = 0;
dump_voronoi_to_svg(debug_out_path("arachne_voronoi-diagram-rotated-%d.svg", iRun++).c_str(), voronoi_diagram, to_points(polys), to_lines(polys));
}
#endif
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));
return vertex_mapping;
}
inline static void rotate_back_skeletal_trapezoidation_graph_after_fix(SkeletalTrapezoidationGraph &graph, inline static void rotate_back_skeletal_trapezoidation_graph_after_fix(SkeletalTrapezoidationGraph &graph,
const double fix_angle, const double fix_angle,
const std::unordered_map<Point, Point, PointHash> &vertex_mapping) const std::unordered_map<Point, Point, PointHash> &vertex_mapping)
@ -626,6 +588,56 @@ VoronoiDiagramStatus detect_voronoi_diagram_known_issues(const Geometry::Voronoi
return VoronoiDiagramStatus::NO_ISSUE_DETECTED; return VoronoiDiagramStatus::NO_ISSUE_DETECTED;
} }
inline static std::pair<std::unordered_map<Point, Point, PointHash>, double> try_to_fix_degenerated_voronoi_diagram_by_rotation(
Geometry::VoronoiDiagram &voronoi_diagram,
const Polygons &polys,
Polygons &polys_rotated,
std::vector<SkeletalTrapezoidation::Segment> &segments,
const std::vector<double> &fix_angles)
{
const Polygons polys_rotated_original = polys_rotated;
double fixed_by_angle = fix_angles.front();
std::unordered_map<Point, Point, PointHash> vertex_mapping;
for (const double &fix_angle : fix_angles) {
vertex_mapping.clear();
polys_rotated = polys_rotated_original;
fixed_by_angle = fix_angle;
for (Polygon &poly : polys_rotated)
poly.rotate(fix_angle);
assert(polys_rotated.size() == polys.size());
for (size_t poly_idx = 0; poly_idx < polys.size(); ++poly_idx) {
assert(polys_rotated[poly_idx].size() == polys[poly_idx].size());
for (size_t point_idx = 0; point_idx < polys[poly_idx].size(); ++point_idx)
vertex_mapping.insert({polys_rotated[poly_idx][point_idx], polys[poly_idx][point_idx]});
}
segments.clear();
for (size_t poly_idx = 0; poly_idx < polys_rotated.size(); poly_idx++)
for (size_t point_idx = 0; point_idx < polys_rotated[poly_idx].size(); point_idx++)
segments.emplace_back(&polys_rotated, poly_idx, point_idx);
voronoi_diagram.clear();
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);
#ifdef ARACHNE_DEBUG_VORONOI
{
static int iRun = 0;
dump_voronoi_to_svg(debug_out_path("arachne_voronoi-diagram-rotated-%d.svg", iRun++).c_str(), voronoi_diagram, to_points(polys), to_lines(polys));
}
#endif
if (detect_voronoi_diagram_known_issues(voronoi_diagram, segments) == VoronoiDiagramStatus::NO_ISSUE_DETECTED)
break;
}
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));
return {vertex_mapping, fixed_by_angle};
}
void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
{ {
#ifdef ARACHNE_DEBUG #ifdef ARACHNE_DEBUG
@ -669,8 +681,9 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
// When any Voronoi vertex is missing, the Voronoi diagram is not planar, or some voronoi edge is // When any Voronoi vertex is missing, the Voronoi diagram is not planar, or some voronoi edge is
// intersecting input segment, rotate the input polygon and try again. // intersecting input segment, rotate the input polygon and try again.
VoronoiDiagramStatus status = detect_voronoi_diagram_known_issues(voronoi_diagram, segments); VoronoiDiagramStatus status = detect_voronoi_diagram_known_issues(voronoi_diagram, segments);
const double fix_angle = PI / 6; const std::vector<double> fix_angles = {PI / 6, PI / 5, PI / 7, PI / 11};
double fixed_by_angle = fix_angles.front();
std::unordered_map<Point, Point, PointHash> vertex_mapping; std::unordered_map<Point, Point, PointHash> vertex_mapping;
// polys_copy is referenced through items stored in the std::vector segments. // polys_copy is referenced through items stored in the std::vector segments.
@ -683,16 +696,15 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
else if (status == VoronoiDiagramStatus::VORONOI_EDGE_INTERSECTING_INPUT_SEGMENT) else if (status == VoronoiDiagramStatus::VORONOI_EDGE_INTERSECTING_INPUT_SEGMENT)
BOOST_LOG_TRIVIAL(warning) << "Detected Voronoi edge intersecting input segment, input polygons will be rotated back and forth."; BOOST_LOG_TRIVIAL(warning) << "Detected Voronoi edge intersecting input segment, input polygons will be rotated back and forth.";
vertex_mapping = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angle); std::tie(vertex_mapping, fixed_by_angle) = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angles);
assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments)); VoronoiDiagramStatus status_after_fix = detect_voronoi_diagram_known_issues(voronoi_diagram, segments);
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segments)); assert(status_after_fix == VoronoiDiagramStatus::NO_ISSUE_DETECTED);
assert(!detect_voronoi_edge_intersecting_input_segment(voronoi_diagram, segments)); if (status_after_fix == VoronoiDiagramStatus::MISSING_VORONOI_VERTEX)
if (detect_missing_voronoi_vertex(voronoi_diagram, segments))
BOOST_LOG_TRIVIAL(error) << "Detected missing Voronoi vertex even after the rotation of input."; BOOST_LOG_TRIVIAL(error) << "Detected missing Voronoi vertex even after the rotation of input.";
else if (!Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segments)) else if (status_after_fix == VoronoiDiagramStatus::NON_PLANAR_VORONOI_DIAGRAM)
BOOST_LOG_TRIVIAL(error) << "Detected non-planar Voronoi diagram even after the rotation of input."; BOOST_LOG_TRIVIAL(error) << "Detected non-planar Voronoi diagram even after the rotation of input.";
else if (detect_voronoi_edge_intersecting_input_segment(voronoi_diagram, segments)) else if (status_after_fix == VoronoiDiagramStatus::VORONOI_EDGE_INTERSECTING_INPUT_SEGMENT)
BOOST_LOG_TRIVIAL(error) << "Detected Voronoi edge intersecting input segment even after the rotation of input."; BOOST_LOG_TRIVIAL(error) << "Detected Voronoi edge intersecting input segment even after the rotation of input.";
} }
@ -759,8 +771,8 @@ process_voronoi_diagram:
// diagram on slightly rotated input polygons that usually make the Voronoi generator generate a non-degenerated Voronoi diagram. // diagram on slightly rotated input polygons that usually make the Voronoi generator generate a non-degenerated Voronoi diagram.
if (status == VoronoiDiagramStatus::NO_ISSUE_DETECTED && has_missing_twin_edge(this->graph)) { if (status == VoronoiDiagramStatus::NO_ISSUE_DETECTED && has_missing_twin_edge(this->graph)) {
BOOST_LOG_TRIVIAL(warning) << "Detected degenerated Voronoi diagram, input polygons will be rotated back and forth."; BOOST_LOG_TRIVIAL(warning) << "Detected degenerated Voronoi diagram, input polygons will be rotated back and forth.";
status = VoronoiDiagramStatus::OTHER_TYPE_OF_VORONOI_DIAGRAM_DEGENERATION; status = VoronoiDiagramStatus::OTHER_TYPE_OF_VORONOI_DIAGRAM_DEGENERATION;
vertex_mapping = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angle); std::tie(vertex_mapping, fixed_by_angle) = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angles);
assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments)); assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments));
if (detect_missing_voronoi_vertex(voronoi_diagram, segments)) if (detect_missing_voronoi_vertex(voronoi_diagram, segments))
@ -784,7 +796,7 @@ process_voronoi_diagram:
} }
if (status != VoronoiDiagramStatus::NO_ISSUE_DETECTED) if (status != VoronoiDiagramStatus::NO_ISSUE_DETECTED)
rotate_back_skeletal_trapezoidation_graph_after_fix(this->graph, fix_angle, vertex_mapping); rotate_back_skeletal_trapezoidation_graph_after_fix(this->graph, fixed_by_angle, vertex_mapping);
#ifdef ARACHNE_DEBUG #ifdef ARACHNE_DEBUG
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram)); assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));

View File

@ -583,8 +583,12 @@ static void process_arrangeable(const ArrangePolygon &arrpoly,
outp.emplace_back(std::move(p)); outp.emplace_back(std::move(p));
outp.back().rotation(rotation); outp.back().rotation(rotation);
outp.back().translation({offs.x(), offs.y()}); outp.back().translation({offs.x(), offs.y()});
outp.back().inflate(arrpoly.inflation);
outp.back().binId(arrpoly.bed_idx); outp.back().binId(arrpoly.bed_idx);
outp.back().priority(arrpoly.priority); outp.back().priority(arrpoly.priority);
outp.back().setOnPackedFn([&arrpoly](Item &itm){
itm.inflate(-arrpoly.inflation);
});
} }
template<class Fn> auto call_with_bed(const Points &bed, Fn &&fn) template<class Fn> auto call_with_bed(const Points &bed, Fn &&fn)

View File

@ -71,7 +71,7 @@ static const constexpr int UNARRANGED = -1;
/// polygon belongs: UNARRANGED means no place for the polygon /// polygon belongs: UNARRANGED means no place for the polygon
/// (also the initial state before arrange), 0..N means the index of the bed. /// (also the initial state before arrange), 0..N means the index of the bed.
/// Zero is the physical bed, larger than zero means a virtual bed. /// Zero is the physical bed, larger than zero means a virtual bed.
struct ArrangePolygon { struct ArrangePolygon {
ExPolygon poly; /// The 2D silhouette to be arranged ExPolygon poly; /// The 2D silhouette to be arranged
Vec2crd translation{0, 0}; /// The translation of the poly Vec2crd translation{0, 0}; /// The translation of the poly
double rotation{0.0}; /// The rotation of the poly in radians double rotation{0.0}; /// The rotation of the poly in radians

View File

@ -1264,15 +1264,17 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
return result; return result;
} }
void Emboss::apply_transformation(const FontProp &font_prop, void Emboss::apply_transformation(const FontProp &font_prop, Transform3d &transformation){
Transform3d &transformation) apply_transformation(font_prop.angle, font_prop.distance, transformation);
{ }
if (font_prop.angle.has_value()) {
double angle_z = *font_prop.angle; void Emboss::apply_transformation(const std::optional<float>& angle, const std::optional<float>& distance, Transform3d &transformation) {
if (angle.has_value()) {
double angle_z = *angle;
transformation *= Eigen::AngleAxisd(angle_z, Vec3d::UnitZ()); transformation *= Eigen::AngleAxisd(angle_z, Vec3d::UnitZ());
} }
if (font_prop.distance.has_value()) { if (distance.has_value()) {
Vec3d translate = Vec3d::UnitZ() * (*font_prop.distance); Vec3d translate = Vec3d::UnitZ() * (*distance);
transformation.translate(translate); transformation.translate(translate);
} }
} }
@ -1540,60 +1542,95 @@ std::optional<Vec2d> Emboss::ProjectZ::unproject(const Vec3d &p, double *depth)
return Vec2d(p.x() / SHAPE_SCALE, p.y() / SHAPE_SCALE); return Vec2d(p.x() / SHAPE_SCALE, p.y() / SHAPE_SCALE);
} }
Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position,
const Vec3f &normal, Vec3d Emboss::suggest_up(const Vec3d normal, double up_limit)
float up_limit)
{ {
// up and emboss direction for generated model // Normal must be 1
Vec3d text_up_dir = Vec3d::UnitY(); assert(is_approx(normal.squaredNorm(), 1.));
Vec3d text_emboss_dir = Vec3d::UnitZ();
// wanted up direction of result // wanted up direction of result
Vec3d wanted_up_side = Vec3d::UnitZ(); Vec3d wanted_up_side =
if (std::fabs(normal.z()) > up_limit) wanted_up_side = Vec3d::UnitY(); (std::fabs(normal.z()) > up_limit)?
Vec3d::UnitY() : Vec3d::UnitZ();
Vec3d wanted_emboss_dir = normal.cast<double>();
// after cast from float it needs to be normalized again
wanted_emboss_dir.normalize();
// create perpendicular unit vector to surface triangle normal vector // create perpendicular unit vector to surface triangle normal vector
// lay on surface of triangle and define up vector for text // lay on surface of triangle and define up vector for text
Vec3d wanted_up_dir = wanted_emboss_dir Vec3d wanted_up_dir = normal.cross(wanted_up_side).cross(normal);
.cross(wanted_up_side)
.cross(wanted_emboss_dir);
// normal3d is NOT perpendicular to normal_up_dir // normal3d is NOT perpendicular to normal_up_dir
wanted_up_dir.normalize(); wanted_up_dir.normalize();
return wanted_up_dir;
}
std::optional<float> Emboss::calc_up(const Transform3d &tr, double up_limit)
{
auto tr_linear = tr.linear();
// z base of transformation ( tr * UnitZ )
Vec3d normal = tr_linear.col(2);
// scaled matrix has base with different size
normal.normalize();
Vec3d suggested = suggest_up(normal);
assert(is_approx(suggested.squaredNorm(), 1.));
Vec3d up = tr_linear.col(1); // tr * UnitY()
up.normalize();
double dot = suggested.dot(up);
if (dot >= 1. || dot <= -1.)
return {}; // zero angle
Matrix3d m;
m.row(0) = up;
m.row(1) = suggested;
m.row(2) = normal;
double det = m.determinant();
return -atan2(det, dot);
}
Transform3d Emboss::create_transformation_onto_surface(const Vec3d &position,
const Vec3d &normal,
double up_limit)
{
// is normalized ?
assert(is_approx(normal.squaredNorm(), 1.));
// up and emboss direction for generated model
Vec3d up_dir = Vec3d::UnitY();
Vec3d emboss_dir = Vec3d::UnitZ();
// after cast from float it needs to be normalized again
Vec3d wanted_up_dir = suggest_up(normal, up_limit);
// perpendicular to emboss vector of text and normal // perpendicular to emboss vector of text and normal
Vec3d axis_view; Vec3d axis_view;
double angle_view; double angle_view;
if (wanted_emboss_dir == -Vec3d::UnitZ()) { if (normal == -Vec3d::UnitZ()) {
// text_emboss_dir has opposit direction to wanted_emboss_dir // text_emboss_dir has opposit direction to wanted_emboss_dir
axis_view = Vec3d::UnitY(); axis_view = Vec3d::UnitY();
angle_view = M_PI; angle_view = M_PI;
} else { } else {
axis_view = text_emboss_dir.cross(wanted_emboss_dir); axis_view = emboss_dir.cross(normal);
angle_view = std::acos(text_emboss_dir.dot(wanted_emboss_dir)); // in rad angle_view = std::acos(emboss_dir.dot(normal)); // in rad
axis_view.normalize(); axis_view.normalize();
} }
Eigen::AngleAxis view_rot(angle_view, axis_view); Eigen::AngleAxis view_rot(angle_view, axis_view);
Vec3d wanterd_up_rotated = view_rot.matrix().inverse() * wanted_up_dir; Vec3d wanterd_up_rotated = view_rot.matrix().inverse() * wanted_up_dir;
wanterd_up_rotated.normalize(); wanterd_up_rotated.normalize();
double angle_up = std::acos(text_up_dir.dot(wanterd_up_rotated)); double angle_up = std::acos(up_dir.dot(wanterd_up_rotated));
// text_view and text_view2 should have same direction Vec3d text_view = up_dir.cross(wanterd_up_rotated);
Vec3d text_view2 = text_up_dir.cross(wanterd_up_rotated); Vec3d diff_view = emboss_dir - text_view;
Vec3d diff_view = text_emboss_dir - text_view2;
if (std::fabs(diff_view.x()) > 1. || if (std::fabs(diff_view.x()) > 1. ||
std::fabs(diff_view.y()) > 1. || std::fabs(diff_view.y()) > 1. ||
std::fabs(diff_view.z()) > 1.) // oposit direction std::fabs(diff_view.z()) > 1.) // oposit direction
angle_up *= -1.; angle_up *= -1.;
Eigen::AngleAxis up_rot(angle_up, text_emboss_dir); Eigen::AngleAxis up_rot(angle_up, emboss_dir);
Transform3d transform = Transform3d::Identity(); Transform3d transform = Transform3d::Identity();
transform.translate(position.cast<double>()); transform.translate(position);
transform.rotate(view_rot); transform.rotate(view_rot);
transform.rotate(up_rot); transform.rotate(up_rot);
return transform; return transform;

View File

@ -193,6 +193,7 @@ namespace Emboss
/// Z-rotation as angle to Y axis(FontProp::angle)</param> /// Z-rotation as angle to Y axis(FontProp::angle)</param>
/// <param name="transformation">In / Out transformation to modify by property</param> /// <param name="transformation">In / Out transformation to modify by property</param>
void apply_transformation(const FontProp &font_prop, Transform3d &transformation); void apply_transformation(const FontProp &font_prop, Transform3d &transformation);
void apply_transformation(const std::optional<float> &angle, const std::optional<float> &distance, Transform3d &transformation);
/// <summary> /// <summary>
/// Read information from naming table of font file /// Read information from naming table of font file
@ -273,7 +274,23 @@ namespace Emboss
/// <param name="projection">Define transformation from 2d to 3d(orientation, position, scale, ...)</param> /// <param name="projection">Define transformation from 2d to 3d(orientation, position, scale, ...)</param>
/// <returns>Projected shape into space</returns> /// <returns>Projected shape into space</returns>
indexed_triangle_set polygons2model(const ExPolygons &shape2d, const IProjection& projection); indexed_triangle_set polygons2model(const ExPolygons &shape2d, const IProjection& projection);
/// <summary>
/// Suggest wanted up vector of embossed text by emboss direction
/// </summary>
/// <param name="normal">Normalized vector of emboss direction in world</param>
/// <param name="up_limit">Is compared with normal.z to suggest up direction</param>
/// <returns>Wanted up vector</returns>
Vec3d suggest_up(const Vec3d normal, double up_limit = 0.9);
/// <summary>
/// By transformation calculate angle between suggested and actual up vector
/// </summary>
/// <param name="tr">Transformation of embossed volume in world</param>
/// <param name="up_limit">Is compared with normal.z to suggest up direction</param>
/// <returns>Rotation of suggested up-vector[in rad] in the range [-Pi, Pi], When rotation is not zero</returns>
std::optional<float> calc_up(const Transform3d &tr, double up_limit = 0.9);
/// <summary> /// <summary>
/// Create transformation for emboss text object to lay on surface point /// Create transformation for emboss text object to lay on surface point
/// </summary> /// </summary>
@ -282,7 +299,7 @@ namespace Emboss
/// <param name="up_limit">Is compared with normal.z to suggest up direction</param> /// <param name="up_limit">Is compared with normal.z to suggest up direction</param>
/// <returns>Transformation onto surface point</returns> /// <returns>Transformation onto surface point</returns>
Transform3d create_transformation_onto_surface( Transform3d create_transformation_onto_surface(
const Vec3f &position, const Vec3f &normal, float up_limit = 0.9f); const Vec3d &position, const Vec3d &normal, double up_limit = 0.9);
class ProjectZ : public IProjection class ProjectZ : public IProjection
{ {

View File

@ -37,6 +37,7 @@ std::pair<double, double> Extruder::extrude(double dE)
value supplied will overwrite the previous one if any. */ value supplied will overwrite the previous one if any. */
std::pair<double, double> Extruder::retract(double retract_length, double restart_extra) std::pair<double, double> Extruder::retract(double retract_length, double restart_extra)
{ {
assert(restart_extra >= 0);
// in case of relative E distances we always reset to 0 before any output // in case of relative E distances we always reset to 0 before any output
if (m_config->use_relative_e_distances) if (m_config->use_relative_e_distances)
m_E = 0.; m_E = 0.;
@ -64,6 +65,24 @@ std::pair<double, double> Extruder::unretract()
return std::make_pair(dE, emitE); return std::make_pair(dE, emitE);
} }
// Setting the retract state from the script.
// Sets current retraction value & restart extra filament amount if retracted > 0.
void Extruder::set_retracted(double retracted, double restart_extra)
{
if (retracted < - EPSILON)
throw Slic3r::RuntimeError("Custom G-code reports negative z_retracted.");
if (restart_extra < - EPSILON)
throw Slic3r::RuntimeError("Custom G-code reports negative z_restart_extra.");
if (retracted > EPSILON) {
m_retracted = retracted;
m_restart_extra = restart_extra < EPSILON ? 0 : restart_extra;
} else {
m_retracted = 0;
m_restart_extra = 0;
}
}
// Used filament volume in mm^3. // Used filament volume in mm^3.
double Extruder::extruded_volume() const double Extruder::extruded_volume() const
{ {

View File

@ -36,6 +36,19 @@ public:
double extruded_volume() const; double extruded_volume() const;
// Used filament length in mm. // Used filament length in mm.
double used_filament() const; double used_filament() const;
// Getters for the PlaceholderParser.
// Get current extruder position. Only applicable with absolute extruder addressing.
double position() const { return m_E; }
// Get current retraction value. Only non-negative values.
double retracted() const { return m_retracted; }
// Get extra retraction planned after
double restart_extra() const { return m_restart_extra; }
// Setters for the PlaceholderParser.
// Set current extruder position. Only applicable with absolute extruder addressing.
void set_position(double e) { m_E = e; }
// Sets current retraction value & restart extra filament amount if retracted > 0.
void set_retracted(double retracted, double restart_extra);
double filament_diameter() const; double filament_diameter() const;
double filament_crossection() const { return this->filament_diameter() * this->filament_diameter() * 0.25 * PI; } double filament_crossection() const { return this->filament_diameter() * this->filament_diameter() * 0.25 * PI; }

View File

@ -1,10 +1,10 @@
#include "ExtrusionRole.hpp" #include "ExtrusionRole.hpp"
#include "I18N.hpp"
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <cassert> #include <cassert>
#define L(s) (s)
namespace Slic3r { namespace Slic3r {

View File

@ -16,6 +16,7 @@
#include "FillLightning.hpp" #include "FillLightning.hpp"
#include "FillConcentric.hpp" #include "FillConcentric.hpp"
#include "FillEnsuring.hpp" #include "FillEnsuring.hpp"
#include "Polygon.hpp"
namespace Slic3r { namespace Slic3r {
@ -486,14 +487,6 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
size_t first_object_layer_id = this->object()->get_layer(0)->id(); size_t first_object_layer_id = this->object()->get_layer(0)->id();
for (SurfaceFill &surface_fill : surface_fills) { for (SurfaceFill &surface_fill : surface_fills) {
//skip patterns for which additional input is nullptr
switch (surface_fill.params.pattern) {
case ipLightning: if (lightning_generator == nullptr) continue; break;
case ipAdaptiveCubic: if (adaptive_fill_octree == nullptr) continue; break;
case ipSupportCubic: if (support_fill_octree == nullptr) continue; break;
default: break;
}
// Create the filler object. // Create the filler object.
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern)); std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
f->set_bounding_box(bbox); f->set_bounding_box(bbox);
@ -647,7 +640,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
#endif #endif
} }
Polylines Layer::generate_sparse_infill_polylines_for_anchoring() const Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator) const
{ {
std::vector<SurfaceFill> surface_fills = group_fills(*this); std::vector<SurfaceFill> surface_fills = group_fills(*this);
const Slic3r::BoundingBox bbox = this->object()->bounding_box(); const Slic3r::BoundingBox bbox = this->object()->bounding_box();
@ -656,14 +649,17 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring() const
Polylines sparse_infill_polylines{}; Polylines sparse_infill_polylines{};
for (SurfaceFill &surface_fill : surface_fills) { for (SurfaceFill &surface_fill : surface_fills) {
// skip patterns for which additional input is nullptr if (surface_fill.surface.surface_type != stInternal) {
continue;
}
switch (surface_fill.params.pattern) { switch (surface_fill.params.pattern) {
case ipLightning: continue; break;
case ipAdaptiveCubic: continue; break;
case ipSupportCubic: continue; break;
case ipCount: continue; break; case ipCount: continue; break;
case ipSupportBase: continue; break; case ipSupportBase: continue; break;
case ipEnsuring: continue; break; case ipEnsuring: continue; break;
case ipLightning:
case ipAdaptiveCubic:
case ipSupportCubic:
case ipRectilinear: case ipRectilinear:
case ipMonotonic: case ipMonotonic:
case ipMonotonicLines: case ipMonotonicLines:
@ -688,10 +684,16 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring() const
f->layer_id = this->id(); f->layer_id = this->id();
f->z = this->print_z; f->z = this->print_z;
f->angle = surface_fill.params.angle; f->angle = surface_fill.params.angle;
// f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree; f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
f->print_config = &this->object()->print()->config(); f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config(); f->print_object_config = &this->object()->config();
if (surface_fill.params.pattern == ipLightning) {
auto *lf = dynamic_cast<FillLightning::Filler *>(f.get());
lf->generator = lightning_generator;
lf->num_raft_layers = this->object()->slicing_parameters().raft_layers();
}
// calculate flow spacing for infill pattern generation // calculate flow spacing for infill pattern generation
double link_max_length = 0.; double link_max_length = 0.;
if (!surface_fill.params.bridge) { if (!surface_fill.params.bridge) {

View File

@ -6,9 +6,6 @@
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
// Mark string for localization and translate.
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r { namespace Slic3r {
FlowErrorNegativeSpacing::FlowErrorNegativeSpacing() : FlowErrorNegativeSpacing::FlowErrorNegativeSpacing() :
@ -58,7 +55,7 @@ static inline FlowRole opt_key_to_flow_role(const std::string &opt_key)
static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key) static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key)
{ {
throw FlowErrorMissingVariable((boost::format(L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str()); throw FlowErrorMissingVariable((boost::format(_u8L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str());
} }
// Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser. // Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser.

View File

@ -296,11 +296,6 @@ bool is_valid_object_type(const std::string& type)
namespace Slic3r { namespace Slic3r {
//! macro used to mark string used at localization,
//! return same string
#define L(s) (s)
#define _(s) Slic3r::I18N::translate(s)
// Base class with error messages management // Base class with error messages management
class _3MF_Base class _3MF_Base
{ {
@ -957,7 +952,7 @@ namespace Slic3r {
try try
{ {
res = mz_zip_reader_extract_file_to_callback(&archive, stat.m_filename, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t { res = mz_zip_reader_extract_to_callback(&archive, stat.m_file_index, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
CallbackData* data = (CallbackData*)pOpaque; CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.parse_error()) { if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.parse_error()) {
char error_buf[1024]; char error_buf[1024];
@ -991,7 +986,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading cut information data to buffer"); add_error("Error while reading cut information data to buffer");
return; return;
@ -1053,7 +1048,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading config data to buffer"); add_error("Error while reading config data to buffer");
return; return;
@ -1073,7 +1068,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading layer heights profile data to buffer"); add_error("Error while reading layer heights profile data to buffer");
return; return;
@ -1135,7 +1130,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading layer config ranges data to buffer"); add_error("Error while reading layer config ranges data to buffer");
return; return;
@ -1192,7 +1187,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading sla support points data to buffer"); add_error("Error while reading sla support points data to buffer");
return; return;
@ -1274,7 +1269,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer(size_t(stat.m_uncomp_size), 0); std::string buffer(size_t(stat.m_uncomp_size), 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading sla support points data to buffer"); add_error("Error while reading sla support points data to buffer");
return; return;
@ -1379,7 +1374,7 @@ namespace Slic3r {
return false; return false;
} }
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, parser_buffer, (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, parser_buffer, (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading config data to buffer"); add_error("Error while reading config data to buffer");
return false; return false;
@ -1399,7 +1394,7 @@ namespace Slic3r {
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0); std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0); mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) { if (res == 0) {
add_error("Error while reading custom Gcodes per height data to buffer"); add_error("Error while reading custom Gcodes per height data to buffer");
return; return;
@ -1875,9 +1870,9 @@ namespace Slic3r {
if (m_curr_metadata_name == SLIC3RPE_3MF_VERSION) { if (m_curr_metadata_name == SLIC3RPE_3MF_VERSION) {
m_version = (unsigned int)atoi(m_curr_characters.c_str()); m_version = (unsigned int)atoi(m_curr_characters.c_str());
if (m_check_version && (m_version > VERSION_3MF_COMPATIBLE)) { if (m_check_version && (m_version > VERSION_3MF_COMPATIBLE)) {
// std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible.")); // std::string msg = _u8L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible.");
// throw version_error(msg.c_str()); // throw version_error(msg.c_str());
const std::string msg = (boost::format(_(L("The selected 3mf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str(); const std::string msg = (boost::format(_u8L("The selected 3mf file has been saved with a newer version of %1% and is not compatible.")) % std::string(SLIC3R_APP_NAME)).str();
throw version_error(msg); throw version_error(msg);
} }
} else if (m_curr_metadata_name == "Application") { } else if (m_curr_metadata_name == "Application") {
@ -1888,15 +1883,15 @@ namespace Slic3r {
} else if (m_curr_metadata_name == SLIC3RPE_FDM_SUPPORTS_PAINTING_VERSION) { } else if (m_curr_metadata_name == SLIC3RPE_FDM_SUPPORTS_PAINTING_VERSION) {
m_fdm_supports_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); m_fdm_supports_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
check_painting_version(m_fdm_supports_painting_version, FDM_SUPPORTS_PAINTING_VERSION, check_painting_version(m_fdm_supports_painting_version, FDM_SUPPORTS_PAINTING_VERSION,
_(L("The selected 3MF contains FDM supports painted object using a newer version of PrusaSlicer and is not compatible."))); _u8L("The selected 3MF contains FDM supports painted object using a newer version of PrusaSlicer and is not compatible."));
} else if (m_curr_metadata_name == SLIC3RPE_SEAM_PAINTING_VERSION) { } else if (m_curr_metadata_name == SLIC3RPE_SEAM_PAINTING_VERSION) {
m_seam_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); m_seam_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
check_painting_version(m_seam_painting_version, SEAM_PAINTING_VERSION, check_painting_version(m_seam_painting_version, SEAM_PAINTING_VERSION,
_(L("The selected 3MF contains seam painted object using a newer version of PrusaSlicer and is not compatible."))); _u8L("The selected 3MF contains seam painted object using a newer version of PrusaSlicer and is not compatible."));
} else if (m_curr_metadata_name == SLIC3RPE_MM_PAINTING_VERSION) { } else if (m_curr_metadata_name == SLIC3RPE_MM_PAINTING_VERSION) {
m_mm_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); m_mm_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
check_painting_version(m_mm_painting_version, MM_PAINTING_VERSION, check_painting_version(m_mm_painting_version, MM_PAINTING_VERSION,
_(L("The selected 3MF contains multi-material painted object using a newer version of PrusaSlicer and is not compatible."))); _u8L("The selected 3MF contains multi-material painted object using a newer version of PrusaSlicer and is not compatible."));
} }
return true; return true;
@ -2963,6 +2958,8 @@ namespace Slic3r {
unsigned int object_cnt = 0; unsigned int object_cnt = 0;
for (const ModelObject* object : model.objects) { for (const ModelObject* object : model.objects) {
if (!object->is_cut())
continue;
object_cnt++; object_cnt++;
pt::ptree& obj_tree = tree.add("objects.object", ""); pt::ptree& obj_tree = tree.add("objects.object", "");

View File

@ -57,10 +57,6 @@ const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config";
namespace Slic3r namespace Slic3r
{ {
//! macro used to mark string used at localization,
//! return same string
#define L(s) (s)
#define _(s) Slic3r::I18N::translate(s)
struct AMFParserContext struct AMFParserContext
{ {
@ -965,7 +961,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
try try
{ {
res = mz_zip_reader_extract_file_to_callback(&archive, stat.m_filename, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t { res = mz_zip_reader_extract_to_callback(&archive, stat.m_file_index, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
CallbackData* data = (CallbackData*)pOpaque; CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->ctx.error()) if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->ctx.error())
{ {
@ -997,7 +993,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
{ {
// std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible.")); // std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
// throw Slic3r::FileIOError(msg.c_str()); // throw Slic3r::FileIOError(msg.c_str());
const std::string msg = (boost::format(_(L("The selected amf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str(); const std::string msg = (boost::format(_u8L("The selected amf file has been saved with a newer version of %1% and is not compatible.")) % std::string(SLIC3R_APP_NAME)).str();
throw Slic3r::FileIOError(msg); throw Slic3r::FileIOError(msg);
} }

View File

@ -1,13 +1,13 @@
#include "SLAArchiveReader.hpp" #include "SLAArchiveReader.hpp"
#include "SL1.hpp" #include "SL1.hpp"
#include "SL1_SVG.hpp" #include "SL1_SVG.hpp"
#include "I18N.hpp"
#include "libslic3r/SlicesToTriangleMesh.hpp" #include "libslic3r/SlicesToTriangleMesh.hpp"
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
constexpr const char * L(const char * str) { return str; }
#include <array> #include <array>
#include <map> #include <map>
@ -37,8 +37,8 @@ static const std::map<std::string, ArchiveEntry> REGISTERED_ARCHIVES {
[] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique<SL1Reader>(fname, quality, progr); } } [] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique<SL1Reader>(fname, quality, progr); } }
}, },
{ {
"SL2", "SL1SVG",
{ L("SL2 archive files"), {"sl2", "sl1_svg"/*, "zip"*/}, // also a zip but unnecessary hassle to implement single extension for multiple archives { L("SL1SVG archive files"), {"sl1_svg"/*, "zip"*/}, // also a zip but unnecessary hassle to implement single extension for multiple archives
[] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique<SL1_SVGReader>(fname, quality, progr); }} [] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique<SL1_SVGReader>(fname, quality, progr); }}
}, },
// TODO: pwmx and future others. // TODO: pwmx and future others.

View File

@ -25,9 +25,13 @@ static const std::map<std::string, ArchiveEntry> REGISTERED_ARCHIVES {
"SL1", "SL1",
{ "sl1", [] (const auto &cfg) { return std::make_unique<SL1Archive>(cfg); } } { "sl1", [] (const auto &cfg) { return std::make_unique<SL1Archive>(cfg); } }
}, },
{
"SL1SVG",
{ "sl1_svg", [] (const auto &cfg) { return std::make_unique<SL1_SVGArchive>(cfg); } }
},
{ {
"SL2", "SL2",
{ "sl2", [] (const auto &cfg) { return std::make_unique<SL1_SVGArchive>(cfg); } } { "sl1_svg", [] (const auto &cfg) { return std::make_unique<SL1_SVGArchive>(cfg); } }
}, },
{ {
"pwmx", "pwmx",

View File

@ -18,7 +18,7 @@ boost::property_tree::ptree read_ini(const mz_zip_archive_file_stat &entry,
{ {
std::string buf(size_t(entry.m_uncomp_size), '\0'); std::string buf(size_t(entry.m_uncomp_size), '\0');
if (!mz_zip_reader_extract_file_to_mem(&zip.arch, entry.m_filename, if (!mz_zip_reader_extract_to_mem(&zip.arch, entry.m_file_index,
buf.data(), buf.size(), 0)) buf.data(), buf.size(), 0))
throw Slic3r::FileIOError(zip.get_errorstr()); throw Slic3r::FileIOError(zip.get_errorstr());
@ -35,7 +35,7 @@ EntryBuffer read_entry(const mz_zip_archive_file_stat &entry,
{ {
std::vector<uint8_t> buf(entry.m_uncomp_size); std::vector<uint8_t> buf(entry.m_uncomp_size);
if (!mz_zip_reader_extract_file_to_mem(&zip.arch, entry.m_filename, if (!mz_zip_reader_extract_to_mem(&zip.arch, entry.m_file_index,
buf.data(), buf.size(), 0)) buf.data(), buf.size(), 0))
throw Slic3r::FileIOError(zip.get_errorstr()); throw Slic3r::FileIOError(zip.get_errorstr());

View File

@ -71,11 +71,6 @@ using namespace std::literals::string_view_literals;
namespace Slic3r { namespace Slic3r {
//! macro used to mark string used at localization,
//! return same string
#define L(s) (s)
#define _(s) Slic3r::I18N::translate(s)
// Only add a newline in case the current G-code does not end with a newline. // Only add a newline in case the current G-code does not end with a newline.
static inline void check_add_eol(std::string& gcode) static inline void check_add_eol(std::string& gcode)
{ {
@ -424,7 +419,7 @@ namespace Slic3r {
std::string WipeTowerIntegration::finalize(GCode& gcodegen) std::string WipeTowerIntegration::finalize(GCode& gcodegen)
{ {
std::string gcode; std::string gcode;
if (std::abs(gcodegen.writer().get_position()(2) - m_final_purge.print_z) > EPSILON) if (std::abs(gcodegen.writer().get_position().z() - m_final_purge.print_z) > EPSILON)
gcode += gcodegen.change_layer(m_final_purge.print_z); gcode += gcodegen.change_layer(m_final_purge.print_z);
gcode += append_tcr(gcodegen, m_final_purge, -1); gcode += append_tcr(gcodegen, m_final_purge, -1);
return gcode; return gcode;
@ -434,6 +429,91 @@ namespace Slic3r {
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id()) #define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
void GCode::PlaceholderParserIntegration::reset()
{
this->failed_templates.clear();
this->output_config.clear();
this->opt_position = nullptr;
this->opt_zhop = nullptr;
this->opt_e_position = nullptr;
this->opt_e_retracted = nullptr;
this->opt_e_restart_extra = nullptr;
this->num_extruders = 0;
this->position.clear();
this->e_position.clear();
this->e_retracted.clear();
this->e_restart_extra.clear();
}
void GCode::PlaceholderParserIntegration::init(const GCodeWriter &writer)
{
this->reset();
const std::vector<Extruder> &extruders = writer.extruders();
if (! extruders.empty()) {
this->num_extruders = extruders.back().id() + 1;
this->e_retracted.assign(num_extruders, 0);
this->e_restart_extra.assign(num_extruders, 0);
this->opt_e_retracted = new ConfigOptionFloats(e_retracted);
this->opt_e_restart_extra = new ConfigOptionFloats(e_restart_extra);
this->output_config.set_key_value("e_retracted", this->opt_e_retracted);
this->output_config.set_key_value("e_restart_extra", this->opt_e_restart_extra);
if (! writer.config.use_relative_e_distances) {
e_position.assign(num_extruders, 0);
opt_e_position = new ConfigOptionFloats(e_position);
this->output_config.set_key_value("e_position", opt_e_position);
}
}
// Reserve buffer for current position.
this->position.assign(3, 0);
this->opt_position = new ConfigOptionFloats(this->position);
this->output_config.set_key_value("position", this->opt_position);
// Store zhop variable into the parser itself, it is a read-only variable to the script.
this->opt_zhop = new ConfigOptionFloat(writer.get_zhop());
this->parser.set("zhop", this->opt_zhop);
}
void GCode::PlaceholderParserIntegration::update_from_gcodewriter(const GCodeWriter &writer)
{
memcpy(this->position.data(), writer.get_position().data(), sizeof(double) * 3);
this->opt_position->values = this->position;
this->opt_zhop->value = writer.get_zhop();
if (this->num_extruders > 0) {
const std::vector<Extruder> &extruders = writer.extruders();
assert(! extruders.empty() && num_extruders == extruders.back().id() + 1);
this->e_retracted.assign(num_extruders, 0);
this->e_restart_extra.assign(num_extruders, 0);
for (const Extruder &e : extruders) {
this->e_retracted[e.id()] = e.retracted();
this->e_restart_extra[e.id()] = e.restart_extra();
}
opt_e_retracted->values = this->e_retracted;
opt_e_restart_extra->values = this->e_restart_extra;
if (! writer.config.use_relative_e_distances) {
this->e_position.assign(num_extruders, 0);
for (const Extruder &e : extruders)
this->e_position[e.id()] = e.position();
this->opt_e_position->values = this->e_position;
}
}
}
// Throw if any of the output vector variables were resized by the script.
void GCode::PlaceholderParserIntegration::validate_output_vector_variables()
{
if (this->opt_position->values.size() != 3)
throw Slic3r::RuntimeError("\"position\" output variable must not be resized by the script.");
if (this->num_extruders > 0) {
if (this->opt_e_position && this->opt_e_position->values.size() != this->num_extruders)
throw Slic3r::RuntimeError("\"e_position\" output variable must not be resized by the script.");
if (this->opt_e_retracted->values.size() != this->num_extruders)
throw Slic3r::RuntimeError("\"e_retracted\" output variable must not be resized by the script.");
if (this->opt_e_restart_extra->values.size() != this->num_extruders)
throw Slic3r::RuntimeError("\"e_restart_extra\" output variable must not be resized by the script.");
}
}
// Collect pairs of object_layer + support_layer sorted by print_z. // Collect pairs of object_layer + support_layer sorted by print_z.
// object_layer & support_layer are considered to be on the same print_z, if they are not further than EPSILON. // object_layer & support_layer are considered to be on the same print_z, if they are not further than EPSILON.
GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& object) GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& object)
@ -487,8 +567,8 @@ GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& obj
// first layer may result in skirt/brim in the air and maybe other issues. // first layer may result in skirt/brim in the air and maybe other issues.
if (layers_to_print.size() == 1u) { if (layers_to_print.size() == 1u) {
if (!has_extrusions) if (!has_extrusions)
throw Slic3r::SlicingError(_(L("There is an object with no extrusions in the first layer.")) + "\n" + throw Slic3r::SlicingError(_u8L("There is an object with no extrusions in the first layer.") + "\n" +
_(L("Object name")) + ": " + object.model_object()->name); _u8L("Object name") + ": " + object.model_object()->name);
} }
// In case there are extrusions on this layer, check there is a layer to lay it on. // In case there are extrusions on this layer, check there is a layer to lay it on.
@ -518,14 +598,14 @@ GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& obj
std::string warning; std::string warning;
size_t i = 0; size_t i = 0;
for (i = 0; i < std::min(warning_ranges.size(), size_t(3)); ++i) for (i = 0; i < std::min(warning_ranges.size(), size_t(3)); ++i)
warning += Slic3r::format(_(L("Empty layer between %1% and %2%.")), warning += Slic3r::format(_u8L("Empty layer between %1% and %2%."),
warning_ranges[i].first, warning_ranges[i].second) + "\n"; warning_ranges[i].first, warning_ranges[i].second) + "\n";
if (i < warning_ranges.size()) if (i < warning_ranges.size())
warning += _(L("(Some lines not shown)")) + "\n"; warning += _u8L("(Some lines not shown)") + "\n";
warning += "\n"; warning += "\n";
warning += Slic3r::format(_(L("Object name: %1%")), object.model_object()->name) + "\n\n" warning += Slic3r::format(_u8L("Object name: %1%"), object.model_object()->name) + "\n\n"
+ _(L("Make sure the object is printable. This is usually caused by negligibly small extrusions or by a faulty model. " + _u8L("Make sure the object is printable. This is usually caused by negligibly small extrusions or by a faulty model. "
"Try to repair the model or change its orientation on the bed.")); "Try to repair the model or change its orientation on the bed.");
const_cast<Print*>(object.print())->active_step_add_warning( const_cast<Print*>(object.print())->active_step_add_warning(
PrintStateBase::WarningLevel::CRITICAL, warning); PrintStateBase::WarningLevel::CRITICAL, warning);
@ -655,25 +735,25 @@ namespace DoExport {
}; };
const GCodeConfig& config = print.config(); const GCodeConfig& config = print.config();
check(_(L("Start G-code")), config.start_gcode.value); check(_u8L("Start G-code"), config.start_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("End G-code")), config.end_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_u8L("End G-code"), config.end_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Before layer change G-code")), config.before_layer_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Before layer change G-code"), config.before_layer_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("After layer change G-code")), config.layer_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_u8L("After layer change G-code"), config.layer_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Tool change G-code")), config.toolchange_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Tool change G-code"), config.toolchange_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Between objects G-code (for sequential printing)")), config.between_objects_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Between objects G-code (for sequential printing)"), config.between_objects_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Color Change G-code"), config.color_change_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause Print G-code")), config.pause_print_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Pause Print G-code"), config.pause_print_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Template Custom G-code"), config.template_custom_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) { if (ret.size() < MAX_TAGS_COUNT) {
for (const std::string& value : config.start_filament_gcode.values) { for (const std::string& value : config.start_filament_gcode.values) {
check(_(L("Filament Start G-code")), value); check(_u8L("Filament Start G-code"), value);
if (ret.size() == MAX_TAGS_COUNT) if (ret.size() == MAX_TAGS_COUNT)
break; break;
} }
} }
if (ret.size() < MAX_TAGS_COUNT) { if (ret.size() < MAX_TAGS_COUNT) {
for (const std::string& value : config.end_filament_gcode.values) { for (const std::string& value : config.end_filament_gcode.values) {
check(_(L("Filament End G-code")), value); check(_u8L("Filament End G-code"), value);
if (ret.size() == MAX_TAGS_COUNT) if (ret.size() == MAX_TAGS_COUNT)
break; break;
} }
@ -681,7 +761,7 @@ namespace DoExport {
if (ret.size() < MAX_TAGS_COUNT) { if (ret.size() < MAX_TAGS_COUNT) {
const CustomGCode::Info& custom_gcode_per_print_z = print.model().custom_gcode_per_print_z; const CustomGCode::Info& custom_gcode_per_print_z = print.model().custom_gcode_per_print_z;
for (const auto& gcode : custom_gcode_per_print_z.gcodes) { for (const auto& gcode : custom_gcode_per_print_z.gcodes) {
check(_(L("Custom G-code")), gcode.extra); check(_u8L("Custom G-code"), gcode.extra);
if (ret.size() == MAX_TAGS_COUNT) if (ret.size() == MAX_TAGS_COUNT)
break; break;
} }
@ -714,9 +794,9 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
reports += source + ": \"" + keyword + "\"\n"; reports += source + ": \"" + keyword + "\"\n";
} }
print->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, print->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
_(L("In the custom G-code were found reserved keywords:")) + "\n" + _u8L("In the custom G-code were found reserved keywords:") + "\n" +
reports + reports +
_(L("This may cause problems in g-code visualization and printing time estimation."))); _u8L("This may cause problems in g-code visualization and printing time estimation."));
} }
BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info(); BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info();
@ -733,7 +813,6 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n"); throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
try { try {
m_placeholder_parser_failed_templates.clear();
this->_do_export(*print, file, thumbnail_cb); this->_do_export(*print, file, thumbnail_cb);
file.flush(); file.flush();
if (file.is_error()) { if (file.is_error()) {
@ -750,11 +829,11 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
} }
file.close(); file.close();
if (! m_placeholder_parser_failed_templates.empty()) { if (! m_placeholder_parser_integration.failed_templates.empty()) {
// G-code export proceeded, but some of the PlaceholderParser substitutions failed. // G-code export proceeded, but some of the PlaceholderParser substitutions failed.
//FIXME localize! //FIXME localize!
std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n"; std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n";
for (const auto &name_and_error : m_placeholder_parser_failed_templates) for (const auto &name_and_error : m_placeholder_parser_integration.failed_templates)
msg += name_and_error.first + "\n" + name_and_error.second + "\n"; msg += name_and_error.first + "\n" + name_and_error.second + "\n";
msg += "\nPlease inspect the file "; msg += "\nPlease inspect the file ";
msg += path_tmp + " for error messages enclosed between\n"; msg += path_tmp + " for error messages enclosed between\n";
@ -1083,10 +1162,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
file.find_replace_enable(); file.find_replace_enable();
// Prepare the helper object for replacing placeholders in custom G-code and output filename. // Prepare the helper object for replacing placeholders in custom G-code and output filename.
m_placeholder_parser = print.placeholder_parser(); m_placeholder_parser_integration.parser = print.placeholder_parser();
m_placeholder_parser.update_timestamp(); m_placeholder_parser_integration.parser.update_timestamp();
m_placeholder_parser_context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count()); m_placeholder_parser_integration.context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count());
print.update_object_placeholders(m_placeholder_parser.config_writable(), ".gcode"); // Enable passing global variables between PlaceholderParser invocations.
m_placeholder_parser_integration.context.global_config = std::make_unique<DynamicConfig>();
print.update_object_placeholders(m_placeholder_parser_integration.parser.config_writable(), ".gcode");
// Get optimal tool ordering to minimize tool switches of a multi-exruder print. // Get optimal tool ordering to minimize tool switches of a multi-exruder print.
// For a print by objects, find the 1st printing object. // For a print by objects, find the 1st printing object.
@ -1109,7 +1190,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
} }
if (initial_extruder_id == static_cast<unsigned int>(-1)) if (initial_extruder_id == static_cast<unsigned int>(-1))
// No object to print was found, cancel the G-code export. // No object to print was found, cancel the G-code export.
throw Slic3r::SlicingError(_(L("No extrusions were generated for objects."))); throw Slic3r::SlicingError(_u8L("No extrusions were generated for objects."));
// We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode. // We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode.
// Use the extruder IDs collected from Regions. // Use the extruder IDs collected from Regions.
this->set_extruders(print.extruders()); this->set_extruders(print.extruders());
@ -1120,7 +1201,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
tool_ordering.assign_custom_gcodes(print); tool_ordering.assign_custom_gcodes(print);
if (tool_ordering.all_extruders().empty()) if (tool_ordering.all_extruders().empty())
// No object to print was found, cancel the G-code export. // No object to print was found, cancel the G-code export.
throw Slic3r::SlicingError(_(L("No extrusions were generated for objects."))); throw Slic3r::SlicingError(_u8L("No extrusions were generated for objects."));
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower();
initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ? initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ?
// The priming towers will be skipped. // The priming towers will be skipped.
@ -1150,27 +1231,25 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
// Emit machine envelope limits for the Marlin firmware. // Emit machine envelope limits for the Marlin firmware.
this->print_machine_envelope(file, print); this->print_machine_envelope(file, print);
// Disable fan. // Update output variables after the extruders were initialized.
if (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id)) m_placeholder_parser_integration.init(m_writer);
file.write(m_writer.set_fan(0));
// Let the start-up script prime the 1st printing tool. // Let the start-up script prime the 1st printing tool.
m_placeholder_parser.set("initial_tool", initial_extruder_id); this->placeholder_parser().set("initial_tool", initial_extruder_id);
m_placeholder_parser.set("initial_extruder", initial_extruder_id); this->placeholder_parser().set("initial_extruder", initial_extruder_id);
m_placeholder_parser.set("current_extruder", initial_extruder_id); this->placeholder_parser().set("current_extruder", initial_extruder_id);
//Set variable for total layer count so it can be used in custom gcode. //Set variable for total layer count so it can be used in custom gcode.
m_placeholder_parser.set("total_layer_count", m_layer_count); this->placeholder_parser().set("total_layer_count", m_layer_count);
// Useful for sequential prints. // Useful for sequential prints.
m_placeholder_parser.set("current_object_idx", 0); this->placeholder_parser().set("current_object_idx", 0);
// For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided. // For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided.
m_placeholder_parser.set("has_wipe_tower", has_wipe_tower); this->placeholder_parser().set("has_wipe_tower", has_wipe_tower);
m_placeholder_parser.set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming); this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming);
m_placeholder_parser.set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change). this->placeholder_parser().set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
{ {
BoundingBoxf bbox(print.config().bed_shape.values); BoundingBoxf bbox(print.config().bed_shape.values);
m_placeholder_parser.set("print_bed_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() })); this->placeholder_parser().set("print_bed_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
m_placeholder_parser.set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() })); this->placeholder_parser().set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
m_placeholder_parser.set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() })); this->placeholder_parser().set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
} }
{ {
// Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line. // Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line.
@ -1183,15 +1262,15 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
for (const Point &pt : print.first_layer_convex_hull().points) for (const Point &pt : print.first_layer_convex_hull().points)
pts->values.emplace_back(unscale(pt)); pts->values.emplace_back(unscale(pt));
BoundingBoxf bbox(pts->values); BoundingBoxf bbox(pts->values);
m_placeholder_parser.set("first_layer_print_convex_hull", pts.release()); this->placeholder_parser().set("first_layer_print_convex_hull", pts.release());
m_placeholder_parser.set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() })); this->placeholder_parser().set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
m_placeholder_parser.set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() })); this->placeholder_parser().set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
m_placeholder_parser.set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() })); this->placeholder_parser().set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
std::vector<unsigned char> is_extruder_used(print.config().nozzle_diameter.size(), 0); std::vector<unsigned char> is_extruder_used(print.config().nozzle_diameter.size(), 0);
for (unsigned int extruder_id : tool_ordering.all_extruders()) for (unsigned int extruder_id : tool_ordering.all_extruders())
is_extruder_used[extruder_id] = true; is_extruder_used[extruder_id] = true;
m_placeholder_parser.set("is_extruder_used", new ConfigOptionBools(is_extruder_used)); this->placeholder_parser().set("is_extruder_used", new ConfigOptionBools(is_extruder_used));
} }
// Enable ooze prevention if configured so. // Enable ooze prevention if configured so.
@ -1258,7 +1337,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
// Ff we are printing the bottom layer of an object, and we have already finished // Ff we are printing the bottom layer of an object, and we have already finished
// another one, set first layer temperatures. This happens before the Z move // another one, set first layer temperatures. This happens before the Z move
// is triggered, so machine has more time to reach such temperatures. // is triggered, so machine has more time to reach such temperatures.
m_placeholder_parser.set("current_object_idx", int(finished_objects)); this->placeholder_parser().set("current_object_idx", int(finished_objects));
std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config().between_objects_gcode.value, initial_extruder_id); std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config().between_objects_gcode.value, initial_extruder_id);
// Set first layer bed and extruder temperatures, don't wait for it to reach the temperature. // Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false); this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false);
@ -1314,8 +1393,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
// (See https://github.com/prusa3d/PrusaSlicer/issues/5441.) // (See https://github.com/prusa3d/PrusaSlicer/issues/5441.)
if (overlap) { if (overlap) {
print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
_(L("Your print is very close to the priming regions. " _u8L("Your print is very close to the priming regions. "
"Make sure there is no collision."))); "Make sure there is no collision."));
} else { } else {
// Just continue printing, no action necessary. // Just continue printing, no action necessary.
} }
@ -1344,7 +1423,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
{ {
DynamicConfig config; DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value)); config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position().z() - m_config.z_offset.value));
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
if (print.config().single_extruder_multi_material) { if (print.config().single_extruder_multi_material) {
// Process the end_filament_gcode for the active filament only. // Process the end_filament_gcode for the active filament only.
@ -1567,17 +1646,46 @@ void GCode::process_layers(
output_stream.find_replace_enable(); output_stream.find_replace_enable();
} }
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) std::string GCode::placeholder_parser_process(
const std::string &name,
const std::string &templ,
unsigned int current_extruder_id,
const DynamicConfig *config_override)
{ {
PlaceholderParserIntegration &ppi = m_placeholder_parser_integration;
try { try {
return m_placeholder_parser.process(templ, current_extruder_id, config_override, &m_placeholder_parser_context); ppi.update_from_gcodewriter(m_writer);
} catch (std::runtime_error &err) { std::string output = ppi.parser.process(templ, current_extruder_id, config_override, &ppi.output_config, &ppi.context);
ppi.validate_output_vector_variables();
if (const std::vector<double> &pos = ppi.opt_position->values; ppi.position != pos) {
// Update G-code writer.
m_writer.update_position({ pos[0], pos[1], pos[2] });
this->set_last_pos(this->gcode_to_point({ pos[0], pos[1] }));
}
for (const Extruder &e : m_writer.extruders()) {
unsigned int eid = e.id();
assert(eid < ppi.num_extruders);
if ( eid < ppi.num_extruders) {
if (! m_writer.config.use_relative_e_distances && ! is_approx(ppi.e_position[eid], ppi.opt_e_position->values[eid]))
const_cast<Extruder&>(e).set_position(ppi.opt_e_position->values[eid]);
if (! is_approx(ppi.e_retracted[eid], ppi.opt_e_retracted->values[eid]) ||
! is_approx(ppi.e_restart_extra[eid], ppi.opt_e_restart_extra->values[eid]))
const_cast<Extruder&>(e).set_retracted(ppi.opt_e_retracted->values[eid], ppi.opt_e_restart_extra->values[eid]);
}
}
return output;
}
catch (std::runtime_error &err)
{
// Collect the names of failed template substitutions for error reporting. // Collect the names of failed template substitutions for error reporting.
auto it = m_placeholder_parser_failed_templates.find(name); auto it = ppi.failed_templates.find(name);
if (it == m_placeholder_parser_failed_templates.end()) if (it == ppi.failed_templates.end())
// Only if there was no error reported for this template, store the first error message into the map to be reported. // Only if there was no error reported for this template, store the first error message into the map to be reported.
// We don't want to collect error message for each and every occurence of a single custom G-code section. // We don't want to collect error message for each and every occurence of a single custom G-code section.
m_placeholder_parser_failed_templates.insert(it, std::make_pair(name, std::string(err.what()))); ppi.failed_templates.insert(it, std::make_pair(name, std::string(err.what())));
// Insert the macro error message into the G-code. // Insert the macro error message into the G-code.
return return
std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" + std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" +
@ -1670,23 +1778,25 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print)
int(print.config().machine_max_feedrate_e.values.front() * factor + 0.5), int(print.config().machine_max_feedrate_e.values.front() * factor + 0.5),
factor == 60 ? "mm / min" : "mm / sec"); factor == 60 ? "mm / min" : "mm / sec");
// Now M204 - acceleration. This one is quite hairy thanks to how Marlin guys care about // Now M204 - acceleration. This one is quite hairy...
// backwards compatibility: https://github.com/prusa3d/PrusaSlicer/issues/1089
// Legacy Marlin should export travel acceleration the same as printing acceleration.
// MarlinFirmware has the two separated.
int travel_acc = flavor == gcfMarlinLegacy
? int(print.config().machine_max_acceleration_extruding.values.front() + 0.5)
: int(print.config().machine_max_acceleration_travel.values.front() + 0.5);
// Retract acceleration not accepted in M204 in RRF
if (flavor == gcfRepRapFirmware) if (flavor == gcfRepRapFirmware)
// Uses M204 P[print] T[travel]
file.write_format("M204 P%d T%d ; sets acceleration (P, T), mm/sec^2\n", file.write_format("M204 P%d T%d ; sets acceleration (P, T), mm/sec^2\n",
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
travel_acc); int(print.config().machine_max_acceleration_travel.values.front() + 0.5));
else else if (flavor == gcfMarlinLegacy)
// Legacy Marlin uses M204 S[print] T[retract]
file.write_format("M204 S%d T%d ; sets acceleration (S) and retract acceleration (R), 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));
else if (flavor == gcfMarlinFirmware)
// New Marlin uses M204 P[print] R[retract] T[travel]
file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n", file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n",
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
int(print.config().machine_max_acceleration_retracting.values.front() + 0.5), int(print.config().machine_max_acceleration_retracting.values.front() + 0.5),
travel_acc); int(print.config().machine_max_acceleration_travel.values.front() + 0.5));
else
assert(false);
assert(is_decimal_separator_point()); assert(is_decimal_separator_point());
file.write_format(flavor == gcfRepRapFirmware file.write_format(flavor == gcfRepRapFirmware
@ -1713,17 +1823,18 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print)
// M190 - Set Extruder Temperature and Wait // M190 - Set Extruder Temperature and Wait
void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait) void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
{ {
bool autoemit = print.config().autoemit_temperature_commands;
// Initial bed temperature based on the first extruder. // Initial bed temperature based on the first extruder.
int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id); int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id);
// Is the bed temperature set by the provided custom G-code? // Is the bed temperature set by the provided custom G-code?
int temp_by_gcode = -1; int temp_by_gcode = -1;
bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, false, temp_by_gcode); bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, false, temp_by_gcode);
if (temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000) if (autoemit && temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000)
temp = temp_by_gcode; temp = temp_by_gcode;
// Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
// the custom start G-code emited these. // the custom start G-code emited these.
std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait); std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait);
if (! temp_set_by_gcode) if (autoemit && ! temp_set_by_gcode)
file.write(set_temp_gcode); file.write(set_temp_gcode);
} }
@ -1734,13 +1845,14 @@ void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &p
// RepRapFirmware: G10 Sxx // RepRapFirmware: G10 Sxx
void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait) void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
{ {
bool autoemit = print.config().autoemit_temperature_commands;
// Is the bed temperature set by the provided custom G-code? // Is the bed temperature set by the provided custom G-code?
int temp_by_gcode = -1; int temp_by_gcode = -1;
bool include_g10 = print.config().gcode_flavor == gcfRepRapFirmware; bool include_g10 = print.config().gcode_flavor == gcfRepRapFirmware;
if (custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) { if (! autoemit || custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) {
// Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code. // Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id); int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
if (temp_by_gcode >= 0 && temp_by_gcode < 1000) if (autoemit && temp_by_gcode >= 0 && temp_by_gcode < 1000)
temp = temp_by_gcode; temp = temp_by_gcode;
m_writer.set_temperature(temp, wait, first_printing_extruder_id); m_writer.set_temperature(temp, wait, first_printing_extruder_id);
} else { } else {
@ -2550,7 +2662,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr
} }
// reset acceleration // reset acceleration
gcode += m_writer.set_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5)); gcode += m_writer.set_print_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5));
if (m_wipe.enable) { if (m_wipe.enable) {
m_wipe.path = paths.front().polyline; m_wipe.path = paths.front().polyline;
@ -2636,7 +2748,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::s
} }
} }
// reset acceleration // reset acceleration
gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
return gcode; return gcode;
} }
@ -2662,7 +2774,7 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string_view description
m_wipe.path.reverse(); m_wipe.path.reverse();
} }
// reset acceleration // reset acceleration
gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
return gcode; return gcode;
} }
@ -2805,7 +2917,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
} else { } else {
acceleration = m_config.default_acceleration.value; acceleration = m_config.default_acceleration.value;
} }
gcode += m_writer.set_acceleration((unsigned int)floor(acceleration + 0.5)); gcode += m_writer.set_print_acceleration((unsigned int)floor(acceleration + 0.5));
} }
// calculate extrusion length per distance unit // calculate extrusion length per distance unit
@ -3074,8 +3186,18 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
// use G1 because we rely on paths being straight (G0 may make round paths) // use G1 because we rely on paths being straight (G0 may make round paths)
if (travel.size() >= 2) { if (travel.size() >= 2) {
gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5));
for (size_t i = 1; i < travel.size(); ++ i) for (size_t i = 1; i < travel.size(); ++ i)
gcode += m_writer.travel_to_xy(this->point_to_gcode(travel.points[i]), comment); gcode += m_writer.travel_to_xy(this->point_to_gcode(travel.points[i]), comment);
if (! GCodeWriter::supports_separate_travel_acceleration(config().gcode_flavor)) {
// In case that this flavor does not support separate print and travel acceleration,
// reset acceleration to default.
gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5));
}
this->set_last_pos(travel.points.back()); this->set_last_pos(travel.points.back());
} }
return gcode; return gcode;
@ -3153,7 +3275,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
// if we are running a single-extruder setup, just set the extruder and return nothing // if we are running a single-extruder setup, just set the extruder and return nothing
if (!m_writer.multiple_extruders) { if (!m_writer.multiple_extruders) {
m_placeholder_parser.set("current_extruder", extruder_id); this->placeholder_parser().set("current_extruder", extruder_id);
std::string gcode; std::string gcode;
// Append the filament start G-code. // Append the filament start G-code.
@ -3162,7 +3284,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
// Process the start_filament_gcode for the filament. // Process the start_filament_gcode for the filament.
DynamicConfig config; DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position()(2) - m_config.z_offset.value)); config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id))); config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config); gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
@ -3226,7 +3348,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
gcode += m_writer.set_temperature(temp, false); gcode += m_writer.set_temperature(temp, false);
} }
m_placeholder_parser.set("current_extruder", extruder_id); this->placeholder_parser().set("current_extruder", extruder_id);
// Append the filament start G-code. // Append the filament start G-code.
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id); const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
@ -3234,7 +3356,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
// Process the start_filament_gcode for the new filament. // Process the start_filament_gcode for the new filament.
DynamicConfig config; DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position()(2) - m_config.z_offset.value)); config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id))); config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config); gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
@ -3263,10 +3385,12 @@ Vec2d GCode::point_to_gcode_quantized(const Point &point) const
// convert a model-space scaled point into G-code coordinates // convert a model-space scaled point into G-code coordinates
Point GCode::gcode_to_point(const Vec2d &point) const Point GCode::gcode_to_point(const Vec2d &point) const
{ {
Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset); Vec2d pt = point - m_origin;
return Point( if (const Extruder *extruder = m_writer.extruder(); extruder)
scale_(point(0) - m_origin(0) + extruder_offset(0)), // This function may be called at the very start from toolchange G-code when the extruder is not assigned yet.
scale_(point(1) - m_origin(1) + extruder_offset(1))); pt += m_config.extruder_offset.get_at(extruder->id());
return scaled<coord_t>(pt);
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -173,8 +173,8 @@ public:
const Layer* layer() const { return m_layer; } const Layer* layer() const { return m_layer; }
GCodeWriter& writer() { return m_writer; } GCodeWriter& writer() { return m_writer; }
const GCodeWriter& writer() const { return m_writer; } const GCodeWriter& writer() const { return m_writer; }
PlaceholderParser& placeholder_parser() { return m_placeholder_parser; } PlaceholderParser& placeholder_parser() { return m_placeholder_parser_integration.parser; }
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; } const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser_integration.parser; }
// Process a template through the placeholder parser, collect error messages to be reported // Process a template through the placeholder parser, collect error messages to be reported
// inside the generated string and after the G-code export finishes. // inside the generated string and after the G-code export finishes.
std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr); std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr);
@ -343,11 +343,33 @@ private:
// scaled G-code resolution // scaled G-code resolution
double m_scaled_resolution; double m_scaled_resolution;
GCodeWriter m_writer; GCodeWriter m_writer;
PlaceholderParser m_placeholder_parser;
// For random number generator etc. struct PlaceholderParserIntegration {
PlaceholderParser::ContextData m_placeholder_parser_context; void reset();
// Collection of templates, on which the placeholder substitution failed. void init(const GCodeWriter &config);
std::map<std::string, std::string> m_placeholder_parser_failed_templates; void update_from_gcodewriter(const GCodeWriter &writer);
void validate_output_vector_variables();
PlaceholderParser parser;
// For random number generator etc.
PlaceholderParser::ContextData context;
// Collection of templates, on which the placeholder substitution failed.
std::map<std::string, std::string> failed_templates;
// Input/output from/to custom G-code block, for returning position, retraction etc.
DynamicConfig output_config;
ConfigOptionFloats *opt_position { nullptr };
ConfigOptionFloat *opt_zhop { nullptr };
ConfigOptionFloats *opt_e_position { nullptr };
ConfigOptionFloats *opt_e_retracted { nullptr };
ConfigOptionFloats *opt_e_restart_extra { nullptr };
// Caches of the data passed to the script.
size_t num_extruders;
std::vector<double> position;
std::vector<double> e_position;
std::vector<double> e_retracted;
std::vector<double> e_restart_extra;
} m_placeholder_parser_integration;
OozePrevention m_ooze_prevention; OozePrevention m_ooze_prevention;
Wipe m_wipe; Wipe m_wipe;
AvoidCrossingPerimeters m_avoid_crossing_perimeters; AvoidCrossingPerimeters m_avoid_crossing_perimeters;
@ -403,15 +425,15 @@ private:
// Index of a last object copy extruded. // Index of a last object copy extruded.
std::pair<const PrintObject*, Point> m_last_obj_copy; std::pair<const PrintObject*, Point> m_last_obj_copy;
bool m_silent_time_estimator_enabled; bool m_silent_time_estimator_enabled;
// Processor // Processor
GCodeProcessor m_processor; GCodeProcessor m_processor;
std::string _extrude(const ExtrusionPath &path, const std::string_view description, double speed = -1); std::string _extrude(const ExtrusionPath &path, const std::string_view description, double speed = -1);
void print_machine_envelope(GCodeOutputStream &file, Print &print); void print_machine_envelope(GCodeOutputStream &file, Print &print);
void _print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); void _print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait); void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
// On the first printing layer. This flag triggers first layer speeds. // On the first printing layer. This flag triggers first layer speeds.
bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; } bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; }
// To control print speed of 1st object layer over raft interface. // To control print speed of 1st object layer over raft interface.

View File

@ -789,10 +789,11 @@ std::string CoolingBuffer::apply_layer_cooldown(
} }
#undef EXTRUDER_CONFIG #undef EXTRUDER_CONFIG
bridge_fan_control = bridge_fan_speed > fan_speed_new; bridge_fan_control = bridge_fan_speed > fan_speed_new;
} else { } else { // fan disabled
bridge_fan_control = false; bridge_fan_control = false;
bridge_fan_speed = 0; bridge_fan_speed = 0;
fan_speed_new = 0; fan_speed_new = 0;
custom_fan_speed_limits.second = 0;
} }
if (fan_speed_new != m_fan_speed) { if (fan_speed_new != m_fan_speed) {
m_fan_speed = fan_speed_new; m_fan_speed = fan_speed_new;

View File

@ -3,6 +3,7 @@
#include "libslic3r/Print.hpp" #include "libslic3r/Print.hpp"
#include "libslic3r/LocalesUtils.hpp" #include "libslic3r/LocalesUtils.hpp"
#include "libslic3r/format.hpp" #include "libslic3r/format.hpp"
#include "libslic3r/GCodeWriter.hpp"
#include "GCodeProcessor.hpp" #include "GCodeProcessor.hpp"
#include <boost/algorithm/string/case_conv.hpp> #include <boost/algorithm/string/case_conv.hpp>
@ -568,10 +569,11 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
m_result.filament_cost[i] = static_cast<float>(config.filament_cost.get_at(i)); m_result.filament_cost[i] = static_cast<float>(config.filament_cost.get_at(i));
} }
if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware) && config.machine_limits_usage.value != MachineLimitsUsage::Ignore) { if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware || m_flavor == gcfKlipper)
&& config.machine_limits_usage.value != MachineLimitsUsage::Ignore) {
m_time_processor.machine_limits = reinterpret_cast<const MachineEnvelopeConfig&>(config); m_time_processor.machine_limits = reinterpret_cast<const MachineEnvelopeConfig&>(config);
if (m_flavor == gcfMarlinLegacy) { if (m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper) {
// Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead. // Legacy Marlin and Klipper don't have separate travel acceleration, they use the 'extruding' value instead.
m_time_processor.machine_limits.machine_max_acceleration_travel = m_time_processor.machine_limits.machine_max_acceleration_extruding; m_time_processor.machine_limits.machine_max_acceleration_travel = m_time_processor.machine_limits.machine_max_acceleration_extruding;
} }
if (m_flavor == gcfRepRapFirmware) { if (m_flavor == gcfRepRapFirmware) {
@ -609,7 +611,12 @@ for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::
float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i); float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i);
m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration; m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration;
m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration : DEFAULT_RETRACT_ACCELERATION; m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration : DEFAULT_RETRACT_ACCELERATION;
float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i); float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
if ( ! GCodeWriter::supports_separate_travel_acceleration(config.gcode_flavor.value) || config.machine_limits_usage.value != MachineLimitsUsage::EmitToGCode) {
// Only clamp travel acceleration when it is accessible in machine limits.
max_travel_acceleration = 0;
}
m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration; m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION; m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
} }
@ -788,7 +795,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
if (machine_limits_usage != nullptr) if (machine_limits_usage != nullptr)
use_machine_limits = machine_limits_usage->value != MachineLimitsUsage::Ignore; use_machine_limits = machine_limits_usage->value != MachineLimitsUsage::Ignore;
if (use_machine_limits && (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware)) { if (use_machine_limits && (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware || m_flavor == gcfKlipper)) {
const ConfigOptionFloats* machine_max_acceleration_x = config.option<ConfigOptionFloats>("machine_max_acceleration_x"); const ConfigOptionFloats* machine_max_acceleration_x = config.option<ConfigOptionFloats>("machine_max_acceleration_x");
if (machine_max_acceleration_x != nullptr) if (machine_max_acceleration_x != nullptr)
m_time_processor.machine_limits.machine_max_acceleration_x.values = machine_max_acceleration_x->values; m_time_processor.machine_limits.machine_max_acceleration_x.values = machine_max_acceleration_x->values;
@ -846,8 +853,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
m_time_processor.machine_limits.machine_max_acceleration_retracting.values = machine_max_acceleration_retracting->values; m_time_processor.machine_limits.machine_max_acceleration_retracting.values = machine_max_acceleration_retracting->values;
// Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead. // Legacy Marlin and Klipper don't have separate travel acceleration, they use the 'extruding' value instead.
const ConfigOptionFloats* machine_max_acceleration_travel = config.option<ConfigOptionFloats>(m_flavor == gcfMarlinLegacy const ConfigOptionFloats* machine_max_acceleration_travel = config.option<ConfigOptionFloats>((m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper)
? "machine_max_acceleration_extruding" ? "machine_max_acceleration_extruding"
: "machine_max_acceleration_travel"); : "machine_max_acceleration_travel");
if (machine_max_acceleration_travel != nullptr) if (machine_max_acceleration_travel != nullptr)
@ -885,7 +892,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION; m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
} }
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) { if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) { // No Klipper here, it does not support silent mode.
const ConfigOptionBool* silent_mode = config.option<ConfigOptionBool>("silent_mode"); const ConfigOptionBool* silent_mode = config.option<ConfigOptionBool>("silent_mode");
if (silent_mode != nullptr) { if (silent_mode != nullptr) {
if (silent_mode->value && m_time_processor.machine_limits.machine_max_acceleration_x.values.size() > 1) if (silent_mode->value && m_time_processor.machine_limits.machine_max_acceleration_x.values.size() > 1)
@ -3244,7 +3251,7 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line)
void GCodeProcessor::process_M220(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_M220(const GCodeReader::GCodeLine& line)
{ {
if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware) if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware && m_flavor != gcfKlipper)
return; return;
if (line.has('B')) if (line.has('B'))

View File

@ -185,11 +185,6 @@ static int run_script(const std::string &script, const std::string &gcode, std::
namespace Slic3r { namespace Slic3r {
//! macro used to mark string used at localization,
//! return same string
#define L(s) (s)
#define _(s) Slic3r::I18N::translate(s)
// Run post processing script / scripts if defined. // Run post processing script / scripts if defined.
// Returns true if a post-processing script was executed. // Returns true if a post-processing script was executed.
// Returns false if no post-processing script was defined. // Returns false if no post-processing script was defined.
@ -285,10 +280,10 @@ bool run_post_process_scripts(std::string &src_path, bool make_copy, const std::
throw Slic3r::RuntimeError(msg); throw Slic3r::RuntimeError(msg);
} }
if (! boost::filesystem::exists(gcode_file)) { if (! boost::filesystem::exists(gcode_file)) {
const std::string msg = (boost::format(_(L( const std::string msg = (boost::format(_u8L(
"Post-processing script %1% failed.\n\n" "Post-processing script %1% failed.\n\n"
"The post-processing script is expected to change the G-code file %2% in place, but the G-code file was deleted and likely saved under a new name.\n" "The post-processing script is expected to change the G-code file %2% in place, but the G-code file was deleted and likely saved under a new name.\n"
"Please adjust the post-processing script to change the G-code in place and consult the manual on how to optionally rename the post-processed G-code file.\n"))) "Please adjust the post-processing script to change the G-code in place and consult the manual on how to optionally rename the post-processed G-code file.\n"))
% script % path).str(); % script % path).str();
BOOST_LOG_TRIVIAL(error) << msg; BOOST_LOG_TRIVIAL(error) << msg;
throw Slic3r::RuntimeError(msg); throw Slic3r::RuntimeError(msg);

View File

@ -4,12 +4,17 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <numeric> #include <numeric>
#include <memory>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include "ClipperUtils.hpp"
#include "GCodeProcessor.hpp" #include "GCodeProcessor.hpp"
#include "BoundingBox.hpp" #include "BoundingBox.hpp"
#include "LocalesUtils.hpp" #include "LocalesUtils.hpp"
#include "Geometry.hpp"
#include "Surface.hpp"
#include "Fill/FillRectilinear.hpp"
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
@ -88,9 +93,12 @@ public:
} }
WipeTowerWriter& disable_linear_advance() { WipeTowerWriter& disable_linear_advance() {
m_gcode += (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware)
? (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n") m_gcode += (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n");
: std::string("M900 K0\n")); else if (m_gcode_flavor == gcfKlipper)
m_gcode += "SET_PRESSURE_ADVANCE ADVANCE=0\n";
else
m_gcode += "M900 K0\n";
return *this; return *this;
} }
@ -358,6 +366,8 @@ public:
// Set digital trimpot motor // Set digital trimpot motor
WipeTowerWriter& set_extruder_trimpot(int current) WipeTowerWriter& set_extruder_trimpot(int current)
{ {
if (m_gcode_flavor == gcfKlipper)
return *this;
if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware) if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware)
m_gcode += "M906 E"; m_gcode += "M906 E";
else else
@ -512,6 +522,8 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
m_wipe_tower_width(float(config.wipe_tower_width)), m_wipe_tower_width(float(config.wipe_tower_width)),
m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)), m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)),
m_wipe_tower_brim_width(float(config.wipe_tower_brim_width)), m_wipe_tower_brim_width(float(config.wipe_tower_brim_width)),
m_wipe_tower_cone_angle(float(config.wipe_tower_cone_angle)),
m_extra_spacing(float(config.wipe_tower_extra_spacing/100.)),
m_y_shift(0.f), m_y_shift(0.f),
m_z_pos(0.f), m_z_pos(0.f),
m_bridging(float(config.wipe_tower_bridging)), m_bridging(float(config.wipe_tower_bridging)),
@ -1169,45 +1181,171 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
";------------------\n\n\n\n\n\n\n"); ";------------------\n\n\n\n\n\n\n");
} }
// outer perimeter (always): const float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4);
writer.rectangle(wt_box, feedrate);
// This block creates the stabilization cone.
// First define a lambda to draw the rectangle with stabilization.
auto supported_rectangle = [this, &writer, spacing](const box_coordinates& wt_box, double feedrate, bool infill_cone) -> Polygon {
const auto [R, support_scale] = get_wipe_tower_cone_base(m_wipe_tower_width, m_wipe_tower_height, m_wipe_tower_depth, m_wipe_tower_cone_angle);
double z = m_no_sparse_layers ? (m_current_height + m_layer_info->height) : m_layer_info->z; // the former should actually work in both cases, but let's stay on the safe side (the 2.6.0 is close)
double r = std::tan(Geometry::deg2rad(m_wipe_tower_cone_angle/2.f)) * (m_wipe_tower_height - z);
Vec2f center = (wt_box.lu + wt_box.rd) / 2.;
double w = wt_box.lu.y() - wt_box.ld.y();
enum Type {
Arc,
Corner,
ArcStart,
ArcEnd
};
// First generate vector of annotated point which form the boundary.
std::vector<std::pair<Vec2f, Type>> pts = {{wt_box.ru, Corner}};
if (double alpha_start = std::asin((0.5*w)/r); ! std::isnan(alpha_start) && r > 0.5*w+0.01) {
for (double alpha = alpha_start; alpha < M_PI-alpha_start+0.001; alpha+=(M_PI-2*alpha_start) / 20.)
pts.emplace_back(Vec2f(center.x() + r*std::cos(alpha)/support_scale, center.y() + r*std::sin(alpha)), alpha == alpha_start ? ArcStart : Arc);
pts.back().second = ArcEnd;
}
pts.emplace_back(wt_box.lu, Corner);
pts.emplace_back(wt_box.ld, Corner);
for (int i=int(pts.size())-3; i>0; --i)
pts.emplace_back(Vec2f(pts[i].first.x(), 2*center.y()-pts[i].first.y()), i == int(pts.size())-3 ? ArcStart : i == 1 ? ArcEnd : Arc);
pts.emplace_back(wt_box.rd, Corner);
// Create a Polygon from the points.
Polygon poly;
for (const auto& [pt, tag] : pts)
poly.points.push_back(Point::new_scale(pt));
// Prepare polygons to be filled by infill.
Polylines polylines;
if (infill_cone && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing) {
ExPolygons infill_areas;
ExPolygon wt_contour(poly);
Polygon wt_rectangle(Points{Point::new_scale(wt_box.ld), Point::new_scale(wt_box.rd), Point::new_scale(wt_box.ru), Point::new_scale(wt_box.lu)});
wt_rectangle = offset(wt_rectangle, scale_(-spacing/2.)).front();
wt_contour = offset_ex(wt_contour, scale_(-spacing/2.)).front();
infill_areas = diff_ex(wt_contour, wt_rectangle);
if (infill_areas.size() == 2) {
ExPolygon& bottom_expoly = infill_areas.front().contour.points.front().y() < infill_areas.back().contour.points.front().y() ? infill_areas[0] : infill_areas[1];
std::unique_ptr<Fill> filler(Fill::new_from_type(ipMonotonicLines));
filler->angle = Geometry::deg2rad(45.f);
filler->spacing = spacing;
FillParams params;
params.density = 1.f;
Surface surface(stBottom, bottom_expoly);
filler->bounding_box = get_extents(bottom_expoly);
polylines = filler->fill_surface(&surface, params);
if (! polylines.empty()) {
if (polylines.front().points.front().x() > polylines.back().points.back().x()) {
std::reverse(polylines.begin(), polylines.end());
for (Polyline& p : polylines)
p.reverse();
}
}
}
}
// Find the closest corner and travel to it.
int start_i = 0;
double min_dist = std::numeric_limits<double>::max();
for (int i=0; i<int(pts.size()); ++i) {
if (pts[i].second == Corner) {
double dist = (pts[i].first - Vec2f(writer.x(), writer.y())).squaredNorm();
if (dist < min_dist) {
min_dist = dist;
start_i = i;
}
}
}
writer.travel(pts[start_i].first);
// Now actually extrude the boundary (and possibly infill):
int i = start_i+1 == int(pts.size()) ? 0 : start_i + 1;
while (i != start_i) {
writer.extrude(pts[i].first, feedrate);
if (pts[i].second == ArcEnd) {
// Extrude the infill.
if (! polylines.empty()) {
// Extrude the infill and travel back to where we were.
bool mirror = ((pts[i].first.y() - center.y()) * (unscale(polylines.front().points.front()).y() - center.y())) < 0.;
for (const Polyline& line : polylines) {
writer.travel(center - (mirror ? 1.f : -1.f) * (unscale(line.points.front()).cast<float>() - center));
for (size_t i=0; i<line.points.size(); ++i)
writer.extrude(center - (mirror ? 1.f : -1.f) * (unscale(line.points[i]).cast<float>() - center));
}
writer.travel(pts[i].first);
}
}
if (++i == int(pts.size()))
i = 0;
}
writer.extrude(pts[start_i].first, feedrate);
return poly;
};
// outer contour (always)
bool infill_cone = first_layer && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing;
Polygon poly = supported_rectangle(wt_box, feedrate, infill_cone);
// brim (first layer only) // brim (first layer only)
if (first_layer) { if (first_layer) {
box_coordinates box = wt_box; box_coordinates box = wt_box;
float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4);
// How many perimeters shall the brim have?
size_t loops_num = (m_wipe_tower_brim_width + spacing/2.f) / spacing; size_t loops_num = (m_wipe_tower_brim_width + spacing/2.f) / spacing;
for (size_t i = 0; i < loops_num; ++ i) { for (size_t i = 0; i < loops_num; ++ i) {
box.expand(spacing); poly = offset(poly, scale_(spacing)).front();
writer.rectangle(box); int cp = poly.closest_point_index(Point::new_scale(writer.x(), writer.y()));
writer.travel(unscale(poly.points[cp]).cast<float>());
for (int i=cp+1; true; ++i ) {
if (i==int(poly.points.size()))
i = 0;
writer.extrude(unscale(poly.points[i]).cast<float>());
if (i == cp)
break;
}
} }
// Save actual brim width to be later passed to the Print object, which will use it // Save actual brim width to be later passed to the Print object, which will use it
// for skirt calculation and pass it to GLCanvas for precise preview box // for skirt calculation and pass it to GLCanvas for precise preview box
m_wipe_tower_brim_width_real = wt_box.ld.x() - box.ld.x() + spacing/2.f; m_wipe_tower_brim_width_real = loops_num * spacing;
wt_box = box;
} }
// Now prepare future wipe. box contains rectangle that was extruded last (ccw). // Now prepare future wipe.
Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : int i = poly.closest_point_index(Point::new_scale(writer.x(), writer.y()));
(writer.pos() == wt_box.rd ? wt_box.ru : writer.add_wipe_point(writer.pos());
(writer.pos() == wt_box.ru ? wt_box.lu : writer.add_wipe_point(unscale(poly.points[i==0 ? int(poly.points.size())-1 : i-1]).cast<float>());
wt_box.ld)));
writer.add_wipe_point(writer.pos())
.add_wipe_point(target);
// Ask our writer about how much material was consumed. // Ask our writer about how much material was consumed.
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled. // Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
if (! m_no_sparse_layers || toolchanges_on_layer || first_layer) if (! m_no_sparse_layers || toolchanges_on_layer || first_layer) {
if (m_current_tool < m_used_filament_length.size()) if (m_current_tool < m_used_filament_length.size())
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
m_current_height += m_layer_info->height;
}
return construct_tcr(writer, false, old_tool); return construct_tcr(writer, false, old_tool);
} }
// Static method to get the radius and x-scaling of the stabilizing cone base.
std::pair<double, double> WipeTower::get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg)
{
double R = std::tan(Geometry::deg2rad(angle_deg/2.)) * height;
double fake_width = 0.66 * width;
double diag = std::hypot(fake_width / 2., depth / 2.);
double support_scale = 1.;
if (R > diag) {
double w = fake_width;
double sin = 0.5 * depth / diag;
double tan = depth / w;
double t = (R - diag) * sin;
support_scale = (w / 2. + t / tan + t * tan) / (w / 2.);
}
return std::make_pair(R, support_scale);
}
// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box // Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box
void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool,
unsigned int new_tool, float wipe_volume) unsigned int new_tool, float wipe_volume)
@ -1250,6 +1388,8 @@ void WipeTower::plan_tower()
m_wipe_tower_depth = 0.f; m_wipe_tower_depth = 0.f;
for (auto& layer : m_plan) for (auto& layer : m_plan)
layer.depth = 0.f; layer.depth = 0.f;
m_wipe_tower_height = m_plan.empty() ? 0.f : m_plan.back().z;
m_current_height = 0.f;
for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index) for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index)
{ {
@ -1334,8 +1474,6 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
if (m_plan.empty()) if (m_plan.empty())
return; return;
m_extra_spacing = 1.f;
plan_tower(); plan_tower();
for (int i=0;i<5;++i) { for (int i=0;i<5;++i) {
save_on_last_wipe(); save_on_last_wipe();
@ -1343,6 +1481,7 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
} }
m_layer_info = m_plan.begin(); m_layer_info = m_plan.begin();
m_current_height = 0.f;
// we don't know which extruder to start with - we'll set it according to the first toolchange // we don't know which extruder to start with - we'll set it according to the first toolchange
for (const auto& layer : m_plan) { for (const auto& layer : m_plan) {
@ -1358,7 +1497,7 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
m_old_temperature = -1; // reset last temperature written in the gcode m_old_temperature = -1; // reset last temperature written in the gcode
std::vector<WipeTower::ToolChangeResult> layer_result; std::vector<WipeTower::ToolChangeResult> layer_result;
for (auto layer : m_plan) for (const WipeTower::WipeTowerInfo& layer : m_plan)
{ {
set_layer(layer.z, layer.height, 0, false/*layer.z == m_plan.front().z*/, layer.z == m_plan.back().z); set_layer(layer.z, layer.height, 0, false/*layer.z == m_plan.front().z*/, layer.z == m_plan.back().z);
m_internal_rotation += 180.f; m_internal_rotation += 180.f;

View File

@ -23,6 +23,8 @@ class WipeTower
public: public:
static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; } static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }
static std::pair<double, double> get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg);
struct Extrusion struct Extrusion
{ {
Extrusion(const Vec2f &pos, float width, unsigned int tool) : pos(pos), width(width), tool(tool) {} Extrusion(const Vec2f &pos, float width, unsigned int tool) : pos(pos), width(width), tool(tool) {}
@ -142,6 +144,7 @@ public:
float get_depth() const { return m_wipe_tower_depth; } float get_depth() const { return m_wipe_tower_depth; }
float get_brim_width() const { return m_wipe_tower_brim_width_real; } float get_brim_width() const { return m_wipe_tower_brim_width_real; }
float get_wipe_tower_height() const { return m_wipe_tower_height; }
@ -253,6 +256,8 @@ private:
Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm. Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm.
float m_wipe_tower_width; // Width of the wipe tower. float m_wipe_tower_width; // Width of the wipe tower.
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
float m_wipe_tower_height = 0.f;
float m_wipe_tower_cone_angle = 0.f;
float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) from config float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) from config
float m_wipe_tower_brim_width_real = 0.f; // Width of brim (mm) after generation float m_wipe_tower_brim_width_real = 0.f; // Width of brim (mm) after generation
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis) float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
@ -359,6 +364,10 @@ private:
std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...)) std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...))
std::vector<WipeTowerInfo>::iterator m_layer_info = m_plan.end(); std::vector<WipeTowerInfo>::iterator m_layer_info = m_plan.end();
// This sums height of all extruded layers, not counting the layers which
// will be later removed when the "no_sparse_layers" is used.
float m_current_height = 0.f;
// Stores information about used filament length per extruder: // Stores information about used filament length per extruder:
std::vector<float> m_used_filament_length; std::vector<float> m_used_filament_length;

View File

@ -15,6 +15,12 @@
namespace Slic3r { namespace Slic3r {
// static
bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor)
{
return (flavor == gcfRepetier || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware);
}
void GCodeWriter::apply_print_config(const PrintConfig &print_config) void GCodeWriter::apply_print_config(const PrintConfig &print_config)
{ {
this->config.apply(print_config, true); this->config.apply(print_config, true);
@ -25,6 +31,8 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|| print_config.gcode_flavor.value == gcfRepRapFirmware; || print_config.gcode_flavor.value == gcfRepRapFirmware;
m_max_acceleration = static_cast<unsigned int>(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) ? m_max_acceleration = static_cast<unsigned int>(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) ?
print_config.machine_max_acceleration_extruding.values.front() : 0)); print_config.machine_max_acceleration_extruding.values.front() : 0));
m_max_travel_acceleration = static_cast<unsigned int>(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode && supports_separate_travel_acceleration(print_config.gcode_flavor.value)) ?
print_config.machine_max_acceleration_travel.values.front() : 0));
} }
void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids) void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
@ -53,6 +61,7 @@ std::string GCodeWriter::preamble()
FLAVOR_IS(gcfRepRapFirmware) || FLAVOR_IS(gcfRepRapFirmware) ||
FLAVOR_IS(gcfMarlinLegacy) || FLAVOR_IS(gcfMarlinLegacy) ||
FLAVOR_IS(gcfMarlinFirmware) || FLAVOR_IS(gcfMarlinFirmware) ||
FLAVOR_IS(gcfKlipper) ||
FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfTeacup) ||
FLAVOR_IS(gcfRepetier) || FLAVOR_IS(gcfRepetier) ||
FLAVOR_IS(gcfSmoothie)) FLAVOR_IS(gcfSmoothie))
@ -154,36 +163,31 @@ std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait
return gcode.str(); return gcode.str();
} }
std::string GCodeWriter::set_acceleration(unsigned int acceleration) std::string GCodeWriter::set_acceleration_internal(Acceleration type, unsigned int acceleration)
{ {
// Clamp the acceleration to the allowed maximum. // Clamp the acceleration to the allowed maximum.
if (m_max_acceleration > 0 && acceleration > m_max_acceleration) if (type == Acceleration::Print && m_max_acceleration > 0 && acceleration > m_max_acceleration)
acceleration = m_max_acceleration; acceleration = m_max_acceleration;
if (type == Acceleration::Travel && m_max_travel_acceleration > 0 && acceleration > m_max_travel_acceleration)
acceleration = m_max_travel_acceleration;
if (acceleration == 0 || acceleration == m_last_acceleration) // Are we setting travel acceleration for a flavour that supports separate travel and print acc?
bool separate_travel = (type == Acceleration::Travel && supports_separate_travel_acceleration(this->config.gcode_flavor));
auto& last_value = separate_travel ? m_last_travel_acceleration : m_last_acceleration ;
if (acceleration == 0 || acceleration == last_value)
return std::string(); return std::string();
m_last_acceleration = acceleration; last_value = acceleration;
std::ostringstream gcode; std::ostringstream gcode;
if (FLAVOR_IS(gcfRepetier)) { if (FLAVOR_IS(gcfRepetier))
// M201: Set max printing acceleration gcode << (separate_travel ? "M202 X" : "M201 X") << acceleration << " Y" << acceleration;
gcode << "M201 X" << acceleration << " Y" << acceleration; else if (FLAVOR_IS(gcfRepRapFirmware) || FLAVOR_IS(gcfMarlinFirmware))
if (this->config.gcode_comments) gcode << " ; adjust acceleration"; gcode << (separate_travel ? "M204 T" : "M204 P") << acceleration;
gcode << "\n"; else
// M202: Set max travel acceleration
gcode << "M202 X" << acceleration << " Y" << acceleration;
} else if (FLAVOR_IS(gcfRepRapFirmware)) {
// M204: Set default acceleration
gcode << "M204 P" << acceleration;
} else if (FLAVOR_IS(gcfMarlinFirmware)) {
// This is new MarlinFirmware with separated print/retraction/travel acceleration.
// Use M204 P, we don't want to override travel acc by M204 S (which is deprecated anyway).
gcode << "M204 P" << acceleration;
} else {
// M204: Set default acceleration
gcode << "M204 S" << acceleration; gcode << "M204 S" << acceleration;
}
if (this->config.gcode_comments) gcode << " ; adjust acceleration"; if (this->config.gcode_comments) gcode << " ; adjust acceleration";
gcode << "\n"; gcode << "\n";
@ -482,6 +486,20 @@ std::string GCodeWriter::unlift()
return gcode; return gcode;
} }
void GCodeWriter::update_position(const Vec3d &new_pos)
{
assert(this->m_lifted >= 0);
const double nominal_z = m_pos.z() - m_lifted;
m_lifted = new_pos.z() - nominal_z;
if (m_lifted < - EPSILON)
throw Slic3r::RuntimeError("Custom G-code reports negative Z-hop. Final Z position is below the print_z height.");
// In case that retract_lift == layer_height we could end up with almost zero in_m_lifted
// and a retract could be skipped (https://github.com/prusa3d/PrusaSlicer/issues/2154
if (m_lifted < EPSILON)
m_lifted = 0.;
m_pos = new_pos;
}
std::string GCodeWriter::set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed) std::string GCodeWriter::set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed)
{ {
std::ostringstream gcode; std::ostringstream gcode;

View File

@ -43,7 +43,8 @@ public:
std::string postamble() const; std::string postamble() const;
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const; std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const;
std::string set_bed_temperature(unsigned int temperature, bool wait = false); std::string set_bed_temperature(unsigned int temperature, bool wait = false);
std::string set_acceleration(unsigned int acceleration); std::string set_print_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Print, acceleration); }
std::string set_travel_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Travel, acceleration); }
std::string reset_e(bool force = false); std::string reset_e(bool force = false);
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const; std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const;
// return false if this extruder was already selected // return false if this extruder was already selected
@ -67,7 +68,21 @@ public:
std::string unretract(); std::string unretract();
std::string lift(); std::string lift();
std::string unlift(); std::string unlift();
// Current position of the printer, in G-code coordinates.
// Z coordinate of current position contains zhop. If zhop is applied (this->zhop() > 0),
// then the print_z = this->get_position().z() - this->zhop().
Vec3d get_position() const { return m_pos; } Vec3d get_position() const { return m_pos; }
// Current Z hop value.
double get_zhop() const { return m_lifted; }
// Update position of the print head based on the final position returned by a custom G-code block.
// The new position Z coordinate contains the Z-hop.
// GCodeWriter expects the custom script to NOT change print_z, only Z-hop, thus the print_z is maintained
// by this function while the current Z-hop accumulator is updated.
void update_position(const Vec3d &new_pos);
// Returns whether this flavor supports separate print and travel acceleration.
static bool supports_separate_travel_acceleration(GCodeFlavor flavor);
// To be called by the CoolingBuffer from another thread. // To be called by the CoolingBuffer from another thread.
static std::string set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed); static std::string set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed);
@ -81,17 +96,26 @@ private:
std::string m_extrusion_axis; std::string m_extrusion_axis;
bool m_single_extruder_multi_material; bool m_single_extruder_multi_material;
Extruder* m_extruder; Extruder* m_extruder;
unsigned int m_last_acceleration; unsigned int m_last_acceleration = (unsigned int)(-1);
unsigned int m_last_travel_acceleration = (unsigned int)(-1); // only used for flavors supporting separate print/travel acc
// Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware. // Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware.
// If set to zero, the limit is not in action. // If set to zero, the limit is not in action.
unsigned int m_max_acceleration; unsigned int m_max_acceleration;
unsigned int m_max_travel_acceleration;
unsigned int m_last_bed_temperature; unsigned int m_last_bed_temperature;
bool m_last_bed_temperature_reached; bool m_last_bed_temperature_reached;
double m_lifted; double m_lifted;
Vec3d m_pos = Vec3d::Zero(); Vec3d m_pos = Vec3d::Zero();
enum class Acceleration {
Travel,
Print
};
std::string _travel_to_z(double z, const std::string &comment); std::string _travel_to_z(double z, const std::string &comment);
std::string _retract(double length, double restart_extra, const std::string &comment); std::string _retract(double length, double restart_extra, const std::string &comment);
std::string set_acceleration_internal(Acceleration type, unsigned int acceleration);
}; };
class GCodeFormatter { class GCodeFormatter {

View File

@ -128,7 +128,7 @@ inline static Linef make_linef(const VD::edge_type &edge)
return {Vec2d(v0->x(), v0->y()), Vec2d(v1->x(), v1->y())}; return {Vec2d(v0->x(), v0->y()), Vec2d(v1->x(), v1->y())};
} }
inline static bool is_equal(const VD::vertex_type &first, const VD::vertex_type &second) { return first.x() == second.x() && first.y() == second.y(); } [[maybe_unused]] inline static bool is_equal(const VD::vertex_type &first, const VD::vertex_type &second) { return first.x() == second.x() && first.y() == second.y(); }
// FIXME Lukas H.: Also includes parabolic segments. // FIXME Lukas H.: Also includes parabolic segments.
bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_diagram) bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_diagram)

View File

@ -3,6 +3,12 @@
#include <string> #include <string>
#ifdef SLIC3R_CURRENTLY_COMPILING_GUI_MODULE
#ifndef SLIC3R_ALLOW_LIBSLIC3R_I18N_IN_SLIC3R
#error You included libslic3r/I18N.hpp into a file belonging to slic3r module.
#endif
#endif
namespace Slic3r { namespace Slic3r {
namespace I18N { namespace I18N {
@ -15,4 +21,17 @@ namespace I18N {
} // namespace Slic3r } // namespace Slic3r
// When this is included from slic3r, better do not define the translation functions.
// Macros from slic3r/GUI/I18N.hpp should be used there.
#ifndef SLIC3R_CURRENTLY_COMPILING_GUI_MODULE
#ifdef L
#error L macro is defined where it shouldn't be. Didn't you include slic3r/GUI/I18N.hpp in libslic3r by mistake?
#endif
namespace {
[[maybe_unused]] const char* L(const char* s) { return s; }
[[maybe_unused]] const char* L_CONTEXT(const char* s, const char* context) { return s; }
[[maybe_unused]] std::string _u8L(const char* s) { return Slic3r::I18N::translate(s); }
}
#endif
#endif /* slic3r_I18N_hpp_ */ #endif /* slic3r_I18N_hpp_ */

View File

@ -1,11 +1,14 @@
#include "Layer.hpp" #include "Layer.hpp"
#include "ClipperZUtils.hpp" #include "ClipperZUtils.hpp"
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
#include "Point.hpp"
#include "Polygon.hpp"
#include "Print.hpp" #include "Print.hpp"
#include "Fill/Fill.hpp" #include "Fill/Fill.hpp"
#include "ShortestPath.hpp" #include "ShortestPath.hpp"
#include "SVG.hpp" #include "SVG.hpp"
#include "BoundingBox.hpp" #include "BoundingBox.hpp"
#include "clipper/clipper.hpp"
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
@ -180,6 +183,31 @@ static void connect_layer_slices(
break; break;
} }
} }
if (!found) {
// The check above might sometimes fail when the polygons overlap only on points, which causes the clipper to detect no intersection.
// The problem happens rarely, mostly on simple polygons (in terms of number of points), but regardless of size!
// example of failing link on two layers, each with single polygon without holes.
// layer A = Polygon{(-24931238,-11153865),(-22504249,-8726874),(-22504249,11477151),(-23261469,12235585),(-23752371,12727276),(-25002495,12727276),(-27502745,10227026),(-27502745,-12727274),(-26504645,-12727274)}
// layer B = Polygon{(-24877897,-11100524),(-22504249,-8726874),(-22504249,11477151),(-23244827,12218916),(-23752371,12727276),(-25002495,12727276),(-27502745,10227026),(-27502745,-12727274),(-26504645,-12727274)}
// note that first point is not identical, and the check above picks (-24877897,-11100524) as the first contour point (polynode.Contour.front()).
// that point is sadly slightly outisde of the layer A, so no link is detected, eventhough they are overlaping "completely"
Polygon contour_poly;
for (const auto& p : polynode.Contour) {
contour_poly.points.emplace_back(p.x(), p.y());
}
BoundingBox contour_aabb{contour_poly.points};
for (int l = int(m_above.lslices_ex.size()) - 1; l >= 0; --l) {
LayerSlice &lslice = m_above.lslices_ex[l];
// it is potentially slow, but should be executed rarely
if (contour_aabb.overlap(lslice.bbox) && !intersection(Polygons{contour_poly}, m_above.lslices[l]).empty()) {
found = true;
j = l;
assert(i >= 0 && i < m_below.lslices_ex.size());
assert(j >= 0 && j < m_above.lslices_ex.size());
break;
}
}
}
} else { } else {
// Index of an island above. Look-it up in the island below. // Index of an island above. Look-it up in the island below.
assert(j < m_offset_end); assert(j < m_offset_end);
@ -194,6 +222,23 @@ static void connect_layer_slices(
break; break;
} }
} }
if (!found) { // Explanation for aditional check is above.
Polygon contour_poly;
for (const auto &p : polynode.Contour) {
contour_poly.points.emplace_back(p.x(), p.y());
}
BoundingBox contour_aabb{contour_poly.points};
for (int l = int(m_below.lslices_ex.size()) - 1; l >= 0; --l) {
LayerSlice &lslice = m_below.lslices_ex[l];
if (contour_aabb.overlap(lslice.bbox) && !intersection(Polygons{contour_poly}, m_below.lslices[l]).empty()) {
found = true;
i = l;
assert(i >= 0 && i < m_below.lslices_ex.size());
assert(j >= 0 && j < m_above.lslices_ex.size());
break;
}
}
}
} }
} else { } else {
assert(assert_intersection_valid(i, j)); assert(assert_intersection_valid(i, j));

View File

@ -368,8 +368,12 @@ public:
void make_perimeters(); void make_perimeters();
// Phony version of make_fills() without parameters for Perl integration only. // Phony version of make_fills() without parameters for Perl integration only.
void make_fills() { this->make_fills(nullptr, nullptr, nullptr); } void make_fills() { this->make_fills(nullptr, nullptr, nullptr); }
void make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator); void make_fills(FillAdaptive::Octree *adaptive_fill_octree,
Polylines generate_sparse_infill_polylines_for_anchoring() const; FillAdaptive::Octree *support_fill_octree,
FillLightning::Generator *lightning_generator);
Polylines generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree *adaptive_fill_octree,
FillAdaptive::Octree *support_fill_octree,
FillLightning::Generator* lightning_generator) const;
void make_ironing(); void make_ironing();
void export_region_slices_to_svg(const char *path) const; void export_region_slices_to_svg(const char *path) const;

View File

@ -291,22 +291,24 @@ Surfaces expand_bridges_detect_orientations(
uint32_t src_id = it->src_id; uint32_t src_id = it->src_id;
for (++ it; it != bridge_expansions.end() && it->src_id == src_id; ++ it) ; for (++ it; it != bridge_expansions.end() && it->src_id == src_id; ++ it) ;
} }
for (uint32_t bridge_id = 0; bridge_id < uint32_t(bridges.size()); ++ bridge_id) { for (uint32_t bridge_id = 0; bridge_id < uint32_t(bridges.size()); ++ bridge_id)
acc.clear(); if (group_id(bridge_id) == bridge_id) {
for (uint32_t bridge_id2 = bridge_id; bridge_id2 < uint32_t(bridges.size()); ++ bridge_id2) // Head of the group.
if (group_id(bridge_id) == bridge_id) { acc.clear();
append(acc, to_polygons(std::move(bridges[bridge_id2].expolygon))); for (uint32_t bridge_id2 = bridge_id; bridge_id2 < uint32_t(bridges.size()); ++ bridge_id2)
auto it_bridge_expansion = bridges[bridge_id2].bridge_expansion_begin; if (group_id(bridge_id2) == bridge_id) {
assert(it_bridge_expansion == bridge_expansions.end() || it_bridge_expansion->src_id == bridge_id2); append(acc, to_polygons(std::move(bridges[bridge_id2].expolygon)));
for (; it_bridge_expansion != bridge_expansions.end() && it_bridge_expansion->src_id == bridge_id2; ++ it_bridge_expansion) auto it_bridge_expansion = bridges[bridge_id2].bridge_expansion_begin;
append(acc, to_polygons(std::move(it_bridge_expansion->expolygon))); assert(it_bridge_expansion == bridge_expansions.end() || it_bridge_expansion->src_id == bridge_id2);
} for (; it_bridge_expansion != bridge_expansions.end() && it_bridge_expansion->src_id == bridge_id2; ++ it_bridge_expansion)
//FIXME try to be smart and pick the best bridging angle for all? append(acc, to_polygons(std::move(it_bridge_expansion->expolygon)));
templ.bridge_angle = bridges[bridge_id].angle; }
// without safety offset, artifacts are generated (GH #2494) //FIXME try to be smart and pick the best bridging angle for all?
for (ExPolygon &ex : union_safety_offset_ex(acc)) templ.bridge_angle = bridges[bridge_id].angle;
out.emplace_back(templ, std::move(ex)); // without safety offset, artifacts are generated (GH #2494)
} for (ExPolygon &ex : union_safety_offset_ex(acc))
out.emplace_back(templ, std::move(ex));
}
} }
// Clip the shells by the expanded bridges. // Clip the shells by the expanded bridges.
@ -378,7 +380,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
const double custom_angle = this->region().config().bridge_angle.value; const double custom_angle = this->region().config().bridge_angle.value;
const auto params = Algorithm::RegionExpansionParameters::build(expansion_bottom_bridge, expansion_step, max_nr_expansion_steps); const auto params = Algorithm::RegionExpansionParameters::build(expansion_bottom_bridge, expansion_step, max_nr_expansion_steps);
bridges.surfaces = custom_angle > 0 ? bridges.surfaces = custom_angle > 0 ?
expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, shells, params, custom_angle) : expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, shells, params, Geometry::deg2rad(custom_angle)) :
expand_bridges_detect_orientations(m_fill_surfaces.surfaces, shells, params); expand_bridges_detect_orientations(m_fill_surfaces.surfaces, shells, params);
BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges - done"; BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges - done";
#if 0 #if 0
@ -725,7 +727,7 @@ void LayerRegion::prepare_fill_surfaces()
if (! spiral_vase && this->region().config().top_solid_layers == 0) { if (! spiral_vase && this->region().config().top_solid_layers == 0) {
for (Surface &surface : m_fill_surfaces) for (Surface &surface : m_fill_surfaces)
if (surface.is_top()) if (surface.is_top())
surface.surface_type = this->layer()->object()->config().infill_only_where_needed && this->region().config().fill_pattern != ipLightning ? stInternalVoid : stInternal; surface.surface_type = /*this->layer()->object()->config().infill_only_where_needed && this->region().config().fill_pattern != ipLightning ? stInternalVoid :*/ stInternal;
} }
if (this->region().config().bottom_solid_layers == 0) { if (this->region().config().bottom_solid_layers == 0) {
for (Surface &surface : m_fill_surfaces) for (Surface &surface : m_fill_surfaces)

View File

@ -1389,6 +1389,25 @@ void ModelObject::clone_for_cut(ModelObject** obj)
(*obj)->input_file.clear(); (*obj)->input_file.clear();
} }
bool ModelVolume::is_the_only_one_part() const
{
if (m_type != ModelVolumeType::MODEL_PART)
return false;
if (object == nullptr)
return false;
for (const ModelVolume *v : object->volumes) {
if (v == nullptr)
continue;
// is this volume?
if (v->id() == this->id())
continue;
// exist another model part in object?
if (v->type() == ModelVolumeType::MODEL_PART)
return false;
}
return true;
}
void ModelVolume::reset_extra_facets() void ModelVolume::reset_extra_facets()
{ {
this->supported_facets.reset(); this->supported_facets.reset();

View File

@ -835,6 +835,7 @@ public:
bool is_support_blocker() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER; } bool is_support_blocker() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER; }
bool is_support_modifier() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER || m_type == ModelVolumeType::SUPPORT_ENFORCER; } bool is_support_modifier() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER || m_type == ModelVolumeType::SUPPORT_ENFORCER; }
bool is_text() const { return text_configuration.has_value(); } bool is_text() const { return text_configuration.has_value(); }
bool is_the_only_one_part() const; // behave like an object
t_model_material_id material_id() const { return m_material_id; } t_model_material_id material_id() const { return m_material_id; }
void reset_extra_facets(); void reset_extra_facets();
void apply_tolerance(); void apply_tolerance();

View File

@ -1019,13 +1019,23 @@ std::tuple<std::vector<ExtrusionPaths>, Polygons> generate_extra_perimeters_over
overhang_region.end()); overhang_region.end());
if (!overhang_region.empty()) { if (!overhang_region.empty()) {
// there is a special case, where the first (or last) generated overhang perimeter eats all anchor space.
// When this happens, the first overhang perimeter is also a closed loop, and needs special check
// instead of the following simple is_anchored lambda, which checks only the first and last point (not very useful on closed
// polyline)
bool first_overhang_is_closed_and_anchored =
(overhang_region.front().first_point() == overhang_region.front().last_point() &&
!intersection_pl(overhang_region.front().polyline, optimized_lower_slices).empty());
auto is_anchored = [&lower_layer_aabb_tree](const ExtrusionPath &path) { auto is_anchored = [&lower_layer_aabb_tree](const ExtrusionPath &path) {
return lower_layer_aabb_tree.distance_from_lines<true>(path.first_point()) <= 0 || return lower_layer_aabb_tree.distance_from_lines<true>(path.first_point()) <= 0 ||
lower_layer_aabb_tree.distance_from_lines<true>(path.last_point()) <= 0; lower_layer_aabb_tree.distance_from_lines<true>(path.last_point()) <= 0;
}; };
std::reverse(overhang_region.begin(), overhang_region.end()); if (!first_overhang_is_closed_and_anchored) {
auto first_unanchored = std::stable_partition(overhang_region.begin(), overhang_region.end(), is_anchored); std::reverse(overhang_region.begin(), overhang_region.end());
int index_of_first_unanchored = first_unanchored - overhang_region.begin(); }
auto first_unanchored = std::stable_partition(overhang_region.begin(), overhang_region.end(), is_anchored);
int index_of_first_unanchored = first_unanchored - overhang_region.begin();
overhang_region = sort_extra_perimeters(overhang_region, index_of_first_unanchored, overhang_flow.scaled_spacing()); overhang_region = sort_extra_perimeters(overhang_region, index_of_first_unanchored, overhang_flow.scaled_spacing());
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,10 @@ public:
// In the future, the context may hold variables created and modified by the PlaceholderParser // In the future, the context may hold variables created and modified by the PlaceholderParser
// and shared between the PlaceholderParser::process() invocations. // and shared between the PlaceholderParser::process() invocations.
struct ContextData { struct ContextData {
std::mt19937 rng; std::mt19937 rng;
// If defined, then this dictionary is used by the scripts to define user variables and persist them
// between PlaceholderParser evaluations.
std::unique_ptr<DynamicConfig> global_config;
}; };
PlaceholderParser(const DynamicConfig *external_config = nullptr); PlaceholderParser(const DynamicConfig *external_config = nullptr);
@ -55,8 +58,10 @@ public:
// Fill in the template using a macro processing language. // Fill in the template using a macro processing language.
// Throws Slic3r::PlaceholderParserError on syntax or runtime error. // Throws Slic3r::PlaceholderParserError on syntax or runtime error.
std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr, ContextData *context = nullptr) const; std::string process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override, DynamicConfig *config_outputs, ContextData *context) const;
std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr, ContextData *context = nullptr) const
{ return this->process(templ, current_extruder_id, config_override, nullptr /* config_outputs */, context); }
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax. // Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
// Throws Slic3r::PlaceholderParserError on syntax or runtime error. // Throws Slic3r::PlaceholderParserError on syntax or runtime error.
static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr); static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr);

View File

@ -3,6 +3,7 @@
#include "Exception.hpp" #include "Exception.hpp"
#include "Preset.hpp" #include "Preset.hpp"
#include "AppConfig.hpp" #include "AppConfig.hpp"
#include "I18N.hpp"
#ifdef _MSC_VER #ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
@ -10,15 +11,6 @@
#include <Windows.h> #include <Windows.h>
#endif /* _MSC_VER */ #endif /* _MSC_VER */
// instead of #include "slic3r/GUI/I18N.hpp" :
#ifndef L
// !!! If you needed to translate some string,
// !!! please use _L(string)
// !!! _() - is a standard wxWidgets macro to translate
// !!! L() is used only for marking localizable string
// !!! It will be used in "xgettext" to create a Locating Message Catalog.
#define L(s) s
#endif /* L */
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
@ -433,7 +425,7 @@ static std::vector<std::string> s_Preset_print_options {
"top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness", "top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
"extra_perimeters", "extra_perimeters_on_overhangs", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs", "extra_perimeters", "extra_perimeters_on_overhangs", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs",
"seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern", "seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
"infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle", "infill_every_layers", /*"infill_only_where_needed",*/ "solid_infill_every_layers", "fill_angle", "bridge_angle",
"solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first", "solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first",
"ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing", "ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing",
"max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour", "max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour",
@ -443,7 +435,7 @@ static std::vector<std::string> s_Preset_print_options {
"enable_dynamic_overhang_speeds", "overhang_speed_0", "overhang_speed_1", "overhang_speed_2", "overhang_speed_3", "enable_dynamic_overhang_speeds", "overhang_speed_0", "overhang_speed_1", "overhang_speed_2", "overhang_speed_3",
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration", "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration",
"external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration", "external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration", "travel_acceleration",
"bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield", "bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
"min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", "min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
@ -460,8 +452,8 @@ static std::vector<std::string> s_Preset_print_options {
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio",
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", "wipe_tower_width", "wipe_tower_cone_angle", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits", "wipe_tower_no_sparse_layers", "wipe_tower_extra_spacing", "compatible_printers", "compatible_printers_condition", "inherits",
"perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", "perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"wall_distribution_count", "min_feature_size", "min_bead_width" "wall_distribution_count", "min_feature_size", "min_bead_width"
}; };
@ -491,7 +483,7 @@ static std::vector<std::string> s_Preset_machine_limits_options {
}; };
static std::vector<std::string> s_Preset_printer_options { static std::vector<std::string> s_Preset_printer_options {
"printer_technology", "printer_technology", "autoemit_temperature_commands",
"bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", "bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances",
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
//FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset.

View File

@ -14,19 +14,19 @@
#include "GCode/WipeTower.hpp" #include "GCode/WipeTower.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "BuildVolume.hpp" #include "BuildVolume.hpp"
#include "format.hpp"
#include <float.h> #include <float.h>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <string>
#include <unordered_set> #include <unordered_set>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <boost/regex.hpp> #include <boost/regex.hpp>
// Mark string for localization and translate.
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r { namespace Slic3r {
@ -58,6 +58,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
// Cache the plenty of parameters, which influence the G-code generator only, // Cache the plenty of parameters, which influence the G-code generator only,
// or they are only notes not influencing the generated G-code. // or they are only notes not influencing the generated G-code.
static std::unordered_set<std::string> steps_gcode = { static std::unordered_set<std::string> steps_gcode = {
"autoemit_temperature_commands",
"avoid_crossing_perimeters", "avoid_crossing_perimeters",
"avoid_crossing_perimeters_max_detour", "avoid_crossing_perimeters_max_detour",
"bed_shape", "bed_shape",
@ -137,6 +138,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"start_filament_gcode", "start_filament_gcode",
"toolchange_gcode", "toolchange_gcode",
"top_solid_infill_acceleration", "top_solid_infill_acceleration",
"travel_acceleration",
"thumbnails", "thumbnails",
"thumbnails_format", "thumbnails_format",
"use_firmware_retraction", "use_firmware_retraction",
@ -203,7 +205,9 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|| opt_key == "wipe_tower" || opt_key == "wipe_tower"
|| opt_key == "wipe_tower_width" || opt_key == "wipe_tower_width"
|| opt_key == "wipe_tower_brim_width" || opt_key == "wipe_tower_brim_width"
|| opt_key == "wipe_tower_cone_angle"
|| opt_key == "wipe_tower_bridging" || opt_key == "wipe_tower_bridging"
|| opt_key == "wipe_tower_extra_spacing"
|| opt_key == "wipe_tower_no_sparse_layers" || opt_key == "wipe_tower_no_sparse_layers"
|| opt_key == "wiping_volumes_matrix" || opt_key == "wiping_volumes_matrix"
|| opt_key == "parking_pos_retraction" || opt_key == "parking_pos_retraction"
@ -460,20 +464,20 @@ std::string Print::validate(std::string* warning) const
std::vector<unsigned int> extruders = this->extruders(); std::vector<unsigned int> extruders = this->extruders();
if (m_objects.empty()) if (m_objects.empty())
return L("All objects are outside of the print volume."); return _u8L("All objects are outside of the print volume.");
if (extruders.empty()) if (extruders.empty())
return L("The supplied settings will cause an empty print."); return _u8L("The supplied settings will cause an empty print.");
if (m_config.complete_objects) { if (m_config.complete_objects) {
if (! sequential_print_horizontal_clearance_valid(*this)) if (! sequential_print_horizontal_clearance_valid(*this))
return L("Some objects are too close; your extruder will collide with them."); return _u8L("Some objects are too close; your extruder will collide with them.");
if (! sequential_print_vertical_clearance_valid(*this)) if (! sequential_print_vertical_clearance_valid(*this))
return L("Some objects are too tall and cannot be printed without extruder collisions."); return _u8L("Some objects are too tall and cannot be printed without extruder collisions.");
} }
if (m_config.avoid_crossing_perimeters && m_config.avoid_crossing_curled_overhangs) { if (m_config.avoid_crossing_perimeters && m_config.avoid_crossing_curled_overhangs) {
return L("Avoid crossing perimeters option and avoid crossing curled overhangs option cannot be both enabled together."); return _u8L("Avoid crossing perimeters option and avoid crossing curled overhangs option cannot be both enabled together.");
} }
if (m_config.spiral_vase) { if (m_config.spiral_vase) {
@ -482,13 +486,17 @@ std::string Print::validate(std::string* warning) const
total_copies_count += object->instances().size(); total_copies_count += object->instances().size();
// #4043 // #4043
if (total_copies_count > 1 && ! m_config.complete_objects.value) if (total_copies_count > 1 && ! m_config.complete_objects.value)
return L("Only a single object may be printed at a time in Spiral Vase mode. " return _u8L("Only a single object may be printed at a time in Spiral Vase mode. "
"Either remove all but the last object, or enable sequential mode by \"complete_objects\"."); "Either remove all but the last object, or enable sequential mode by \"complete_objects\".");
assert(m_objects.size() == 1); assert(m_objects.size() == 1);
if (m_objects.front()->all_regions().size() > 1) if (m_objects.front()->all_regions().size() > 1)
return L("The Spiral Vase option can only be used when printing single material objects."); return _u8L("The Spiral Vase option can only be used when printing single material objects.");
} }
if (m_config.machine_limits_usage == MachineLimitsUsage::EmitToGCode && m_config.gcode_flavor == gcfKlipper)
return L("Machine limits cannot be emitted to G-Code when Klipper firmware flavor is used. "
"Change the value of machine_limits_usage.");
// Cache of layer height profiles for checking: // Cache of layer height profiles for checking:
// 1) Whether all layers are synchronized if printing with wipe tower and / or unsynchronized supports. // 1) Whether all layers are synchronized if printing with wipe tower and / or unsynchronized supports.
// 2) Whether layer height is constant for Organic supports. // 2) Whether layer height is constant for Organic supports.
@ -510,7 +518,7 @@ std::string Print::validate(std::string* warning) const
//FIXME It is quite expensive to generate object layers just to get the print height! //FIXME It is quite expensive to generate object layers just to get the print height!
if (auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx)); if (auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx));
! layers.empty() && layers.back() > this->config().max_print_height + EPSILON) { ! layers.empty() && layers.back() > this->config().max_print_height + EPSILON) {
return L("The print is taller than the maximum allowed height. You might want to reduce the size of your model" return _u8L("The print is taller than the maximum allowed height. You might want to reduce the size of your model"
" or change current print settings and retry."); " or change current print settings and retry.");
} }
} }
@ -527,7 +535,7 @@ std::string Print::validate(std::string* warning) const
print_object.model_object()->has_custom_layering()) { print_object.model_object()->has_custom_layering()) {
if (const std::vector<coordf_t> &layers = layer_height_profile(print_object_idx); ! layers.empty()) if (const std::vector<coordf_t> &layers = layer_height_profile(print_object_idx); ! layers.empty())
if (! check_object_layers_fixed(print_object.slicing_parameters(), layers)) if (! check_object_layers_fixed(print_object.slicing_parameters(), layers))
return L("Variable layer height is not supported with Organic supports."); return _u8L("Variable layer height is not supported with Organic supports.");
} }
if (this->has_wipe_tower() && ! m_objects.empty()) { if (this->has_wipe_tower() && ! m_objects.empty()) {
@ -540,21 +548,22 @@ std::string Print::validate(std::string* warning) const
double filament_diam = m_config.filament_diameter.get_at(extruder_idx); double filament_diam = m_config.filament_diameter.get_at(extruder_idx);
if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam
|| std::abs((filament_diam-first_filament_diam)/first_filament_diam) > 0.1) || std::abs((filament_diam-first_filament_diam)/first_filament_diam) > 0.1)
return L("The wipe tower is only supported if all extruders have the same nozzle diameter " return _u8L("The wipe tower is only supported if all extruders have the same nozzle diameter "
"and use filaments of the same diameter."); "and use filaments of the same diameter.");
} }
if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware && if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware &&
m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy && m_config.gcode_flavor != gcfMarlinFirmware) m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy &&
return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors."); m_config.gcode_flavor != gcfMarlinFirmware && m_config.gcode_flavor != gcfKlipper)
return _u8L("The Wipe Tower is currently only supported for the Marlin, Klipper, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors.");
if (! m_config.use_relative_e_distances) if (! m_config.use_relative_e_distances)
return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."); return _u8L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).");
if (m_config.ooze_prevention && m_config.single_extruder_multi_material) if (m_config.ooze_prevention && m_config.single_extruder_multi_material)
return L("Ooze prevention is only supported with the wipe tower when 'single_extruder_multi_material' is off."); return _u8L("Ooze prevention is only supported with the wipe tower when 'single_extruder_multi_material' is off.");
if (m_config.use_volumetric_e) if (m_config.use_volumetric_e)
return L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0)."); return _u8L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0).");
if (m_config.complete_objects && extruders.size() > 1) if (m_config.complete_objects && extruders.size() > 1)
return L("The Wipe Tower is currently not supported for multimaterial sequential prints."); return _u8L("The Wipe Tower is currently not supported for multimaterial sequential prints.");
if (m_objects.size() > 1) { if (m_objects.size() > 1) {
const SlicingParameters &slicing_params0 = m_objects.front()->slicing_parameters(); const SlicingParameters &slicing_params0 = m_objects.front()->slicing_parameters();
@ -564,21 +573,21 @@ std::string Print::validate(std::string* warning) const
const SlicingParameters &slicing_params = object->slicing_parameters(); const SlicingParameters &slicing_params = object->slicing_parameters();
if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON || if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON ||
std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON) std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON)
return L("The Wipe Tower is only supported for multiple objects if they have equal layer heights"); return _u8L("The Wipe Tower is only supported for multiple objects if they have equal layer heights");
if (slicing_params.raft_layers() != slicing_params0.raft_layers()) if (slicing_params.raft_layers() != slicing_params0.raft_layers())
return L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers"); return _u8L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers");
if (slicing_params0.gap_object_support != slicing_params.gap_object_support || if (slicing_params0.gap_object_support != slicing_params.gap_object_support ||
slicing_params0.gap_support_object != slicing_params.gap_support_object) slicing_params0.gap_support_object != slicing_params.gap_support_object)
return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance"); return _u8L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance");
if (! equal_layering(slicing_params, slicing_params0)) if (! equal_layering(slicing_params, slicing_params0))
return L("The Wipe Tower is only supported for multiple objects if they are sliced equally."); return _u8L("The Wipe Tower is only supported for multiple objects if they are sliced equally.");
if (has_custom_layering) { if (has_custom_layering) {
auto &lh = layer_height_profile(i); auto &lh = layer_height_profile(i);
auto &lh_tallest = layer_height_profile(tallest_object_idx); auto &lh_tallest = layer_height_profile(tallest_object_idx);
if (*(lh.end()-2) > *(lh_tallest.end()-2)) if (*(lh.end()-2) > *(lh_tallest.end()-2))
tallest_object_idx = i; tallest_object_idx = i;
} }
} }
if (has_custom_layering) { if (has_custom_layering) {
for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) { for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) {
@ -596,7 +605,7 @@ std::string Print::validate(std::string* warning) const
if (i%2 == 0 && layer_height_profiles[tallest_object_idx][i] > layer_height_profiles[idx_object][layer_height_profiles[idx_object].size() - 2 ]) if (i%2 == 0 && layer_height_profiles[tallest_object_idx][i] > layer_height_profiles[idx_object][layer_height_profiles[idx_object].size() - 2 ])
break; break;
if (std::abs(layer_height_profiles[idx_object][i] - layer_height_profiles[tallest_object_idx][i]) > eps) if (std::abs(layer_height_profiles[idx_object][i] - layer_height_profiles[tallest_object_idx][i]) > eps)
return L("The Wipe tower is only supported if all objects have the same variable layer height"); return _u8L("The Wipe tower is only supported if all objects have the same variable layer height");
++i; ++i;
} }
} }
@ -620,7 +629,7 @@ std::string Print::validate(std::string* warning) const
unsigned int total_extruders_count = m_config.nozzle_diameter.size(); unsigned int total_extruders_count = m_config.nozzle_diameter.size();
for (const auto& extruder_idx : extruders) for (const auto& extruder_idx : extruders)
if ( extruder_idx >= total_extruders_count ) if ( extruder_idx >= total_extruders_count )
return L("One or more object were assigned an extruder that the printer does not have."); return _u8L("One or more object were assigned an extruder that the printer does not have.");
#endif #endif
auto validate_extrusion_width = [/*min_nozzle_diameter,*/ max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool { auto validate_extrusion_width = [/*min_nozzle_diameter,*/ max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool {
@ -633,10 +642,10 @@ std::string Print::validate(std::string* warning) const
if (extrusion_width_min == 0) { if (extrusion_width_min == 0) {
// Default "auto-generated" extrusion width is always valid. // Default "auto-generated" extrusion width is always valid.
} else if (extrusion_width_min <= layer_height) { } else if (extrusion_width_min <= layer_height) {
err_msg = (boost::format(L("%1%=%2% mm is too low to be printable at a layer height %3% mm")) % opt_key % extrusion_width_min % layer_height).str(); err_msg = (boost::format(_u8L("%1%=%2% mm is too low to be printable at a layer height %3% mm")) % opt_key % extrusion_width_min % layer_height).str();
return false; return false;
} else if (extrusion_width_max >= max_nozzle_diameter * 3.) { } else if (extrusion_width_max >= max_nozzle_diameter * 3.) {
err_msg = (boost::format(L("Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm")) % opt_key % extrusion_width_max % max_nozzle_diameter).str(); err_msg = (boost::format(_u8L("Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm")) % opt_key % extrusion_width_max % max_nozzle_diameter).str();
return false; return false;
} }
return true; return true;
@ -647,7 +656,7 @@ std::string Print::validate(std::string* warning) const
// The object has some form of support and either support_material_extruder or support_material_interface_extruder // The object has some form of support and either support_material_extruder or support_material_interface_extruder
// will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles
// are of the same diameter. // are of the same diameter.
return L("Printing with multiple extruders of differing nozzle diameters. " return _u8L("Printing with multiple extruders of differing nozzle diameters. "
"If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), " "If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), "
"all nozzles have to be of the same diameter."); "all nozzles have to be of the same diameter.");
} }
@ -655,11 +664,11 @@ std::string Print::validate(std::string* warning) const
if (object->config().support_material_contact_distance == 0) { if (object->config().support_material_contact_distance == 0) {
// Soluble interface // Soluble interface
if (! object->config().support_material_synchronize_layers) if (! object->config().support_material_synchronize_layers)
return L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers."); return _u8L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers.");
} else { } else {
// Non-soluble interface // Non-soluble interface
if (object->config().support_material_extruder != 0 || object->config().support_material_interface_extruder != 0) if (object->config().support_material_extruder != 0 || object->config().support_material_interface_extruder != 0)
return L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. " return _u8L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. "
"(both support_material_extruder and support_material_interface_extruder need to be set to 0)."); "(both support_material_extruder and support_material_interface_extruder need to be set to 0).");
} }
} }
@ -695,12 +704,12 @@ std::string Print::validate(std::string* warning) const
first_layer_min_nozzle_diameter = min_nozzle_diameter; first_layer_min_nozzle_diameter = min_nozzle_diameter;
} }
if (first_layer_height > first_layer_min_nozzle_diameter) if (first_layer_height > first_layer_min_nozzle_diameter)
return L("First layer height can't be greater than nozzle diameter"); return _u8L("First layer height can't be greater than nozzle diameter");
// validate layer_height // validate layer_height
double layer_height = object->config().layer_height.value; double layer_height = object->config().layer_height.value;
if (layer_height > min_nozzle_diameter) if (layer_height > min_nozzle_diameter)
return L("Layer height can't be greater than nozzle diameter"); return _u8L("Layer height can't be greater than nozzle diameter");
// Validate extrusion widths. // Validate extrusion widths.
std::string err_msg; std::string err_msg;
@ -721,11 +730,11 @@ std::string Print::validate(std::string* warning) const
// See GH issues #6336 #5073 // See GH issues #6336 #5073
if ((m_config.gcode_flavor == gcfMarlinLegacy || m_config.gcode_flavor == gcfMarlinFirmware) && if ((m_config.gcode_flavor == gcfMarlinLegacy || m_config.gcode_flavor == gcfMarlinFirmware) &&
! before_layer_gcode_resets_extruder && ! layer_gcode_resets_extruder) ! before_layer_gcode_resets_extruder && ! layer_gcode_resets_extruder)
return L("Relative extruder addressing requires resetting the extruder position at each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to layer_gcode."); return _u8L("Relative extruder addressing requires resetting the extruder position at each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to layer_gcode.");
} else if (before_layer_gcode_resets_extruder) } else if (before_layer_gcode_resets_extruder)
return L("\"G92 E0\" was found in before_layer_gcode, which is incompatible with absolute extruder addressing."); return _u8L("\"G92 E0\" was found in before_layer_gcode, which is incompatible with absolute extruder addressing.");
else if (layer_gcode_resets_extruder) else if (layer_gcode_resets_extruder)
return L("\"G92 E0\" was found in layer_gcode, which is incompatible with absolute extruder addressing."); return _u8L("\"G92 E0\" was found in layer_gcode, which is incompatible with absolute extruder addressing.");
} }
return std::string(); return std::string();
@ -867,7 +876,7 @@ void Print::process()
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info(); BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
for (PrintObject *obj : m_objects) for (PrintObject *obj : m_objects)
obj->make_perimeters(); obj->make_perimeters();
this->set_status(70, L("Infilling layers")); this->set_status(70, _u8L("Infilling layers"));
for (PrintObject *obj : m_objects) for (PrintObject *obj : m_objects)
obj->infill(); obj->infill();
for (PrintObject *obj : m_objects) for (PrintObject *obj : m_objects)
@ -884,7 +893,7 @@ void Print::process()
m_wipe_tower_data.clear(); m_wipe_tower_data.clear();
m_tool_ordering.clear(); m_tool_ordering.clear();
if (this->has_wipe_tower()) { if (this->has_wipe_tower()) {
//this->set_status(95, L("Generating wipe tower")); //this->set_status(95, _u8L("Generating wipe tower"));
this->_make_wipe_tower(); this->_make_wipe_tower();
} else if (! this->config().complete_objects.value) { } else if (! this->config().complete_objects.value) {
// Initialize the tool ordering, so it could be used by the G-code preview slider for planning tool changes and filament switches. // Initialize the tool ordering, so it could be used by the G-code preview slider for planning tool changes and filament switches.
@ -895,7 +904,7 @@ void Print::process()
this->set_done(psWipeTower); this->set_done(psWipeTower);
} }
if (this->set_started(psSkirtBrim)) { if (this->set_started(psSkirtBrim)) {
this->set_status(88, L("Generating skirt and brim")); this->set_status(88, _u8L("Generating skirt and brim"));
m_skirt.clear(); m_skirt.clear();
m_skirt_convex_hull.clear(); m_skirt_convex_hull.clear();
@ -943,11 +952,11 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor
std::string message; std::string message;
if (!path.empty() && result == nullptr) { if (!path.empty() && result == nullptr) {
// Only show the path if preview_data is not set -> running from command line. // Only show the path if preview_data is not set -> running from command line.
message = L("Exporting G-code"); message = _u8L("Exporting G-code");
message += " to "; message += " to ";
message += path; message += path;
} else } else
message = L("Generating G-code"); message = _u8L("Generating G-code");
this->set_status(90, message); this->set_status(90, message);
// Create GCode on heap, it has quite a lot of data. // Create GCode on heap, it has quite a lot of data.
@ -1121,23 +1130,34 @@ Polygons Print::first_layer_islands() const
std::vector<Point> Print::first_layer_wipe_tower_corners() const std::vector<Point> Print::first_layer_wipe_tower_corners() const
{ {
std::vector<Point> corners; std::vector<Point> pts_scaled;
if (has_wipe_tower() && ! m_wipe_tower_data.tool_changes.empty()) { if (has_wipe_tower() && ! m_wipe_tower_data.tool_changes.empty()) {
double width = m_config.wipe_tower_width + 2*m_wipe_tower_data.brim_width; double width = m_config.wipe_tower_width + 2*m_wipe_tower_data.brim_width;
double depth = m_wipe_tower_data.depth + 2*m_wipe_tower_data.brim_width; double depth = m_wipe_tower_data.depth + 2*m_wipe_tower_data.brim_width;
Vec2d pt0(-m_wipe_tower_data.brim_width, -m_wipe_tower_data.brim_width); Vec2d pt0(-m_wipe_tower_data.brim_width, -m_wipe_tower_data.brim_width);
for (Vec2d pt : {
pt0, // First the corners.
Vec2d(pt0.x()+width, pt0.y() ), std::vector<Vec2d> pts = { pt0,
Vec2d(pt0.x()+width, pt0.y()+depth), Vec2d(pt0.x()+width, pt0.y()),
Vec2d(pt0.x(), pt0.y()+depth) Vec2d(pt0.x()+width, pt0.y()+depth),
}) { Vec2d(pt0.x(),pt0.y()+depth)
};
// Now the stabilization cone.
Vec2d center = (pts[0] + pts[2])/2.;
const auto [cone_R, cone_x_scale] = WipeTower::get_wipe_tower_cone_base(m_config.wipe_tower_width, m_wipe_tower_data.height, m_wipe_tower_data.depth, m_config.wipe_tower_cone_angle);
double r = cone_R + m_wipe_tower_data.brim_width;
for (double alpha = 0.; alpha<2*M_PI; alpha += M_PI/20.)
pts.emplace_back(center + r*Vec2d(std::cos(alpha)/cone_x_scale, std::sin(alpha)));
for (Vec2d& pt : pts) {
pt = Eigen::Rotation2Dd(Geometry::deg2rad(m_config.wipe_tower_rotation_angle.value)) * pt; pt = Eigen::Rotation2Dd(Geometry::deg2rad(m_config.wipe_tower_rotation_angle.value)) * pt;
pt += Vec2d(m_config.wipe_tower_x.value, m_config.wipe_tower_y.value); pt += Vec2d(m_config.wipe_tower_x.value, m_config.wipe_tower_y.value);
corners.emplace_back(Point(scale_(pt.x()), scale_(pt.y()))); pts_scaled.emplace_back(Point(scale_(pt.x()), scale_(pt.y())));
} }
} }
return corners; return pts_scaled;
} }
void Print::finalize_first_layer_convex_hull() void Print::finalize_first_layer_convex_hull()
@ -1156,26 +1176,71 @@ void Print::alert_when_supports_needed()
{ {
if (this->set_started(psAlertWhenSupportsNeeded)) { if (this->set_started(psAlertWhenSupportsNeeded)) {
BOOST_LOG_TRIVIAL(debug) << "psAlertWhenSupportsNeeded - start"; BOOST_LOG_TRIVIAL(debug) << "psAlertWhenSupportsNeeded - start";
set_status(69, L("Alert if supports needed")); set_status(69, _u8L("Alert if supports needed"));
auto issue_to_alert_message = [](SupportSpotsGenerator::SupportPointCause cause, bool critical) { auto issue_to_alert_message = [](SupportSpotsGenerator::SupportPointCause cause, bool critical) {
std::string message; std::string message;
switch (cause) { switch (cause) {
case SupportSpotsGenerator::SupportPointCause::LongBridge: message = L("long bridging extrusions"); break; //TRN Alert when support is needed. Describes that the model has long bridging extrusions which may print badly
case SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor: message = L("floating bridge anchors"); break; case SupportSpotsGenerator::SupportPointCause::LongBridge: message = _u8L("Long bridging extrusions"); break;
//TRN Alert when support is needed. Describes bridge anchors/turns in the air, which will definitely print badly
case SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor: message = _u8L("Floating bridge anchors"); break;
case SupportSpotsGenerator::SupportPointCause::FloatingExtrusion: case SupportSpotsGenerator::SupportPointCause::FloatingExtrusion:
if (critical) { if (critical) {
message = L("collapsing overhang"); //TRN Alert when support is needed. Describes that the print has large overhang area which will print badly or not print at all.
message = _u8L("Collapsing overhang");
} else { } else {
message = L("loose extrusions"); //TRN Alert when support is needed. Describes extrusions that are not supported enough and come out curled or loose.
message = _u8L("Loose extrusions");
} }
break; break;
case SupportSpotsGenerator::SupportPointCause::SeparationFromBed: message = L("low bed adhesion"); break; //TRN Alert when support is needed. Describes that the print has low bed adhesion and may became loose.
case SupportSpotsGenerator::SupportPointCause::UnstableFloatingPart: message = L("floating object part"); break; case SupportSpotsGenerator::SupportPointCause::SeparationFromBed: message = _u8L("Low bed adhesion"); break;
case SupportSpotsGenerator::SupportPointCause::WeakObjectPart: message = L("thin fragile section"); break; //TRN Alert when support is needed. Describes that the object has part that is not connected to the bed and will not print at all without supports.
case SupportSpotsGenerator::SupportPointCause::UnstableFloatingPart: message = _u8L("Floating object part"); break;
//TRN Alert when support is needed. Describes that the object has thin part that may brake during printing
case SupportSpotsGenerator::SupportPointCause::WeakObjectPart: message = _u8L("Thin fragile part"); break;
} }
return (critical ? "!" : "") + message; return message;
};
// TRN this translation rule is used to translate lists of uknown size on single line. The first argument is element of the list,
// the second argument may be element or rest of the list. For most languages, this does not need translation, but some use different
// separator than comma and some use blank space in front of the separator.
auto single_line_list_rule = L("%1%, %2%");
auto multiline_list_rule = "%1%\n%2%";
auto elements_to_translated_list = [](const std::vector<std::string> &translated_elements, std::string expansion_rule) {
if (expansion_rule.find("%1%") == expansion_rule.npos || expansion_rule.find("%2%") == expansion_rule.npos) {
BOOST_LOG_TRIVIAL(error) << "INCORRECT EXPANSION RULE FOR LIST TRANSLATION: " << expansion_rule
<< " - IT SHOULD CONTAIN %1% and %2%!";
expansion_rule = "%1% %2%";
}
if (translated_elements.size() == 0) {
return std::string{};
}
if (translated_elements.size() == 1) {
return translated_elements.front();
}
std::string translated_list = expansion_rule;
for (int i = 0; i < translated_elements.size() - 1; i++) {
auto first_elem = translated_list.find("%1%");
assert(first_elem != translated_list.npos);
translated_list.replace(first_elem, 3, translated_elements[i]);
// expand the translated list by another application of the same rule
auto second_elem = translated_list.find("%2%");
assert(second_elem != translated_list.npos);
if (i < translated_elements.size() - 2) {
translated_list.replace(second_elem, 3, expansion_rule);
} else {
translated_list.replace(second_elem, 3, translated_elements[i + 1]);
}
}
return translated_list;
}; };
// vector of pairs of object and its issues, where each issue is a pair of type and critical flag // vector of pairs of object and its issues, where each issue is a pair of type and critical flag
@ -1197,45 +1262,58 @@ void Print::alert_when_supports_needed()
} }
} }
bool recommend_brim = false; bool recommend_brim = false;
std::map<std::pair<SupportSpotsGenerator::SupportPointCause, bool>, std::vector<const PrintObject *>> po_by_support_issues; std::map<std::pair<SupportSpotsGenerator::SupportPointCause, bool>, std::vector<const PrintObject *>> po_by_support_issues;
for (const auto &obj : objects_isssues) { for (const auto &obj : objects_isssues) {
for (const auto &issue : obj.second) { for (const auto &issue : obj.second) {
po_by_support_issues[issue].push_back(obj.first); po_by_support_issues[issue].push_back(obj.first);
if (issue.first == SupportSpotsGenerator::SupportPointCause::SeparationFromBed && !obj.first->has_brim()){ if (issue.first == SupportSpotsGenerator::SupportPointCause::SeparationFromBed && !obj.first->has_brim()) {
recommend_brim = true; recommend_brim = true;
} }
} }
} }
auto message = L("Detected print stability issues") + ": \n"; std::vector<std::pair<std::string, std::vector<std::string>>> message_elements;
if (objects_isssues.size() > po_by_support_issues.size()) { if (objects_isssues.size() > po_by_support_issues.size()) {
// there are more objects than causes, group by issues // there are more objects than causes, group by issues
for (const auto &issue : po_by_support_issues) { for (const auto &issue : po_by_support_issues) {
message += "\n" + issue_to_alert_message(issue.first.first, issue.first.second) + " >> "; auto &pair = message_elements.emplace_back(issue_to_alert_message(issue.first.first, issue.first.second),
std::vector<std::string>{});
for (const auto &obj : issue.second) { for (const auto &obj : issue.second) {
message += obj->m_model_object->name + ", "; pair.second.push_back(obj->m_model_object->name);
} }
message.pop_back();
message.pop_back(); // remove ,
message += ".\n";
} }
} else { } else {
// more causes than objects, group by objects // more causes than objects, group by objects
for (const auto &obj : objects_isssues) { for (const auto &obj : objects_isssues) {
message += "\n" + L("Object") + " " + obj.first->model_object()->name + " << "; auto &pair = message_elements.emplace_back(obj.first->model_object()->name, std::vector<std::string>{});
for (const auto &issue : obj.second) { for (const auto &issue : obj.second) {
message += issue_to_alert_message(issue.first, issue.second) + ", "; pair.second.push_back(issue_to_alert_message(issue.first, issue.second));
} }
message.pop_back();
message.pop_back(); // remove ,
message += ".\n";
} }
} }
bool brim_or_supp = recommend_brim && po_by_support_issues.size() < 2; // first, gather sublements into single line list, store in first subelement
auto brim_part = " " + (brim_or_supp ? L("or") : L("and")) + " " + L("brim"); for (auto &pair : message_elements) {
message += "\n" + L("Consider enabling supports") + (recommend_brim ? brim_part : "") + "."; pair.second.front() = elements_to_translated_list(pair.second, single_line_list_rule);
}
// then gather elements to create multiline list
std::vector<std::string> lines = {};
for (auto &pair : message_elements) {
lines.push_back(""); // empty line for readability
lines.push_back(pair.first);
lines.push_back(pair.second.front());
}
lines.push_back("");
lines.push_back(_u8L("Consider enabling supports."));
if (recommend_brim) {
lines.push_back(_u8L("Also consider enabling brim."));
}
// TRN Alert message for detected print issues. first argument is a list of detected issues.
auto message = Slic3r::format(_u8L("Detected print stability issues:\n%1%"), elements_to_translated_list(lines, multiline_list_rule));
if (objects_isssues.size() > 0) { if (objects_isssues.size() > 0) {
this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, message); this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, message);
@ -1377,6 +1455,7 @@ void Print::_make_wipe_tower()
wipe_tower.generate(m_wipe_tower_data.tool_changes); wipe_tower.generate(m_wipe_tower_data.tool_changes);
m_wipe_tower_data.depth = wipe_tower.get_depth(); m_wipe_tower_data.depth = wipe_tower.get_depth();
m_wipe_tower_data.brim_width = wipe_tower.get_brim_width(); m_wipe_tower_data.brim_width = wipe_tower.get_brim_width();
m_wipe_tower_data.height = wipe_tower.get_wipe_tower_height();
// Unload the current filament over the purge tower. // Unload the current filament over the purge tower.
coordf_t layer_height = m_objects.front()->config().layer_height.value; coordf_t layer_height = m_objects.front()->config().layer_height.value;

View File

@ -1,6 +1,8 @@
#ifndef slic3r_Print_hpp_ #ifndef slic3r_Print_hpp_
#define slic3r_Print_hpp_ #define slic3r_Print_hpp_
#include "Fill/FillAdaptive.hpp"
#include "Fill/FillLightning.hpp"
#include "PrintBase.hpp" #include "PrintBase.hpp"
#include "BoundingBox.hpp" #include "BoundingBox.hpp"
@ -385,7 +387,8 @@ private:
void discover_horizontal_shells(); void discover_horizontal_shells();
void combine_infill(); void combine_infill();
void _generate_support_material(); void _generate_support_material();
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> prepare_adaptive_infill_data(); std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> prepare_adaptive_infill_data(
const std::vector<std::pair<const Surface*, float>>& surfaces_w_bottom_z) const;
FillLightning::GeneratorPtr prepare_lightning_infill_data(); FillLightning::GeneratorPtr prepare_lightning_infill_data();
// XYZ in scaled coordinates // XYZ in scaled coordinates
@ -410,6 +413,9 @@ private:
// this is set to true when LayerRegion->slices is split in top/internal/bottom // this is set to true when LayerRegion->slices is split in top/internal/bottom
// so that next call to make_perimeters() performs a union() before computing loops // so that next call to make_perimeters() performs a union() before computing loops
bool m_typed_slices = false; bool m_typed_slices = false;
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> m_adaptive_fill_octrees;
FillLightning::GeneratorPtr m_lightning_generator;
}; };
struct WipeTowerData struct WipeTowerData
@ -428,6 +434,7 @@ struct WipeTowerData
// Depth of the wipe tower to pass to GLCanvas3D for exact bounding box: // Depth of the wipe tower to pass to GLCanvas3D for exact bounding box:
float depth; float depth;
float brim_width; float brim_width;
float height;
void clear() { void clear() {
priming.reset(nullptr); priming.reset(nullptr);
@ -559,6 +566,11 @@ public:
SpanOfConstPtrs<PrintObject> objects() const { return SpanOfConstPtrs<PrintObject>(const_cast<const PrintObject* const* const>(m_objects.data()), m_objects.size()); } SpanOfConstPtrs<PrintObject> objects() const { return SpanOfConstPtrs<PrintObject>(const_cast<const PrintObject* const* const>(m_objects.data()), m_objects.size()); }
PrintObject* get_object(size_t idx) { return const_cast<PrintObject*>(m_objects[idx]); } PrintObject* get_object(size_t idx) { return const_cast<PrintObject*>(m_objects[idx]); }
const PrintObject* get_object(size_t idx) const { return m_objects[idx]; } const PrintObject* get_object(size_t idx) const { return m_objects[idx]; }
const PrintObject* get_print_object_by_model_object_id(ObjectID object_id) const {
auto it = std::find_if(m_objects.begin(), m_objects.end(),
[object_id](const PrintObject* obj) { return obj->model_object()->id() == object_id; });
return (it == m_objects.end()) ? nullptr : *it;
}
// PrintObject by its ObjectID, to be used to uniquely bind slicing warnings to their source PrintObjects // PrintObject by its ObjectID, to be used to uniquely bind slicing warnings to their source PrintObjects
// in the notification center. // in the notification center.
const PrintObject* get_object(ObjectID object_id) const { const PrintObject* get_object(ObjectID object_id) const {

View File

@ -6,10 +6,6 @@
#include "I18N.hpp" #include "I18N.hpp"
//! macro used to mark string used at localization,
//! return same string
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r namespace Slic3r
{ {
@ -81,7 +77,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str
filename = boost::filesystem::change_extension(filename, default_ext); filename = boost::filesystem::change_extension(filename, default_ext);
return filename.string(); return filename.string();
} catch (std::runtime_error &err) { } catch (std::runtime_error &err) {
throw Slic3r::PlaceholderParserError(L("Failed processing of the output_filename_format template.") + "\n" + err.what()); throw Slic3r::PlaceholderParserError(_u8L("Failed processing of the output_filename_format template.") + "\n" + err.what());
} }
} }

View File

@ -16,11 +16,6 @@
namespace Slic3r { namespace Slic3r {
//! macro used to mark string used at localization,
//! return same string
#define L(s) (s)
#define _(s) Slic3r::I18N::translate(s)
static t_config_enum_names enum_names_from_keys_map(const t_config_enum_values &enum_keys_map) static t_config_enum_names enum_names_from_keys_map(const t_config_enum_values &enum_keys_map)
{ {
t_config_enum_names names; t_config_enum_names names;
@ -53,6 +48,7 @@ static const t_config_enum_values s_keys_map_GCodeFlavor {
{ "makerware", gcfMakerWare }, { "makerware", gcfMakerWare },
{ "marlin", gcfMarlinLegacy }, { "marlin", gcfMarlinLegacy },
{ "marlin2", gcfMarlinFirmware }, { "marlin2", gcfMarlinFirmware },
{ "klipper", gcfKlipper },
{ "sailfish", gcfSailfish }, { "sailfish", gcfSailfish },
{ "smoothie", gcfSmoothie }, { "smoothie", gcfSmoothie },
{ "mach3", gcfMach3 }, { "mach3", gcfMach3 },
@ -72,6 +68,7 @@ static const t_config_enum_values s_keys_map_PrintHostType {
{ "prusalink", htPrusaLink }, { "prusalink", htPrusaLink },
{ "prusaconnect", htPrusaConnect }, { "prusaconnect", htPrusaConnect },
{ "octoprint", htOctoPrint }, { "octoprint", htOctoPrint },
{ "mainsail", htMainSail },
{ "duet", htDuet }, { "duet", htDuet },
{ "flashair", htFlashAir }, { "flashair", htFlashAir },
{ "astrobox", htAstroBox }, { "astrobox", htAstroBox },
@ -404,6 +401,7 @@ void PrintConfigDef::init_fff_params()
const int max_temp = 1500; const int max_temp = 1500;
def = this->add("avoid_crossing_curled_overhangs", coBool); def = this->add("avoid_crossing_curled_overhangs", coBool);
def->label = L("Avoid crossing curled overhangs (Experimental)"); def->label = L("Avoid crossing curled overhangs (Experimental)");
// TRN PrintSettings: "Avoid crossing curled overhangs (Experimental)"
def->tooltip = L("Plan travel moves such that the extruder avoids areas where the filament may be curled up. " def->tooltip = L("Plan travel moves such that the extruder avoids areas where the filament may be curled up. "
"This is mostly happening on steeper rounded overhangs and may cause a crash with the nozzle. " "This is mostly happening on steeper rounded overhangs and may cause a crash with the nozzle. "
"This feature slows down both the print and the G-code generation."); "This feature slows down both the print and the G-code generation.");
@ -461,8 +459,8 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionString("")); def->set_default_value(new ConfigOptionString(""));
def = this->add("bottom_solid_layers", coInt); def = this->add("bottom_solid_layers", coInt);
//TRN To be shown in Print Settings "Bottom solid layers" //TRN Print Settings: "Bottom solid layers"
def->label = L("Bottom"); def->label = L_CONTEXT("Bottom", "Layers");
def->category = L("Layers and Perimeters"); def->category = L("Layers and Perimeters");
def->tooltip = L("Number of solid layers to generate on bottom surfaces."); def->tooltip = L("Number of solid layers to generate on bottom surfaces.");
def->full_label = L("Bottom solid layers"); def->full_label = L("Bottom solid layers");
@ -470,8 +468,7 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionInt(3)); def->set_default_value(new ConfigOptionInt(3));
def = this->add("bottom_solid_min_thickness", coFloat); def = this->add("bottom_solid_min_thickness", coFloat);
//TRN To be shown in Print Settings "Top solid layers" def->label = L_CONTEXT("Bottom", "Layers");
def->label = L("Bottom");
def->category = L("Layers and Perimeters"); def->category = L("Layers and Perimeters");
def->tooltip = L("The number of bottom solid layers is increased above bottom_solid_layers if necessary to satisfy " def->tooltip = L("The number of bottom solid layers is increased above bottom_solid_layers if necessary to satisfy "
"minimum thickness of bottom shell."); "minimum thickness of bottom shell.");
@ -538,6 +535,7 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false)); def->set_default_value(new ConfigOptionBool(false));
// TRN PrintSettings : "Dynamic overhang speed"
auto overhang_speed_setting_description = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: " auto overhang_speed_setting_description = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
"100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). " "100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). "
"Speeds for overhang sizes in between are calculated via linear interpolation. " "Speeds for overhang sizes in between are calculated via linear interpolation. "
@ -585,10 +583,11 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionBools{false}); def->set_default_value(new ConfigOptionBools{false});
// TRN FilamentSettings : "Dynamic fan speeds"
auto fan_speed_setting_description = L( auto fan_speed_setting_description = L(
"Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: " "Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
"100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). " "100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). "
"Fan speeds for overhang sizes in between are calculated via linear interpolation. "); "Fan speeds for overhang sizes in between are calculated via linear interpolation.");
def = this->add("overhang_fan_speed_0", coInts); def = this->add("overhang_fan_speed_0", coInts);
def->label = L("speed for 0% overlap (bridge)"); def->label = L("speed for 0% overlap (bridge)");
@ -1409,6 +1408,7 @@ void PrintConfigDef::init_fff_params()
{ "makerware", "MakerWare (MakerBot)" }, { "makerware", "MakerWare (MakerBot)" },
{ "marlin", "Marlin (legacy)" }, { "marlin", "Marlin (legacy)" },
{ "marlin2", "Marlin 2" }, { "marlin2", "Marlin 2" },
{ "klipper", "Klipper" },
{ "sailfish", "Sailfish (MakerBot)" }, { "sailfish", "Sailfish (MakerBot)" },
{ "mach3", "Mach3/LinuxCNC" }, { "mach3", "Mach3/LinuxCNC" },
{ "machinekit", "Machinekit" }, { "machinekit", "Machinekit" },
@ -1466,7 +1466,15 @@ void PrintConfigDef::init_fff_params()
def->min = 0; def->min = 0;
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0)); def->set_default_value(new ConfigOptionFloat(0));
def = this->add("travel_acceleration", coFloat);
def->label = L("Travel");
def->tooltip = L("This is the acceleration your printer will use for travel moves. Set zero to disable "
"acceleration control for travel.");
def->sidetext = L("mm/s²");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("infill_every_layers", coInt); def = this->add("infill_every_layers", coInt);
def->label = L("Combine infill every"); def->label = L("Combine infill every");
@ -1552,14 +1560,14 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false)); def->set_default_value(new ConfigOptionBool(false));
def = this->add("infill_only_where_needed", coBool); // def = this->add("infill_only_where_needed", coBool);
def->label = L("Only infill where needed"); // def->label = L("Only infill where needed");
def->category = L("Infill"); // def->category = L("Infill");
def->tooltip = L("This option will limit infill to the areas actually needed for supporting ceilings " // def->tooltip = L("This option will limit infill to the areas actually needed for supporting ceilings "
"(it will act as internal support material). If enabled, slows down the G-code generation " // "(it will act as internal support material). If enabled, slows down the G-code generation "
"due to the multiple checks involved."); // "due to the multiple checks involved.");
def->mode = comAdvanced; // def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false)); // def->set_default_value(new ConfigOptionBool(false));
def = this->add("infill_overlap", coFloatOrPercent); def = this->add("infill_overlap", coFloatOrPercent);
def->label = L("Infill/perimeters overlap"); def->label = L("Infill/perimeters overlap");
@ -1795,9 +1803,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("machine_max_acceleration_extruding", coFloats); def = this->add("machine_max_acceleration_extruding", coFloats);
def->full_label = L("Maximum acceleration when extruding"); def->full_label = L("Maximum acceleration when extruding");
def->category = L("Machine limits"); def->category = L("Machine limits");
def->tooltip = L("Maximum acceleration when extruding (M204 P)\n\n" def->tooltip = L("Maximum acceleration when extruding");
"Marlin (legacy) firmware flavor will use this also "
"as travel acceleration (M204 T).");
def->sidetext = L("mm/s²"); def->sidetext = L("mm/s²");
def->min = 0; def->min = 0;
def->mode = comAdvanced; def->mode = comAdvanced;
@ -1808,7 +1814,8 @@ void PrintConfigDef::init_fff_params()
def = this->add("machine_max_acceleration_retracting", coFloats); def = this->add("machine_max_acceleration_retracting", coFloats);
def->full_label = L("Maximum acceleration when retracting"); def->full_label = L("Maximum acceleration when retracting");
def->category = L("Machine limits"); def->category = L("Machine limits");
def->tooltip = L("Maximum acceleration when retracting (M204 R)"); def->tooltip = L("Maximum acceleration when retracting.\n\n"
"Not used for RepRapFirmware, which does not support it.");
def->sidetext = L("mm/s²"); def->sidetext = L("mm/s²");
def->min = 0; def->min = 0;
def->mode = comAdvanced; def->mode = comAdvanced;
@ -1818,7 +1825,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("machine_max_acceleration_travel", coFloats); def = this->add("machine_max_acceleration_travel", coFloats);
def->full_label = L("Maximum acceleration for travel moves"); def->full_label = L("Maximum acceleration for travel moves");
def->category = L("Machine limits"); def->category = L("Machine limits");
def->tooltip = L("Maximum acceleration for travel moves (M204 T)"); def->tooltip = L("Maximum acceleration for travel moves.");
def->sidetext = L("mm/s²"); def->sidetext = L("mm/s²");
def->min = 0; def->min = 0;
def->mode = comAdvanced; def->mode = comAdvanced;
@ -1947,6 +1954,7 @@ void PrintConfigDef::init_fff_params()
{ "prusalink", "PrusaLink" }, { "prusalink", "PrusaLink" },
{ "prusaconnect", "PrusaConnect" }, { "prusaconnect", "PrusaConnect" },
{ "octoprint", "OctoPrint" }, { "octoprint", "OctoPrint" },
{ "mainsail", "Mainsail/Fluidd" },
{ "duet", "Duet" }, { "duet", "Duet" },
{ "flashair", "FlashAir" }, { "flashair", "FlashAir" },
{ "astrobox", "AstroBox" }, { "astrobox", "AstroBox" },
@ -1966,7 +1974,8 @@ void PrintConfigDef::init_fff_params()
def = this->add("ooze_prevention", coBool); def = this->add("ooze_prevention", coBool);
def->label = L("Enable"); def->label = L("Enable");
def->tooltip = L("This option will drop the temperature of the inactive extruders to prevent oozing. "); // TRN PrintSettings: Enable ooze prevention
def->tooltip = L("This option will drop the temperature of the inactive extruders to prevent oozing.");
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false)); def->set_default_value(new ConfigOptionBool(false));
@ -2304,6 +2313,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("staggered_inner_seams", coBool); def = this->add("staggered_inner_seams", coBool);
def->label = L("Staggered inner seams"); def->label = L("Staggered inner seams");
// TRN PrintSettings: "Staggered inner seams"
def->tooltip = L("This option causes the inner seams to be shifted backwards based on their depth, forming a zigzag pattern."); def->tooltip = L("This option causes the inner seams to be shifted backwards based on their depth, forming a zigzag pattern.");
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false)); def->set_default_value(new ConfigOptionBool(false));
@ -2469,6 +2479,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("standby_temperature_delta", coInt); def = this->add("standby_temperature_delta", coInt);
def->label = L("Temperature variation"); def->label = L("Temperature variation");
// TRN PrintSettings : "Ooze prevention" > "Temperature variation"
def->tooltip = L("Temperature difference to be applied when an extruder is not active. " def->tooltip = L("Temperature difference to be applied when an extruder is not active. "
"The value is not used when 'idle_temperature' in filament settings " "The value is not used when 'idle_temperature' in filament settings "
"is defined."); "is defined.");
@ -2478,15 +2489,25 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionInt(-5)); def->set_default_value(new ConfigOptionInt(-5));
def = this->add("autoemit_temperature_commands", coBool);
def->label = L("Emit temperature commands automatically");
def->tooltip = L("When enabled, PrusaSlicer will check whether your Custom Start G-Code contains M104 or M190. "
"If so, the temperatures will not be emitted automatically so you're free to customize "
"the order of heating commands and other custom actions. Note that you can use "
"placeholder variables for all PrusaSlicer settings, so you can put "
"a \"M109 S[first_layer_temperature]\" command wherever you want.\n"
"If your Custom Start G-Code does NOT contain M104 or M190, "
"PrusaSlicer will execute the Start G-Code after bed reached its target temperature "
"and extruder just started heating.\n\n"
"When disabled, PrusaSlicer will NOT emit commands to heat up extruder and bed, "
"leaving both to Custom Start G-Code.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("start_gcode", coString); def = this->add("start_gcode", coString);
def->label = L("Start G-code"); def->label = L("Start G-code");
def->tooltip = L("This start procedure is inserted at the beginning, after bed has reached " def->tooltip = L("This start procedure is inserted at the beginning, possibly prepended by "
"the target temperature and extruder just started heating, and before extruder " "temperature-changing commands. See 'autoemit_temperature_commands'.");
"has finished heating. If PrusaSlicer detects M104 or M190 in your custom codes, "
"such commands will not be prepended automatically so you're free to customize "
"the order of heating commands and other custom actions. Note that you can use "
"placeholder variables for all PrusaSlicer settings, so you can put "
"a \"M109 S[first_layer_temperature]\" command wherever you want.");
def->multiline = true; def->multiline = true;
def->full_width = true; def->full_width = true;
def->height = 12; def->height = 12;
@ -2646,8 +2667,8 @@ void PrintConfigDef::init_fff_params()
"If set to zero, support_material_contact_distance will be used for both top and bottom contact Z distances."); "If set to zero, support_material_contact_distance will be used for both top and bottom contact Z distances.");
def->sidetext = L("mm"); def->sidetext = L("mm");
// def->min = 0; // def->min = 0;
//TRN To be shown in Print Settings "Bottom contact Z distance". Have to be as short as possible
def->set_enum_values(ConfigOptionDef::GUIType::f_enum_open, { def->set_enum_values(ConfigOptionDef::GUIType::f_enum_open, {
//TRN Print Settings: "Bottom contact Z distance". Have to be as short as possible
{ "0", L("Same as top") }, { "0", L("Same as top") },
{ "0.1", "0.1" }, { "0.1", "0.1" },
{ "0.2", "0.2" } { "0.2", "0.2" }
@ -2705,7 +2726,7 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(1)); def->set_default_value(new ConfigOptionInt(1));
auto support_material_interface_layers = def = this->add("support_material_interface_layers", coInt); def = this->add("support_material_interface_layers", coInt);
def->label = L("Top interface layers"); def->label = L("Top interface layers");
def->category = L("Support material"); def->category = L("Support material");
def->tooltip = L("Number of interface layers to insert between the object(s) and support material."); def->tooltip = L("Number of interface layers to insert between the object(s) and support material.");
@ -2727,8 +2748,8 @@ void PrintConfigDef::init_fff_params()
"Set to -1 to use support_material_interface_layers"); "Set to -1 to use support_material_interface_layers");
def->sidetext = L("layers"); def->sidetext = L("layers");
def->min = -1; def->min = -1;
//TRN To be shown in Print Settings "Bottom interface layers". Have to be as short as possible
def->set_enum_values(ConfigOptionDef::GUIType::i_enum_open, { def->set_enum_values(ConfigOptionDef::GUIType::i_enum_open, {
//TRN Print Settings: "Bottom interface layers". Have to be as short as possible
{ "-1", L("Same as top") }, { "-1", L("Same as top") },
{ "0", L("0 (off)") }, { "0", L("0 (off)") },
{ "1", L("1 (light)") }, { "1", L("1 (light)") },
@ -2829,6 +2850,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("support_material_synchronize_layers", coBool); def = this->add("support_material_synchronize_layers", coBool);
def->label = L("Synchronize with object layers"); def->label = L("Synchronize with object layers");
def->category = L("Support material"); def->category = L("Support material");
// TRN PrintSettings : "Synchronize with object layers"
def->tooltip = L("Synchronize support layers with the object print layers. This is useful " def->tooltip = L("Synchronize support layers with the object print layers. This is useful "
"with multi-material printers, where the extruder switch is expensive. " "with multi-material printers, where the extruder switch is expensive. "
"This option is only available when top contact Z distance is set to zero."); "This option is only available when top contact Z distance is set to zero.");
@ -2860,6 +2882,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("support_tree_angle", coFloat); def = this->add("support_tree_angle", coFloat);
def->label = L("Maximum Branch Angle"); def->label = L("Maximum Branch Angle");
def->category = L("Support material"); def->category = L("Support material");
// TRN PrintSettings: "Organic supports" > "Maximum Branch Angle"
def->tooltip = L("The maximum angle of the branches, when the branches have to avoid the model. " def->tooltip = L("The maximum angle of the branches, when the branches have to avoid the model. "
"Use a lower angle to make them more vertical and more stable. Use a higher angle to be able to have more reach."); "Use a lower angle to make them more vertical and more stable. Use a higher angle to be able to have more reach.");
def->sidetext = L("°"); def->sidetext = L("°");
@ -2871,6 +2894,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("support_tree_angle_slow", coFloat); def = this->add("support_tree_angle_slow", coFloat);
def->label = L("Preferred Branch Angle"); def->label = L("Preferred Branch Angle");
def->category = L("Support material"); def->category = L("Support material");
// TRN PrintSettings: "Organic supports" > "Preferred Branch Angle"
def->tooltip = L("The preferred angle of the branches, when they do not have to avoid the model. " def->tooltip = L("The preferred angle of the branches, when they do not have to avoid the model. "
"Use a lower angle to make them more vertical and more stable. Use a higher angle for branches to merge faster."); "Use a lower angle to make them more vertical and more stable. Use a higher angle for branches to merge faster.");
def->sidetext = L("°"); def->sidetext = L("°");
@ -2882,6 +2906,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("support_tree_tip_diameter", coFloat); def = this->add("support_tree_tip_diameter", coFloat);
def->label = L("Tip Diameter"); def->label = L("Tip Diameter");
def->category = L("Support material"); def->category = L("Support material");
// TRN PrintSettings: "Organic supports" > "Tip Diameter"
def->tooltip = L("The diameter of the top of the tip of the branches of organic support."); def->tooltip = L("The diameter of the top of the tip of the branches of organic support.");
def->sidetext = L("mm"); def->sidetext = L("mm");
def->min = 0; def->min = 0;
@ -2891,6 +2916,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("support_tree_branch_diameter", coFloat); def = this->add("support_tree_branch_diameter", coFloat);
def->label = L("Branch Diameter"); def->label = L("Branch Diameter");
def->category = L("Support material"); def->category = L("Support material");
// TRN PrintSettings: "Organic supports" > "Branch Diameter"
def->tooltip = L("The diameter of the thinnest branches of organic support. Thicker branches are more sturdy. " def->tooltip = L("The diameter of the thinnest branches of organic support. Thicker branches are more sturdy. "
"Branches towards the base will be thicker than this."); "Branches towards the base will be thicker than this.");
def->sidetext = L("mm"); def->sidetext = L("mm");
@ -2899,8 +2925,10 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloat(2)); def->set_default_value(new ConfigOptionFloat(2));
def = this->add("support_tree_branch_diameter_angle", coFloat); def = this->add("support_tree_branch_diameter_angle", coFloat);
// TRN PrintSettings: #lmFIXME
def->label = L("Branch Diameter Angle"); def->label = L("Branch Diameter Angle");
def->category = L("Support material"); def->category = L("Support material");
// TRN PrintSettings: "Organic supports" > "Branch Diameter Angle"
def->tooltip = L("The angle of the branches' diameter as they gradually become thicker towards the bottom. " def->tooltip = L("The angle of the branches' diameter as they gradually become thicker towards the bottom. "
"An angle of 0 will cause the branches to have uniform thickness over their length. " "An angle of 0 will cause the branches to have uniform thickness over their length. "
"A bit of an angle can increase stability of the organic support."); "A bit of an angle can increase stability of the organic support.");
@ -2914,8 +2942,10 @@ void PrintConfigDef::init_fff_params()
// How far apart the branches need to be when they touch the model. Making this distance small will cause // How far apart the branches need to be when they touch the model. Making this distance small will cause
// the tree support to touch the model at more points, causing better overhang but making support harder to remove. // the tree support to touch the model at more points, causing better overhang but making support harder to remove.
def = this->add("support_tree_branch_distance", coFloat); def = this->add("support_tree_branch_distance", coFloat);
// TRN PrintSettings: #lmFIXME
def->label = L("Branch Distance"); def->label = L("Branch Distance");
def->category = L("Support material"); def->category = L("Support material");
// TRN PrintSettings: "Organic supports" > "Branch Distance"
def->tooltip = L("How far apart the branches need to be when they touch the model. " def->tooltip = L("How far apart the branches need to be when they touch the model. "
"Making this distance small will cause the tree support to touch the model at more points, " "Making this distance small will cause the tree support to touch the model at more points, "
"causing better overhang but making support harder to remove."); "causing better overhang but making support harder to remove.");
@ -2925,6 +2955,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("support_tree_top_rate", coPercent); def = this->add("support_tree_top_rate", coPercent);
def->label = L("Branch Density"); def->label = L("Branch Density");
def->category = L("Support material"); def->category = L("Support material");
// TRN PrintSettings: "Organic supports" > "Branch Density"
def->tooltip = L("Adjusts the density of the support structure used to generate the tips of the branches. " def->tooltip = L("Adjusts the density of the support structure used to generate the tips of the branches. "
"A higher value results in better overhangs but the supports are harder to remove, " "A higher value results in better overhangs but the supports are harder to remove, "
"thus it is recommended to enable top support interfaces instead of a high branch density value " "thus it is recommended to enable top support interfaces instead of a high branch density value "
@ -3013,8 +3044,8 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloatOrPercent(15, false)); def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
def = this->add("top_solid_layers", coInt); def = this->add("top_solid_layers", coInt);
//TRN To be shown in Print Settings "Top solid layers" //TRN Print Settings: "Top solid layers"
def->label = L("Top"); def->label = L_CONTEXT("Top", "Layers");
def->category = L("Layers and Perimeters"); def->category = L("Layers and Perimeters");
def->tooltip = L("Number of solid layers to generate on top surfaces."); def->tooltip = L("Number of solid layers to generate on top surfaces.");
def->full_label = L("Top solid layers"); def->full_label = L("Top solid layers");
@ -3022,8 +3053,7 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionInt(3)); def->set_default_value(new ConfigOptionInt(3));
def = this->add("top_solid_min_thickness", coFloat); def = this->add("top_solid_min_thickness", coFloat);
//TRN To be shown in Print Settings "Top solid layers" def->label = L_CONTEXT("Top", "Layers");
def->label = L("Top");
def->category = L("Layers and Perimeters"); def->category = L("Layers and Perimeters");
def->tooltip = L("The number of top solid layers is increased above top_solid_layers if necessary to satisfy " def->tooltip = L("The number of top solid layers is increased above top_solid_layers if necessary to satisfy "
"minimum thickness of top shell." "minimum thickness of top shell."
@ -3150,6 +3180,25 @@ void PrintConfigDef::init_fff_params()
def->min = 0.; def->min = 0.;
def->set_default_value(new ConfigOptionFloat(2.)); def->set_default_value(new ConfigOptionFloat(2.));
def = this->add("wipe_tower_cone_angle", coFloat);
def->label = L("Stabilization cone apex angle");
def->tooltip = L("Angle at the apex of the cone that is used to stabilize the wipe tower. "
"Larger angle means wider base.");
def->sidetext = L("°");
def->mode = comAdvanced;
def->min = 0.;
def->max = 90.;
def->set_default_value(new ConfigOptionFloat(0.));
def = this->add("wipe_tower_extra_spacing", coPercent);
def->label = L("Wipe tower purge lines spacing");
def->tooltip = L("Spacing of purge lines on the wipe tower.");
def->sidetext = L("%");
def->mode = comExpert;
def->min = 100.;
def->max = 300.;
def->set_default_value(new ConfigOptionPercent(100.));
def = this->add("wipe_into_infill", coBool); def = this->add("wipe_into_infill", coBool);
def->category = L("Wipe options"); def->category = L("Wipe options");
def->label = L("Wipe into this object's infill"); def->label = L("Wipe into this object's infill");
@ -3860,7 +3909,9 @@ void PrintConfigDef::init_sla_params()
def->tooltip = L("Support tree building strategy"); def->tooltip = L("Support tree building strategy");
def->set_enum<sla::SupportTreeType>( def->set_enum<sla::SupportTreeType>(
ConfigOptionEnum<sla::SupportTreeType>::get_enum_names(), ConfigOptionEnum<sla::SupportTreeType>::get_enum_names(),
{ L("Default"), L("Branching (experimental)") }); { L("Default"),
// TRN One of the "Support tree type"s on SLAPrintSettings : Supports
L("Branching (experimental)") });
// TODO: def->enum_def->labels[2] = L("Organic"); // TODO: def->enum_def->labels[2] = L("Organic");
def->mode = comSimple; def->mode = comSimple;
def->set_default_value(new ConfigOptionEnum(sla::SupportTreeType::Default)); def->set_default_value(new ConfigOptionEnum(sla::SupportTreeType::Default));
@ -4103,6 +4154,8 @@ static std::set<std::string> PrintConfigDef_ignore = {
"wall_add_middle_threshold", "wall_split_middle_threshold", "wall_add_middle_threshold", "wall_split_middle_threshold",
// Replaced by new concentric ensuring in 2.6.0-alpha5 // Replaced by new concentric ensuring in 2.6.0-alpha5
"ensure_vertical_shell_thickness", "ensure_vertical_shell_thickness",
// Disabled in 2.6.0-alpha6, this option is problematic
"infill_only_where_needed",
}; };
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
@ -4383,8 +4436,9 @@ std::string validate(const FullPrintConfig &cfg)
cfg.gcode_flavor.value != gcfMarlinLegacy && cfg.gcode_flavor.value != gcfMarlinLegacy &&
cfg.gcode_flavor.value != gcfMarlinFirmware && cfg.gcode_flavor.value != gcfMarlinFirmware &&
cfg.gcode_flavor.value != gcfMachinekit && cfg.gcode_flavor.value != gcfMachinekit &&
cfg.gcode_flavor.value != gcfRepetier) cfg.gcode_flavor.value != gcfRepetier &&
return "--use-firmware-retraction is only supported by Marlin, Smoothie, RepRapFirmware, Repetier and Machinekit firmware"; cfg.gcode_flavor.value != gcfKlipper)
return "--use-firmware-retraction is only supported by Marlin, Klipper, Smoothie, RepRapFirmware, Repetier and Machinekit firmware";
if (cfg.use_firmware_retraction.value) if (cfg.use_firmware_retraction.value)
for (unsigned char wipe : cfg.wipe.values) for (unsigned char wipe : cfg.wipe.values)
@ -4500,12 +4554,19 @@ std::string validate(const FullPrintConfig &cfg)
} }
case coFloats: case coFloats:
case coPercents: case coPercents:
for (double v : static_cast<const ConfigOptionVector<double>*>(opt)->values) {
const auto* vec = static_cast<const ConfigOptionVector<double>*>(opt);
for (size_t i = 0; i < vec->size(); ++i) {
if (vec->is_nil(i))
continue;
double v = vec->values[i];
if (v < optdef->min || v > optdef->max) { if (v < optdef->min || v > optdef->max) {
out_of_range = true; out_of_range = true;
break; break;
} }
}
break; break;
}
case coInt: case coInt:
{ {
auto *iopt = static_cast<const ConfigOptionInt*>(opt); auto *iopt = static_cast<const ConfigOptionInt*>(opt);
@ -4513,12 +4574,19 @@ std::string validate(const FullPrintConfig &cfg)
break; break;
} }
case coInts: case coInts:
for (int v : static_cast<const ConfigOptionVector<int>*>(opt)->values) {
const auto* vec = static_cast<const ConfigOptionVector<int>*>(opt);
for (size_t i = 0; i < vec->size(); ++i) {
if (vec->is_nil(i))
continue;
int v = vec->values[i];
if (v < optdef->min || v > optdef->max) { if (v < optdef->min || v > optdef->max) {
out_of_range = true; out_of_range = true;
break; break;
} }
}
break; break;
}
default:; default:;
} }
if (out_of_range) if (out_of_range)

View File

@ -32,7 +32,7 @@
namespace Slic3r { namespace Slic3r {
enum GCodeFlavor : unsigned char { enum GCodeFlavor : unsigned char {
gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfSailfish, gcfMach3, gcfMachinekit, gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfKlipper, gcfSailfish, gcfMach3, gcfMachinekit,
gcfSmoothie, gcfNoExtrusion, gcfSmoothie, gcfNoExtrusion,
}; };
@ -44,7 +44,7 @@ enum class MachineLimitsUsage {
}; };
enum PrintHostType { enum PrintHostType {
htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htMainSail
}; };
enum AuthorizationType { enum AuthorizationType {
@ -495,7 +495,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloatOrPercent, extrusion_width)) ((ConfigOptionFloatOrPercent, extrusion_width))
((ConfigOptionFloat, first_layer_acceleration_over_raft)) ((ConfigOptionFloat, first_layer_acceleration_over_raft))
((ConfigOptionFloatOrPercent, first_layer_speed_over_raft)) ((ConfigOptionFloatOrPercent, first_layer_speed_over_raft))
((ConfigOptionBool, infill_only_where_needed)) // ((ConfigOptionBool, infill_only_where_needed))
// Force the generation of solid shells between adjacent materials/volumes. // Force the generation of solid shells between adjacent materials/volumes.
((ConfigOptionBool, interface_shells)) ((ConfigOptionBool, interface_shells))
((ConfigOptionFloat, layer_height)) ((ConfigOptionFloat, layer_height))
@ -661,6 +661,7 @@ PRINT_CONFIG_CLASS_DEFINE(
PRINT_CONFIG_CLASS_DEFINE( PRINT_CONFIG_CLASS_DEFINE(
GCodeConfig, GCodeConfig,
((ConfigOptionBool, autoemit_temperature_commands))
((ConfigOptionString, before_layer_gcode)) ((ConfigOptionString, before_layer_gcode))
((ConfigOptionString, between_objects_gcode)) ((ConfigOptionString, between_objects_gcode))
((ConfigOptionFloats, deretract_speed)) ((ConfigOptionFloats, deretract_speed))
@ -815,6 +816,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionPoints, thumbnails)) ((ConfigOptionPoints, thumbnails))
((ConfigOptionEnum<GCodeThumbnailsFormat>, thumbnails_format)) ((ConfigOptionEnum<GCodeThumbnailsFormat>, thumbnails_format))
((ConfigOptionFloat, top_solid_infill_acceleration)) ((ConfigOptionFloat, top_solid_infill_acceleration))
((ConfigOptionFloat, travel_acceleration))
((ConfigOptionBools, wipe)) ((ConfigOptionBools, wipe))
((ConfigOptionBool, wipe_tower)) ((ConfigOptionBool, wipe_tower))
((ConfigOptionFloat, wipe_tower_x)) ((ConfigOptionFloat, wipe_tower_x))
@ -823,6 +825,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionFloat, wipe_tower_per_color_wipe)) ((ConfigOptionFloat, wipe_tower_per_color_wipe))
((ConfigOptionFloat, wipe_tower_rotation_angle)) ((ConfigOptionFloat, wipe_tower_rotation_angle))
((ConfigOptionFloat, wipe_tower_brim_width)) ((ConfigOptionFloat, wipe_tower_brim_width))
((ConfigOptionFloat, wipe_tower_cone_angle))
((ConfigOptionPercent, wipe_tower_extra_spacing))
((ConfigOptionFloat, wipe_tower_bridging)) ((ConfigOptionFloat, wipe_tower_bridging))
((ConfigOptionFloats, wiping_volumes_matrix)) ((ConfigOptionFloats, wiping_volumes_matrix))
((ConfigOptionFloats, wiping_volumes_extruders)) ((ConfigOptionFloats, wiping_volumes_extruders))

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,6 @@
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
//! macro used to mark string used at localization, return same string
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r { namespace Slic3r {
@ -499,7 +497,7 @@ void PrintObject::slice()
{ {
if (! this->set_started(posSlice)) if (! this->set_started(posSlice))
return; return;
m_print->set_status(10, L("Processing triangulated mesh")); m_print->set_status(10, _u8L("Processing triangulated mesh"));
std::vector<coordf_t> layer_height_profile; std::vector<coordf_t> layer_height_profile;
this->update_layer_height_profile(*this->model_object(), m_slicing_params, layer_height_profile); this->update_layer_height_profile(*this->model_object(), m_slicing_params, layer_height_profile);
m_print->throw_if_canceled(); m_print->throw_if_canceled();
@ -733,9 +731,9 @@ void PrintObject::slice_volumes()
if (m_config.xy_size_compensation.value != 0.f) { if (m_config.xy_size_compensation.value != 0.f) {
this->active_step_add_warning( this->active_step_add_warning(
PrintStateBase::WarningLevel::CRITICAL, PrintStateBase::WarningLevel::CRITICAL,
L("An object has enabled XY Size compensation which will not be used because it is also multi-material painted.\nXY Size " _u8L("An object has enabled XY Size compensation which will not be used because it is also multi-material painted.\nXY Size "
"compensation cannot be combined with multi-material painting.") + "compensation cannot be combined with multi-material painting.") +
"\n" + (L("Object name")) + ": " + this->model_object()->name); "\n" + (_u8L("Object name")) + ": " + this->model_object()->name);
} }
BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - MMU segmentation"; BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - MMU segmentation";

View File

@ -23,10 +23,6 @@
#include <libslic3r/MTUtils.hpp> #include <libslic3r/MTUtils.hpp>
#include <libslic3r/I18N.hpp> #include <libslic3r/I18N.hpp>
//! macro used to mark string used at localization,
//! return same string
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r { namespace Slic3r {
namespace sla { namespace sla {
@ -83,12 +79,12 @@ InteriorPtr generate_interior(const VoxelGrid &vgrid,
auto narrowb = 1.f; // voxel units (voxel count) auto narrowb = 1.f; // voxel units (voxel count)
if (ctl.stopcondition()) return {}; if (ctl.stopcondition()) return {};
else ctl.statuscb(0, L("Hollowing")); else ctl.statuscb(0, _u8L("Hollowing"));
auto gridptr = dilate_grid(vgrid, out_range, in_range); auto gridptr = dilate_grid(vgrid, out_range, in_range);
if (ctl.stopcondition()) return {}; if (ctl.stopcondition()) return {};
else ctl.statuscb(30, L("Hollowing")); else ctl.statuscb(30, _u8L("Hollowing"));
double iso_surface = D; double iso_surface = D;
if (D > EPSILON) { if (D > EPSILON) {
@ -103,7 +99,7 @@ InteriorPtr generate_interior(const VoxelGrid &vgrid,
} }
if (ctl.stopcondition()) return {}; if (ctl.stopcondition()) return {};
else ctl.statuscb(70, L("Hollowing")); else ctl.statuscb(70, _u8L("Hollowing"));
double adaptivity = 0.; double adaptivity = 0.;
InteriorPtr interior = InteriorPtr{new Interior{}}; InteriorPtr interior = InteriorPtr{new Interior{}};
@ -112,7 +108,7 @@ InteriorPtr generate_interior(const VoxelGrid &vgrid,
interior->gridptr = std::move(gridptr); interior->gridptr = std::move(gridptr);
if (ctl.stopcondition()) return {}; if (ctl.stopcondition()) return {};
else ctl.statuscb(100, L("Hollowing")); else ctl.statuscb(100, _u8L("Hollowing"));
interior->iso_surface = iso_surface; interior->iso_surface = iso_surface;
interior->thickness = offset; interior->thickness = offset;

View File

@ -21,9 +21,6 @@
#include "I18N.hpp" #include "I18N.hpp"
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
//! macro used to mark string used at localization,
//! return same string
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r { namespace sla { namespace Slic3r { namespace sla {
@ -530,7 +527,7 @@ std::string PadConfig::validate() const
if (brim_size_mm < MIN_BRIM_SIZE_MM || if (brim_size_mm < MIN_BRIM_SIZE_MM ||
bottom_offset() > brim_size_mm + wing_distance() || bottom_offset() > brim_size_mm + wing_distance() ||
get_waffle_offset(*this) <= MIN_BRIM_SIZE_MM) get_waffle_offset(*this) <= MIN_BRIM_SIZE_MM)
return L("Pad brim size is too small for the current configuration."); return _u8L("Pad brim size is too small for the current configuration.");
return ""; return "";
} }

View File

@ -16,13 +16,9 @@
#include <libslic3r/TriangleMeshSlicer.hpp> #include <libslic3r/TriangleMeshSlicer.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <libslic3r/I18N.hpp>
#include <libnest2d/tools/benchmark.h> #include <libnest2d/tools/benchmark.h>
//! macro used to mark string used at localization,
//! return same string
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r { namespace sla { namespace Slic3r { namespace sla {

View File

@ -2,6 +2,7 @@
#include "SLAPrintSteps.hpp" #include "SLAPrintSteps.hpp"
#include "CSGMesh/CSGMeshCopy.hpp" #include "CSGMesh/CSGMeshCopy.hpp"
#include "CSGMesh/PerformCSGMeshBooleans.hpp" #include "CSGMesh/PerformCSGMeshBooleans.hpp"
#include "format.hpp"
#include "Geometry.hpp" #include "Geometry.hpp"
#include "Thread.hpp" #include "Thread.hpp"
@ -23,7 +24,7 @@
//! macro used to mark string used at localization, //! macro used to mark string used at localization,
//! return same string //! return same string
#define L(s) Slic3r::I18N::translate(s) #define _u8L(s) Slic3r::I18N::translate(s)
namespace Slic3r { namespace Slic3r {
@ -543,7 +544,7 @@ std::string SLAPrint::validate(std::string*) const
if(supports_en && if(supports_en &&
mo->sla_points_status == sla::PointsStatus::UserModified && mo->sla_points_status == sla::PointsStatus::UserModified &&
mo->sla_support_points.empty()) mo->sla_support_points.empty())
return L("Cannot proceed without support points! " return _u8L("Cannot proceed without support points! "
"Add support points or disable support generation."); "Add support points or disable support generation.");
sla::SupportTreeConfig cfg = make_support_cfg(po->config()); sla::SupportTreeConfig cfg = make_support_cfg(po->config());
@ -554,13 +555,13 @@ std::string SLAPrint::validate(std::string*) const
sla::PadConfig::EmbedObject &builtinpad = padcfg.embed_object; sla::PadConfig::EmbedObject &builtinpad = padcfg.embed_object;
if(supports_en && !builtinpad.enabled && elv < cfg.head_fullwidth()) if(supports_en && !builtinpad.enabled && elv < cfg.head_fullwidth())
return L( return _u8L(
"Elevation is too low for object. Use the \"Pad around " "Elevation is too low for object. Use the \"Pad around "
"object\" feature to print the object without elevation."); "object\" feature to print the object without elevation.");
if(supports_en && builtinpad.enabled && if(supports_en && builtinpad.enabled &&
cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) { cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) {
return L( return _u8L(
"The endings of the support pillars will be deployed on the " "The endings of the support pillars will be deployed on the "
"gap between the object and the pad. 'Support base safety " "gap between the object and the pad. 'Support base safety "
"distance' has to be greater than the 'Pad object gap' " "distance' has to be greater than the 'Pad object gap' "
@ -576,18 +577,27 @@ std::string SLAPrint::validate(std::string*) const
double expt_cur = m_material_config.exposure_time.getFloat(); double expt_cur = m_material_config.exposure_time.getFloat();
if (expt_cur < expt_min || expt_cur > expt_max) if (expt_cur < expt_min || expt_cur > expt_max)
return L("Exposition time is out of printer profile bounds."); return _u8L("Exposition time is out of printer profile bounds.");
double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat(); double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat();
double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat(); double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat();
double iexpt_cur = m_material_config.initial_exposure_time.getFloat(); double iexpt_cur = m_material_config.initial_exposure_time.getFloat();
if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max) if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max)
return L("Initial exposition time is out of printer profile bounds."); return _u8L("Initial exposition time is out of printer profile bounds.");
return ""; return "";
} }
void SLAPrint::export_print(const std::string &fname, const ThumbnailsList &thumbnails, const std::string &projectname)
{
if (m_archiver)
m_archiver->export_print(fname, *this, thumbnails, projectname);
else {
throw ExportError(format(_u8L("Unknown archive format: %s"), m_printer_config.sla_archive_format.value));
}
}
bool SLAPrint::invalidate_step(SLAPrintStep step) bool SLAPrint::invalidate_step(SLAPrintStep step)
{ {
bool invalidated = Inherited::invalidate_step(step); bool invalidated = Inherited::invalidate_step(step);
@ -690,7 +700,7 @@ void SLAPrint::process()
} }
// If everything vent well // If everything vent well
m_report_status(*this, 100, L("Slicing done")); m_report_status(*this, 100, _u8L("Slicing done"));
#ifdef SLAPRINT_DO_BENCHMARK #ifdef SLAPRINT_DO_BENCHMARK
std::string csvbenchstr; std::string csvbenchstr;

View File

@ -546,10 +546,7 @@ public:
void export_print(const std::string &fname, void export_print(const std::string &fname,
const ThumbnailsList &thumbnails, const ThumbnailsList &thumbnails,
const std::string &projectname = "") const std::string &projectname = "");
{
m_archiver->export_print(fname, *this, thumbnails, projectname);
}
private: private:

View File

@ -32,9 +32,6 @@
#include <libnest2d/tools/benchmark.h> #include <libnest2d/tools/benchmark.h>
//! macro used to mark string used at localization,
//! return same string
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r { namespace Slic3r {
@ -54,14 +51,15 @@ const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS = {
std::string OBJ_STEP_LABELS(size_t idx) std::string OBJ_STEP_LABELS(size_t idx)
{ {
switch (idx) { switch (idx) {
case slaposAssembly: return L("Assembling model from parts"); // TRN Status of the SLA print calculation
case slaposHollowing: return L("Hollowing model"); case slaposAssembly: return _u8L("Assembling model from parts");
case slaposDrillHoles: return L("Drilling holes into model."); case slaposHollowing: return _u8L("Hollowing model");
case slaposObjectSlice: return L("Slicing model"); case slaposDrillHoles: return _u8L("Drilling holes into model.");
case slaposSupportPoints: return L("Generating support points"); case slaposObjectSlice: return _u8L("Slicing model");
case slaposSupportTree: return L("Generating support tree"); case slaposSupportPoints: return _u8L("Generating support points");
case slaposPad: return L("Generating pad"); case slaposSupportTree: return _u8L("Generating support tree");
case slaposSliceSupports: return L("Slicing supports"); case slaposPad: return _u8L("Generating pad");
case slaposSliceSupports: return _u8L("Slicing supports");
default:; default:;
} }
assert(false); assert(false);
@ -76,8 +74,8 @@ const std::array<unsigned, slapsCount> PRINT_STEP_LEVELS = {
std::string PRINT_STEP_LABELS(size_t idx) std::string PRINT_STEP_LABELS(size_t idx)
{ {
switch (idx) { switch (idx) {
case slapsMergeSlicesAndEval: return L("Merging slices and calculating statistics"); case slapsMergeSlicesAndEval: return _u8L("Merging slices and calculating statistics");
case slapsRasterize: return L("Rasterizing layers"); case slapsRasterize: return _u8L("Rasterizing layers");
default:; default:;
} }
assert(false); return "Out of bounds!"; assert(false); return "Out of bounds!";
@ -201,7 +199,13 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
m = csgmesh_merge_positive_parts(r); m = csgmesh_merge_positive_parts(r);
handled = true; handled = true;
} else if (csg::check_csgmesh_booleans(r) == r.end()) { } else if (csg::check_csgmesh_booleans(r) == r.end()) {
auto cgalmeshptr = csg::perform_csgmesh_booleans(r); MeshBoolean::cgal::CGALMeshPtr cgalmeshptr;
try {
cgalmeshptr = csg::perform_csgmesh_booleans(r);
} catch (...) {
// leaves cgalmeshptr as nullptr
}
if (cgalmeshptr) { if (cgalmeshptr) {
m = MeshBoolean::cgal::cgal_to_indexed_triangle_set(*cgalmeshptr); m = MeshBoolean::cgal::cgal_to_indexed_triangle_set(*cgalmeshptr);
handled = true; handled = true;
@ -252,14 +256,14 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
if (ret & static_cast<int>(sla::HollowMeshResult::FaultyMesh)) { if (ret & static_cast<int>(sla::HollowMeshResult::FaultyMesh)) {
po.active_step_add_warning( po.active_step_add_warning(
PrintStateBase::WarningLevel::NON_CRITICAL, PrintStateBase::WarningLevel::NON_CRITICAL,
L("Mesh to be hollowed is not suitable for hollowing (does not " _u8L("Mesh to be hollowed is not suitable for hollowing (does not "
"bound a volume).")); "bound a volume)."));
} }
if (ret & static_cast<int>(sla::HollowMeshResult::FaultyHoles)) { if (ret & static_cast<int>(sla::HollowMeshResult::FaultyHoles)) {
po.active_step_add_warning( po.active_step_add_warning(
PrintStateBase::WarningLevel::NON_CRITICAL, PrintStateBase::WarningLevel::NON_CRITICAL,
L("Unable to drill the current configuration of holes into the " _u8L("Unable to drill the current configuration of holes into the "
"model.")); "model."));
} }
@ -267,7 +271,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
if (ret & static_cast<int>(sla::HollowMeshResult::DrillingFailed)) { if (ret & static_cast<int>(sla::HollowMeshResult::DrillingFailed)) {
po.active_step_add_warning( po.active_step_add_warning(
PrintStateBase::WarningLevel::NON_CRITICAL, L( PrintStateBase::WarningLevel::NON_CRITICAL, _u8L(
"Drilling holes into the mesh failed. " "Drilling holes into the mesh failed. "
"This is usually caused by broken model. Try to fix it first.")); "This is usually caused by broken model. Try to fix it first."));
@ -276,7 +280,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
if (hole_fail) { if (hole_fail) {
po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
L("Failed to drill some holes into the model")); _u8L("Failed to drill some holes into the model"));
handled = false; handled = false;
} }
@ -286,7 +290,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
if (!handled) { // Last resort to voxelization. if (!handled) { // Last resort to voxelization.
po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
L("Can't perform full mesh booleans! " _u8L("Can't perform full mesh booleans! "
"Some parts of the print will be previewed with approximated meshes. " "Some parts of the print will be previewed with approximated meshes. "
"This does not affect the quality of slices or the physical print in any way.")); "This does not affect the quality of slices or the physical print in any way."));
m = generate_preview_vdb(po, step); m = generate_preview_vdb(po, step);
@ -507,7 +511,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
if(slindex_it == po.m_slice_index.end()) if(slindex_it == po.m_slice_index.end())
//TRN To be shown at the status bar on SLA slicing error. //TRN To be shown at the status bar on SLA slicing error.
throw Slic3r::RuntimeError( throw Slic3r::RuntimeError(
L("Slicing had to be stopped due to an internal error: " _u8L("Slicing had to be stopped due to an internal error: "
"Inconsistent slice index.")); "Inconsistent slice index."));
po.m_model_height_levels.clear(); po.m_model_height_levels.clear();
@ -688,7 +692,7 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
// Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass
// the update status to GLGizmoSlaSupports // the update status to GLGizmoSlaSupports
report_status(-1, L("Generating support points"), report_status(-1, _u8L("Generating support points"),
SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
} else { } else {
// There are either some points on the front-end, or the user // There are either some points on the front-end, or the user
@ -737,7 +741,7 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po)
auto rc = SlicingStatus::RELOAD_SCENE; auto rc = SlicingStatus::RELOAD_SCENE;
// This is to prevent "Done." being displayed during merged_mesh() // This is to prevent "Done." being displayed during merged_mesh()
report_status(-1, L("Visualizing supports")); report_status(-1, _u8L("Visualizing supports"));
BOOST_LOG_TRIVIAL(debug) << "Processed support point count " BOOST_LOG_TRIVIAL(debug) << "Processed support point count "
<< po.m_supportdata->input.pts.size(); << po.m_supportdata->input.pts.size();
@ -746,7 +750,7 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po)
if(po.support_mesh().empty()) if(po.support_mesh().empty())
BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty"; BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty";
report_status(-1, L("Visualizing supports"), rc); report_status(-1, _u8L("Visualizing supports"), rc);
} }
void SLAPrint::Steps::generate_pad(SLAPrintObject &po) { void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
@ -776,7 +780,7 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
if (!validate_pad(po.m_supportdata->pad_mesh.its, pcfg)) if (!validate_pad(po.m_supportdata->pad_mesh.its, pcfg))
throw Slic3r::SlicingError( throw Slic3r::SlicingError(
L("No pad can be generated for this model with the " _u8L("No pad can be generated for this model with the "
"current configuration")); "current configuration"));
} else if(po.m_supportdata) { } else if(po.m_supportdata) {
@ -784,7 +788,7 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
} }
throw_if_canceled(); throw_if_canceled();
report_status(-1, L("Visualizing supports"), SlicingStatus::RELOAD_SCENE); report_status(-1, _u8L("Visualizing supports"), SlicingStatus::RELOAD_SCENE);
} }
// Slicing the support geometries similarly to the model slicing procedure. // Slicing the support geometries similarly to the model slicing procedure.
@ -905,7 +909,7 @@ void SLAPrint::Steps::initialize_printer_input()
for(const SliceRecord& slicerecord : o->get_slice_index()) { for(const SliceRecord& slicerecord : o->get_slice_index()) {
if (!slicerecord.is_valid()) if (!slicerecord.is_valid())
throw Slic3r::SlicingError( throw Slic3r::SlicingError(
L("There are unprintable objects. Try to " _u8L("There are unprintable objects. Try to "
"adjust support settings to make the " "adjust support settings to make the "
"objects printable.")); "objects printable."));

View File

@ -49,10 +49,12 @@ struct FontProp
// used for move over model surface // used for move over model surface
// When not set value is zero and is not stored // When not set value is zero and is not stored
std::optional<float> distance; // [in mm] std::optional<float> distance; // [in mm]
// change up vector direction of font // Angle of rotation around emboss direction (Z axis)
// It is calculate on the fly from volume world transformation
// only StyleManager keep actual value for comparision with style
// When not set value is zero and is not stored // When not set value is zero and is not stored
std::optional<float> angle; // [in radians] std::optional<float> angle; // [in radians] form -Pi to Pi
// Parameter for True Type Font collections // Parameter for True Type Font collections
// Select index of font in collection // Select index of font in collection

View File

@ -1451,7 +1451,7 @@ static void generate_initial_areas(
// As a circle is round this length is identical for every axis as long as the 90 degrees angle between both remains. // As a circle is round this length is identical for every axis as long as the 90 degrees angle between both remains.
const coord_t circle_length_to_half_linewidth_change = config.min_radius < config.support_line_width ? const coord_t circle_length_to_half_linewidth_change = config.min_radius < config.support_line_width ?
config.min_radius / 2 : config.min_radius / 2 :
sqrt(sqr(config.min_radius) - sqr(config.min_radius - config.support_line_width / 2)); scale_(sqrt(sqr(unscale<double>(config.min_radius)) - sqr(unscale<double>(config.min_radius - config.support_line_width / 2))));
// Extra support offset to compensate for larger tip radiis. Also outset a bit more when z overwrites xy, because supporting something with a part of a support line is better than not supporting it at all. // Extra support offset to compensate for larger tip radiis. Also outset a bit more when z overwrites xy, because supporting something with a part of a support line is better than not supporting it at all.
//FIXME Vojtech: This is not sufficient for support enforcers to work. //FIXME Vojtech: This is not sufficient for support enforcers to work.
//FIXME There is no account for the support overhang angle. //FIXME There is no account for the support overhang angle.

View File

@ -34,6 +34,10 @@
// #define SLIC3R_DEBUG_SLICE_PROCESSING // #define SLIC3R_DEBUG_SLICE_PROCESSING
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
#define DEBUG_INTERSECTIONLINE
#endif
#if defined(SLIC3R_DEBUG) || defined(SLIC3R_DEBUG_SLICE_PROCESSING) #if defined(SLIC3R_DEBUG) || defined(SLIC3R_DEBUG_SLICE_PROCESSING)
#include "SVG.hpp" #include "SVG.hpp"
#endif #endif
@ -125,7 +129,7 @@ public:
}; };
uint32_t flags { 0 }; uint32_t flags { 0 };
#if DEBUG_INTERSECTIONLINE #ifdef DEBUG_INTERSECTIONLINE
enum class Source { enum class Source {
BottomPlane, BottomPlane,
TopPlane, TopPlane,
@ -1446,19 +1450,19 @@ static std::vector<Polygons> make_slab_loops(
for (const IntersectionLine &l : lines.at_slice[slice_below]) for (const IntersectionLine &l : lines.at_slice[slice_below])
if (l.edge_type != IntersectionLine::FacetEdgeType::Top) { if (l.edge_type != IntersectionLine::FacetEdgeType::Top) {
in.emplace_back(l); in.emplace_back(l);
#if DEBUG_INTERSECTIONLINE #ifdef DEBUG_INTERSECTIONLINE
in.back().source = IntersectionLine::Source::BottomPlane; in.back().source = IntersectionLine::Source::BottomPlane;
#endif // DEBUG_INTERSECTIONLINE #endif // DEBUG_INTERSECTIONLINE
} }
} }
{ {
// Edges in between slice_below and slice_above. // Edges in between slice_below and slice_above.
#if DEBUG_INTERSECTIONLINE #ifdef DEBUG_INTERSECTIONLINE
size_t old_size = in.size(); size_t old_size = in.size();
#endif // DEBUG_INTERSECTIONLINE #endif // DEBUG_INTERSECTIONLINE
// Edge IDs of end points on in-between lines that touch the layer above are already increased with num_edges. // Edge IDs of end points on in-between lines that touch the layer above are already increased with num_edges.
append(in, lines.between_slices[line_idx]); append(in, lines.between_slices[line_idx]);
#if DEBUG_INTERSECTIONLINE #ifdef DEBUG_INTERSECTIONLINE
for (auto it = in.begin() + old_size; it != in.end(); ++ it) { for (auto it = in.begin() + old_size; it != in.end(); ++ it) {
assert(it->edge_type == IntersectionLine::FacetEdgeType::Slab); assert(it->edge_type == IntersectionLine::FacetEdgeType::Slab);
it->source = IntersectionLine::Source::Slab; it->source = IntersectionLine::Source::Slab;
@ -1476,7 +1480,7 @@ static std::vector<Polygons> make_slab_loops(
l.edge_a_id += num_edges; l.edge_a_id += num_edges;
if (l.edge_b_id >= 0) if (l.edge_b_id >= 0)
l.edge_b_id += num_edges; l.edge_b_id += num_edges;
#if DEBUG_INTERSECTIONLINE #ifdef DEBUG_INTERSECTIONLINE
l.source = IntersectionLine::Source::TopPlane; l.source = IntersectionLine::Source::TopPlane;
#endif // DEBUG_INTERSECTIONLINE #endif // DEBUG_INTERSECTIONLINE
} }

View File

@ -6,10 +6,6 @@
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include "I18N.hpp" #include "I18N.hpp"
//! macro used to mark string used at localization,
//! return same string
#define L(s) Slic3r::I18N::translate(s)
#if defined(_MSC_VER) && _MSC_VER <= 1800 || __cplusplus < 201103L #if defined(_MSC_VER) && _MSC_VER <= 1800 || __cplusplus < 201103L
#define SLIC3R_NORETURN #define SLIC3R_NORETURN
#elif __cplusplus >= 201103L #elif __cplusplus >= 201103L
@ -24,7 +20,7 @@ public:
std::string formatted_errorstr() const std::string formatted_errorstr() const
{ {
return L("Error with zip archive") + " " + m_zipname + ": " + return _u8L("Error with zip archive") + " " + m_zipname + ": " +
get_errorstr(); get_errorstr();
} }

View File

@ -6,11 +6,7 @@
#include "boost/nowide/cstdio.hpp" #include "boost/nowide/cstdio.hpp"
#endif #endif
#include "I18N.hpp" #include "libslic3r/I18N.hpp"
//! macro used to mark string used at localization,
//! return same string
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r { namespace Slic3r {
@ -88,67 +84,67 @@ std::string MZ_Archive::get_errorstr(mz_zip_error mz_err)
case MZ_ZIP_NO_ERROR: case MZ_ZIP_NO_ERROR:
return "no error"; return "no error";
case MZ_ZIP_UNDEFINED_ERROR: case MZ_ZIP_UNDEFINED_ERROR:
return L("undefined error"); return _u8L("undefined error");
case MZ_ZIP_TOO_MANY_FILES: case MZ_ZIP_TOO_MANY_FILES:
return L("too many files"); return _u8L("too many files");
case MZ_ZIP_FILE_TOO_LARGE: case MZ_ZIP_FILE_TOO_LARGE:
return L("file too large"); return _u8L("file too large");
case MZ_ZIP_UNSUPPORTED_METHOD: case MZ_ZIP_UNSUPPORTED_METHOD:
return L("unsupported method"); return _u8L("unsupported method");
case MZ_ZIP_UNSUPPORTED_ENCRYPTION: case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
return L("unsupported encryption"); return _u8L("unsupported encryption");
case MZ_ZIP_UNSUPPORTED_FEATURE: case MZ_ZIP_UNSUPPORTED_FEATURE:
return L("unsupported feature"); return _u8L("unsupported feature");
case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
return L("failed finding central directory"); return _u8L("failed finding central directory");
case MZ_ZIP_NOT_AN_ARCHIVE: case MZ_ZIP_NOT_AN_ARCHIVE:
return L("not a ZIP archive"); return _u8L("not a ZIP archive");
case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
return L("invalid header or archive is corrupted"); return _u8L("invalid header or archive is corrupted");
case MZ_ZIP_UNSUPPORTED_MULTIDISK: case MZ_ZIP_UNSUPPORTED_MULTIDISK:
return L("unsupported multidisk archive"); return _u8L("unsupported multidisk archive");
case MZ_ZIP_DECOMPRESSION_FAILED: case MZ_ZIP_DECOMPRESSION_FAILED:
return L("decompression failed or archive is corrupted"); return _u8L("decompression failed or archive is corrupted");
case MZ_ZIP_COMPRESSION_FAILED: case MZ_ZIP_COMPRESSION_FAILED:
return L("compression failed"); return _u8L("compression failed");
case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
return L("unexpected decompressed size"); return _u8L("unexpected decompressed size");
case MZ_ZIP_CRC_CHECK_FAILED: case MZ_ZIP_CRC_CHECK_FAILED:
return L("CRC-32 check failed"); return _u8L("CRC-32 check failed");
case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
return L("unsupported central directory size"); return _u8L("unsupported central directory size");
case MZ_ZIP_ALLOC_FAILED: case MZ_ZIP_ALLOC_FAILED:
return L("allocation failed"); return _u8L("allocation failed");
case MZ_ZIP_FILE_OPEN_FAILED: case MZ_ZIP_FILE_OPEN_FAILED:
return L("file open failed"); return _u8L("file open failed");
case MZ_ZIP_FILE_CREATE_FAILED: case MZ_ZIP_FILE_CREATE_FAILED:
return L("file create failed"); return _u8L("file create failed");
case MZ_ZIP_FILE_WRITE_FAILED: case MZ_ZIP_FILE_WRITE_FAILED:
return L("file write failed"); return _u8L("file write failed");
case MZ_ZIP_FILE_READ_FAILED: case MZ_ZIP_FILE_READ_FAILED:
return L("file read failed"); return _u8L("file read failed");
case MZ_ZIP_FILE_CLOSE_FAILED: case MZ_ZIP_FILE_CLOSE_FAILED:
return L("file close failed"); return _u8L("file close failed");
case MZ_ZIP_FILE_SEEK_FAILED: case MZ_ZIP_FILE_SEEK_FAILED:
return L("file seek failed"); return _u8L("file seek failed");
case MZ_ZIP_FILE_STAT_FAILED: case MZ_ZIP_FILE_STAT_FAILED:
return L("file stat failed"); return _u8L("file stat failed");
case MZ_ZIP_INVALID_PARAMETER: case MZ_ZIP_INVALID_PARAMETER:
return L("invalid parameter"); return _u8L("invalid parameter");
case MZ_ZIP_INVALID_FILENAME: case MZ_ZIP_INVALID_FILENAME:
return L("invalid filename"); return _u8L("invalid filename");
case MZ_ZIP_BUF_TOO_SMALL: case MZ_ZIP_BUF_TOO_SMALL:
return L("buffer too small"); return _u8L("buffer too small");
case MZ_ZIP_INTERNAL_ERROR: case MZ_ZIP_INTERNAL_ERROR:
return L("internal error"); return _u8L("internal error");
case MZ_ZIP_FILE_NOT_FOUND: case MZ_ZIP_FILE_NOT_FOUND:
return L("file not found"); return _u8L("file not found");
case MZ_ZIP_ARCHIVE_TOO_LARGE: case MZ_ZIP_ARCHIVE_TOO_LARGE:
return L("archive is too large"); return _u8L("archive is too large");
case MZ_ZIP_VALIDATION_FAILED: case MZ_ZIP_VALIDATION_FAILED:
return L("validation failed"); return _u8L("validation failed");
case MZ_ZIP_WRITE_CALLBACK_FAILED: case MZ_ZIP_WRITE_CALLBACK_FAILED:
return L("write calledback failed"); return _u8L("write calledback failed");
default: default:
break; break;
} }

View File

@ -97,6 +97,8 @@ set(SLIC3R_GUI_SOURCES
GUI/GUI_Geometry.hpp GUI/GUI_Geometry.hpp
GUI/I18N.cpp GUI/I18N.cpp
GUI/I18N.hpp GUI/I18N.hpp
GUI/IconManager.cpp
GUI/IconManager.hpp
GUI/MainFrame.cpp GUI/MainFrame.cpp
GUI/MainFrame.hpp GUI/MainFrame.hpp
GUI/Plater.cpp GUI/Plater.cpp
@ -157,6 +159,8 @@ set(SLIC3R_GUI_SOURCES
GUI/RemovableDriveManager.hpp GUI/RemovableDriveManager.hpp
GUI/SendSystemInfoDialog.cpp GUI/SendSystemInfoDialog.cpp
GUI/SendSystemInfoDialog.hpp GUI/SendSystemInfoDialog.hpp
GUI/SurfaceDrag.cpp
GUI/SurfaceDrag.hpp
GUI/BonjourDialog.cpp GUI/BonjourDialog.cpp
GUI/BonjourDialog.hpp GUI/BonjourDialog.hpp
GUI/ButtonsDescription.cpp GUI/ButtonsDescription.cpp
@ -340,3 +344,6 @@ if (UNIX AND NOT APPLE)
target_include_directories(libslic3r_gui PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS}) target_include_directories(libslic3r_gui PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS})
target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES} fontconfig) target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES} fontconfig)
endif () endif ()
# Add a definition so that we can tell we are compiling slic3r.
target_compile_definitions(libslic3r_gui PRIVATE SLIC3R_CURRENTLY_COMPILING_GUI_MODULE)

View File

@ -109,26 +109,23 @@ Point Bed3D::point_projection(const Point& point) const
return m_polygon.point_projection(point); return m_polygon.point_projection(point);
} }
void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes, bool show_texture) void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_texture)
{ {
render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, show_axes, show_texture, false); render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, show_texture, false);
} }
void Bed3D::render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor) void Bed3D::render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor)
{ {
render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, false, false, true); render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, false, true);
} }
void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor,
bool show_axes, bool show_texture, bool picking) bool show_texture, bool picking)
{ {
m_scale_factor = scale_factor; m_scale_factor = scale_factor;
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
if (show_axes)
render_axes();
m_model.model.set_color(picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR); m_model.model.set_color(picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR);
switch (m_type) switch (m_type)
@ -314,9 +311,6 @@ std::tuple<Bed3D::Type, std::string, std::string> Bed3D::detect_type(const Point
void Bed3D::render_axes() void Bed3D::render_axes()
{ {
if (!m_show_axes)
return;
if (m_build_volume.valid()) if (m_build_volume.valid())
m_axes.render(Transform3d::Identity(), 0.25f); m_axes.render(Transform3d::Identity(), 0.25f);
} }

View File

@ -50,7 +50,6 @@ private:
CoordAxes m_axes; CoordAxes m_axes;
float m_scale_factor{ 1.0f }; float m_scale_factor{ 1.0f };
bool m_show_axes{ true };
public: public:
Bed3D() = default; Bed3D() = default;
@ -78,9 +77,8 @@ public:
bool contains(const Point& point) const; bool contains(const Point& point) const;
Point point_projection(const Point& point) const; Point point_projection(const Point& point) const;
void toggle_show_axes() { m_show_axes = !m_show_axes; } void render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_texture);
void render_axes();
void render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes, bool show_texture);
void render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor); void render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor);
private: private:
@ -91,8 +89,7 @@ private:
void init_contourlines(); void init_contourlines();
static std::tuple<Type, std::string, std::string> detect_type(const Pointfs& shape); static std::tuple<Type, std::string, std::string> detect_type(const Pointfs& shape);
void render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, void render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor,
bool show_axes, bool show_texture, bool picking); bool show_texture, bool picking);
void render_axes();
void render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture); void render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture);
void render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix); void render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix);
void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix); void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix);

View File

@ -480,11 +480,11 @@ int GLVolumeCollection::load_object_volume(
#if ENABLE_OPENGL_ES #if ENABLE_OPENGL_ES
int GLVolumeCollection::load_wipe_tower_preview( int GLVolumeCollection::load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, float height, float pos_x, float pos_y, float width, float depth, float height, float cone_angle,
float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh) float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh)
#else #else
int GLVolumeCollection::load_wipe_tower_preview( int GLVolumeCollection::load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, float height, float pos_x, float pos_y, float width, float depth, float height, float cone_angle,
float rotation_angle, bool size_unknown, float brim_width) float rotation_angle, bool size_unknown, float brim_width)
#endif // ENABLE_OPENGL_ES #endif // ENABLE_OPENGL_ES
{ {
@ -544,6 +544,21 @@ int GLVolumeCollection::load_wipe_tower_preview(
brim_mesh.translate(-brim_width, -brim_width, 0.f); brim_mesh.translate(-brim_width, -brim_width, 0.f);
mesh.merge(brim_mesh); mesh.merge(brim_mesh);
// Now the stabilization cone and its base.
const auto [R, scale_x] = WipeTower::get_wipe_tower_cone_base(width, height, depth, cone_angle);
if (R > 0.) {
TriangleMesh cone_mesh(its_make_cone(R, height));
cone_mesh.scale(Vec3f(1.f/scale_x, 1.f, 1.f));
TriangleMesh disk_mesh(its_make_cylinder(R, brim_height));
disk_mesh.scale(Vec3f(1. / scale_x, 1., 1.)); // Now it matches the base, which may be elliptic.
disk_mesh.scale(Vec3f(1.f + scale_x*brim_width/R, 1.f + brim_width/R, 1.f)); // Scale so the brim is not deformed.
cone_mesh.merge(disk_mesh);
cone_mesh.translate(width / 2., depth / 2., 0.);
mesh.merge(cone_mesh);
}
volumes.emplace_back(new GLVolume(color)); volumes.emplace_back(new GLVolume(color));
GLVolume& v = *volumes.back(); GLVolume& v = *volumes.back();
#if ENABLE_OPENGL_ES #if ENABLE_OPENGL_ES
@ -564,6 +579,71 @@ int GLVolumeCollection::load_wipe_tower_preview(
return int(volumes.size() - 1); return int(volumes.size() - 1);
} }
// Load SLA auxiliary GLVolumes (for support trees or pad).
// This function produces volumes for multiple instances in a single shot,
// as some object specific mesh conversions may be expensive.
void GLVolumeCollection::load_object_auxiliary(
const SLAPrintObject* print_object,
int obj_idx,
// pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone
size_t timestamp)
{
if (print_object->get_mesh_to_print() == nullptr)
return;
const Transform3d mesh_trafo_inv = print_object->trafo().inverse();
auto add_volume = [this, &instances, timestamp](int obj_idx, int inst_idx, const ModelInstance& model_instance, SLAPrintObjectStep step,
const TriangleMesh& mesh, const ColorRGBA& color, std::optional<const TriangleMesh> convex_hull = std::nullopt) {
if (mesh.empty())
return;
GLVolume& v = *this->volumes.emplace_back(new GLVolume(color));
#if ENABLE_SMOOTH_NORMALS
v.model.init_from(mesh, true);
#else
v.model.init_from(mesh);
v.model.set_color(color);
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<const TriangleMesh>(mesh));
#endif // ENABLE_SMOOTH_NORMALS
v.composite_id = GLVolume::CompositeID(obj_idx, -int(step), inst_idx);
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
if (convex_hull.has_value())
v.set_convex_hull(*convex_hull);
v.is_modifier = false;
v.shader_outside_printer_detection_enabled = (step == slaposSupportTree);
v.set_instance_transformation(model_instance.get_transformation());
};
// Get the support mesh.
if (milestone == SLAPrintObjectStep::slaposSupportTree) {
TriangleMesh supports_mesh = print_object->support_mesh();
if (!supports_mesh.empty()) {
supports_mesh.transform(mesh_trafo_inv);
TriangleMesh convex_hull = supports_mesh.convex_hull_3d();
for (const std::pair<size_t, size_t>& instance_idx : instances) {
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposSupportTree, supports_mesh, GLVolume::SLA_SUPPORT_COLOR, convex_hull);
}
}
}
// Get the pad mesh.
if (milestone == SLAPrintObjectStep::slaposPad) {
TriangleMesh pad_mesh = print_object->pad_mesh();
if (!pad_mesh.empty()) {
pad_mesh.transform(mesh_trafo_inv);
TriangleMesh convex_hull = pad_mesh.convex_hull_3d();
for (const std::pair<size_t, size_t>& instance_idx : instances) {
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposPad, pad_mesh, GLVolume::SLA_PAD_COLOR, convex_hull);
}
}
}
}
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba) GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba)
{ {
GLVolume* out = new_nontoolpath_volume(rgba); GLVolume* out = new_nontoolpath_volume(rgba);

View File

@ -396,12 +396,22 @@ public:
#if ENABLE_OPENGL_ES #if ENABLE_OPENGL_ES
int load_wipe_tower_preview( int load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr); float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr);
#else #else
int load_wipe_tower_preview( int load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width); float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width);
#endif // ENABLE_OPENGL_ES #endif // ENABLE_OPENGL_ES
// Load SLA auxiliary GLVolumes (for support trees or pad).
void load_object_auxiliary(
const SLAPrintObject* print_object,
int obj_idx,
// pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone
size_t timestamp);
GLVolume* new_toolpath_volume(const ColorRGBA& rgba); GLVolume* new_toolpath_volume(const ColorRGBA& rgba);
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba); GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba);
// Render the volumes by OpenGL. // Render the volumes by OpenGL.

View File

@ -41,9 +41,9 @@ void AboutDialogLogo::onRepaint(wxEvent &event)
// CopyrightsDialog // CopyrightsDialog
// ----------------------------------------- // -----------------------------------------
CopyrightsDialog::CopyrightsDialog() CopyrightsDialog::CopyrightsDialog()
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, from_u8((boost::format("%1% - %2%") : DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, format_wxstr("%1% - %2%"
% (wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME) , wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME
% _utf8(L("Portions copyright"))).str()), , _L("Portions copyright")),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{ {
this->SetFont(wxGetApp().normal_font()); this->SetFont(wxGetApp().normal_font());
@ -141,7 +141,6 @@ wxString CopyrightsDialog::get_html_text()
const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue())); const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
const wxString copyright_str = _L("Copyright") + "&copy; "; const wxString copyright_str = _L("Copyright") + "&copy; ";
// TRN "Slic3r _is licensed under the_ License"
const wxString header_str = _L("License agreements of all following programs (libraries) are part of application license agreement"); const wxString header_str = _L("License agreements of all following programs (libraries) are part of application license agreement");
wxString text = wxString::Format( wxString text = wxString::Format(
@ -211,7 +210,7 @@ void CopyrightsDialog::onCloseDialog(wxEvent &)
} }
AboutDialog::AboutDialog() AboutDialog::AboutDialog()
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, from_u8((boost::format(_utf8(L("About %s"))) % (wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME)).str()), wxDefaultPosition, : DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, format_wxstr(_L("About %s"), wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME), wxDefaultPosition,
wxDefaultSize, /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) wxDefaultSize, /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{ {
SetFont(wxGetApp().normal_font()); SetFont(wxGetApp().normal_font());
@ -267,14 +266,13 @@ AboutDialog::AboutDialog()
int size[] = {fs,fs,fs,fs,fs,fs,fs}; int size[] = {fs,fs,fs,fs,fs,fs,fs};
m_html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); m_html->SetFonts(font.GetFaceName(), font.GetFaceName(), size);
m_html->SetBorders(2); m_html->SetBorders(2);
const std::string copyright_str = _utf8(L("Copyright")); const wxString copyright_str = _L("Copyright");
// TRN "Slic3r _is licensed under the_ License" // TRN AboutDialog: "Slic3r %1% GNU Affero General Public License"
const std::string is_lecensed_str = _utf8(L("is licensed under the")); const wxString is_lecensed_str = _L("is licensed under the");
const std::string license_str = _utf8(L("GNU Affero General Public License, version 3")); const wxString license_str = _L("GNU Affero General Public License, version 3");
const std::string based_on_str = _utf8(L("PrusaSlicer is based on Slic3r by Alessandro Ranellucci and the RepRap community.")); const wxString based_on_str = _L("PrusaSlicer is based on Slic3r by Alessandro Ranellucci and the RepRap community.");
const std::string contributors_str = _utf8(L("Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and numerous others.")); const wxString contributors_str = _L("Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and numerous others.");
const auto text = from_u8( const auto text = format_wxstr(
(boost::format(
"<html>" "<html>"
"<body bgcolor= %1% link= %2%>" "<body bgcolor= %1% link= %2%>"
"<font color=%3%>" "<font color=%3%>"
@ -288,12 +286,12 @@ AboutDialog::AboutDialog()
"%9%" "%9%"
"</font>" "</font>"
"</body>" "</body>"
"</html>") % bgr_clr_str % text_clr_str % text_clr_str "</html>", bgr_clr_str, text_clr_str, text_clr_str
% copyright_str % copyright_str , copyright_str, copyright_str
% is_lecensed_str , is_lecensed_str
% license_str , license_str
% based_on_str , based_on_str
% contributors_str).str()); , contributors_str);
m_html->SetPage(text); m_html->SetPage(text);
vsizer->Add(m_html, 1, wxEXPAND | wxBOTTOM, 10); vsizer->Add(m_html, 1, wxEXPAND | wxBOTTOM, 10);
m_html->Bind(wxEVT_HTML_LINK_CLICKED, &AboutDialog::onLinkClicked, this); m_html->Bind(wxEVT_HTML_LINK_CLICKED, &AboutDialog::onLinkClicked, this);

View File

@ -76,10 +76,10 @@ std::pair<std::string, bool> SlicingProcessCompletedEvent::format_error_message(
try { try {
this->rethrow_exception(); this->rethrow_exception();
} catch (const std::bad_alloc &ex) { } catch (const std::bad_alloc &ex) {
wxString errmsg = GUI::from_u8((boost::format(_utf8(L("%s has encountered an error. It was likely caused by running out of memory. " error = GUI::format(_L("%s has encountered an error. It was likely caused by running out of memory. "
"If you are sure you have enough RAM on your system, this may also be a bug and we would " "If you are sure you have enough RAM on your system, this may also be a bug and we would "
"be glad if you reported it."))) % SLIC3R_APP_NAME).str()); "be glad if you reported it."), SLIC3R_APP_NAME);
error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what()); error += "\n\n" + std::string(ex.what());
} catch (const HardCrash &ex) { } catch (const HardCrash &ex) {
error = GUI::format(_L("PrusaSlicer has encountered a fatal error: \"%1%\""), ex.what()) + "\n\n" + error = GUI::format(_L("PrusaSlicer has encountered a fatal error: \"%1%\""), ex.what()) + "\n\n" +
_u8L("Please save your project and restart PrusaSlicer. " _u8L("Please save your project and restart PrusaSlicer. "
@ -159,7 +159,7 @@ void BackgroundSlicingProcess::process_fff()
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id)); wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
prepare_upload(); prepare_upload();
} else { } else {
m_print->set_status(100, _utf8(L("Slicing complete"))); m_print->set_status(100, _u8L("Slicing complete"));
} }
this->set_step_done(bspsGCodeFinalize); this->set_step_done(bspsGCodeFinalize);
} }
@ -180,12 +180,12 @@ void BackgroundSlicingProcess::process_sla()
m_sla_print->export_print(export_path, thumbnails); m_sla_print->export_print(export_path, thumbnails);
m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str()); m_print->set_status(100, GUI::format(_L("Masked SLA file exported to %1%"), export_path));
} else if (! m_upload_job.empty()) { } else if (! m_upload_job.empty()) {
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id)); wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
prepare_upload(); prepare_upload();
} else { } else {
m_print->set_status(100, _utf8(L("Slicing complete"))); m_print->set_status(100, _u8L("Slicing complete"));
} }
this->set_step_done(bspsGCodeFinalize); this->set_step_done(bspsGCodeFinalize);
} }
@ -649,7 +649,7 @@ bool BackgroundSlicingProcess::invalidate_all_steps()
// Copy the final G-code to target location (possibly a SD card, if it is a removable media, then verify that the file was written without an error). // Copy the final G-code to target location (possibly a SD card, if it is a removable media, then verify that the file was written without an error).
void BackgroundSlicingProcess::finalize_gcode() void BackgroundSlicingProcess::finalize_gcode()
{ {
m_print->set_status(95, _utf8(L("Running post-processing scripts"))); m_print->set_status(95, _u8L("Running post-processing scripts"));
// Perform the final post-processing of the export path by applying the print statistics over the file name. // Perform the final post-processing of the export path by applying the print statistics over the file name.
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path); std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
@ -680,32 +680,32 @@ void BackgroundSlicingProcess::finalize_gcode()
catch (...) catch (...)
{ {
remove_post_processed_temp_file(); remove_post_processed_temp_file();
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code."))); throw Slic3r::ExportError(_u8L("Unknown error occured during exporting G-code."));
} }
switch (copy_ret_val) { switch (copy_ret_val) {
case CopyFileResult::SUCCESS: break; // no error case CopyFileResult::SUCCESS: break; // no error
case CopyFileResult::FAIL_COPY_FILE: case CopyFileResult::FAIL_COPY_FILE:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str()); throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"), error_message));
break; break;
case CopyFileResult::FAIL_FILES_DIFFERENT: case CopyFileResult::FAIL_FILES_DIFFERENT:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str()); throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."), export_path));
break; break;
case CopyFileResult::FAIL_RENAMING: case CopyFileResult::FAIL_RENAMING:
throw Slic3r::ExportError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str()); throw Slic3r::ExportError(GUI::format(_L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."), export_path));
break; break;
case CopyFileResult::FAIL_CHECK_ORIGIN_NOT_OPENED: case CopyFileResult::FAIL_CHECK_ORIGIN_NOT_OPENED:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % output_path % export_path).str()); throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."), output_path, export_path));
break; break;
case CopyFileResult::FAIL_CHECK_TARGET_NOT_OPENED: case CopyFileResult::FAIL_CHECK_TARGET_NOT_OPENED:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str()); throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."), export_path));
break; break;
default: default:
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code."))); throw Slic3r::ExportError(_u8L("Unknown error occured during exporting G-code."));
BOOST_LOG_TRIVIAL(error) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << "."; BOOST_LOG_TRIVIAL(error) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
break; break;
} }
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str()); m_print->set_status(100, GUI::format(_L("G-code file exported to %1%"), export_path));
} }
// A print host upload job has been scheduled, enqueue it to the printhost job queue // A print host upload job has been scheduled, enqueue it to the printhost job queue
@ -716,10 +716,10 @@ void BackgroundSlicingProcess::prepare_upload()
/ boost::filesystem::unique_path("." SLIC3R_APP_KEY ".upload.%%%%-%%%%-%%%%-%%%%"); / boost::filesystem::unique_path("." SLIC3R_APP_KEY ".upload.%%%%-%%%%-%%%%-%%%%");
if (m_print == m_fff_print) { if (m_print == m_fff_print) {
m_print->set_status(95, _utf8(L("Running post-processing scripts"))); m_print->set_status(95, _u8L("Running post-processing scripts"));
std::string error_message; std::string error_message;
if (copy_file(m_temp_output_path, source_path.string(), error_message) != SUCCESS) if (copy_file(m_temp_output_path, source_path.string(), error_message) != SUCCESS)
throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed"))); throw Slic3r::RuntimeError(_u8L("Copying of the temporary G-code to the output G-code failed"));
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
// Make a copy of the source path, as run_post_process_scripts() is allowed to change it when making a copy of the source file // Make a copy of the source path, as run_post_process_scripts() is allowed to change it when making a copy of the source file
// (not here, but when the final target is a file). // (not here, but when the final target is a file).
@ -735,7 +735,7 @@ void BackgroundSlicingProcess::prepare_upload()
m_sla_print->export_print(source_path.string(),thumbnails, m_upload_job.upload_data.upload_path.filename().string()); m_sla_print->export_print(source_path.string(),thumbnails, m_upload_job.upload_data.upload_path.filename().string());
} }
m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str()); m_print->set_status(100, GUI::format(_L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"), m_upload_job.printhost->get_host()));
m_upload_job.upload_data.source_path = std::move(source_path); m_upload_job.upload_data.source_path = std::move(source_path);

View File

@ -128,6 +128,9 @@ void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup)
} }
} }
BedShapeDialog::BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {}
void BedShapeDialog::build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model) void BedShapeDialog::build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model)
{ {
SetFont(wxGetApp().normal_font()); SetFont(wxGetApp().normal_font());

View File

@ -5,7 +5,6 @@
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#include "2DBed.hpp" #include "2DBed.hpp"
#include "I18N.hpp"
#include <libslic3r/BuildVolume.hpp> #include <libslic3r/BuildVolume.hpp>
@ -93,8 +92,7 @@ class BedShapeDialog : public DPIDialog
{ {
BedShapePanel* m_panel; BedShapePanel* m_panel;
public: public:
BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")), BedShapeDialog(wxWindow* parent);
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {}
void build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model); void build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model);

View File

@ -224,14 +224,14 @@ void BonjourDialog::on_timer(wxTimerEvent &)
// explicitly (wxTimerEvent should not be created by user code). // explicitly (wxTimerEvent should not be created by user code).
void BonjourDialog::on_timer_process() void BonjourDialog::on_timer_process()
{ {
const auto search_str = _utf8(L("Searching for devices")); const auto search_str = _L("Searching for devices");
if (timer_state > 0) { if (timer_state > 0) {
const std::string dots(timer_state, '.'); const std::string dots(timer_state, '.');
label->SetLabel(GUI::from_u8((boost::format("%1% %2%") % search_str % dots).str())); label->SetLabel(search_str + dots);
timer_state = (timer_state) % 3 + 1; timer_state = (timer_state) % 3 + 1;
} else { } else {
label->SetLabel(GUI::from_u8((boost::format("%1%: %2%") % search_str % (_utf8(L("Finished"))+".")).str())); label->SetLabel(search_str + ": " + _L("Finished") + ".");
timer->Stop(); timer->Stop();
} }
} }

View File

@ -160,7 +160,7 @@ void FillSizerWithModeColorDescriptions(
wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(9, 5, 5); wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(9, 5, 5);
sizer->Add(grid_sizer, 0, wxEXPAND); sizer->Add(grid_sizer, 0, wxEXPAND);
const std::vector<wxString> names = { _L("Simple"), _CTX(L_CONTEXT("Advanced", "Mode"), "Mode"), _L("Expert") }; const std::vector<wxString> names = { _L("Simple"), _CTX("Advanced", "Mode"), _L("Expert") };
for (size_t mode = 0; mode < names.size(); ++mode) { for (size_t mode = 0; mode < names.size(); ++mode) {
wxColour& color = mode_palette[mode]; wxColour& color = mode_palette[mode];

View File

@ -256,7 +256,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
bool have_default_acceleration = config->opt_float("default_acceleration") > 0; bool have_default_acceleration = config->opt_float("default_acceleration") > 0;
for (auto el : { "perimeter_acceleration", "infill_acceleration", "top_solid_infill_acceleration", for (auto el : { "perimeter_acceleration", "infill_acceleration", "top_solid_infill_acceleration",
"solid_infill_acceleration", "external_perimeter_acceleration" "solid_infill_acceleration", "external_perimeter_acceleration",
"bridge_acceleration", "first_layer_acceleration" }) "bridge_acceleration", "first_layer_acceleration" })
toggle_field(el, have_default_acceleration); toggle_field(el, have_default_acceleration);
@ -319,8 +319,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field("standby_temperature_delta", have_ooze_prevention); toggle_field("standby_temperature_delta", have_ooze_prevention);
bool have_wipe_tower = config->opt_bool("wipe_tower"); bool have_wipe_tower = config->opt_bool("wipe_tower");
for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_cone_angle",
"wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming" }) "wipe_tower_extra_spacing", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming" })
toggle_field(el, have_wipe_tower); toggle_field(el, have_wipe_tower);
toggle_field("avoid_crossing_curled_overhangs", !config->opt_bool("avoid_crossing_perimeters")); toggle_field("avoid_crossing_curled_overhangs", !config->opt_bool("avoid_crossing_perimeters"));

View File

@ -9,6 +9,7 @@
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "MainFrame.hpp" #include "MainFrame.hpp"
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
#include "format.hpp"
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -89,10 +90,10 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve
} }
if (! compatible) { if (! compatible) {
text += "<p align=\"right\">" + from_u8((boost::format(_utf8(L("Incompatible with this %s"))) % SLIC3R_APP_NAME).str()) + "</p>"; text += "<p align=\"right\">" + format_wxstr(_L("Incompatible with this %s"), SLIC3R_APP_NAME) + "</p>";
} }
else if (! snapshot_active) else if (! snapshot_active)
text += "<p align=\"right\"><a href=\"" + snapshot.id + "\">" + _(L("Activate")) + "</a></p>"; text += "<p align=\"right\"><a href=\"" + snapshot.id + "\">" + _L("Activate") + "</a></p>";
text += "</td>"; text += "</td>";
text += "</tr>"; text += "</tr>";
return text; return text;

View File

@ -56,6 +56,7 @@
#include "MsgDialog.hpp" #include "MsgDialog.hpp"
#include "UnsavedChangesDialog.hpp" #include "UnsavedChangesDialog.hpp"
#include "slic3r/Utils/AppUpdater.hpp" #include "slic3r/Utils/AppUpdater.hpp"
#include "slic3r/GUI/I18N.hpp"
#if defined(__linux__) && defined(__WXGTK3__) #if defined(__linux__) && defined(__WXGTK3__)
#define wxLinux_gtk3 true #define wxLinux_gtk3 true
@ -288,7 +289,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
const auto &variant = model.variants[i]; const auto &variant = model.variants[i];
const auto label = model.technology == ptFFF const auto label = model.technology == ptFFF
? from_u8((boost::format("%1% %2% %3%") % variant.name % _utf8(L("mm")) % _utf8(L("nozzle"))).str()) ? format_wxstr("%1% %2% %3%", variant.name, _L("mm"), _L("nozzle"))
: from_u8(model.name); : from_u8(model.name);
if (i == 1) { if (i == 1) {
@ -508,17 +509,17 @@ void ConfigWizardPage::append_spacer(int space)
// Wizard pages // Wizard pages
PageWelcome::PageWelcome(ConfigWizard *parent) PageWelcome::PageWelcome(ConfigWizard *parent)
: ConfigWizardPage(parent, from_u8((boost::format( : ConfigWizardPage(parent, format_wxstr(
#ifdef __APPLE__ #ifdef __APPLE__
_utf8(L("Welcome to the %s Configuration Assistant")) _L("Welcome to the %s Configuration Assistant")
#else #else
_utf8(L("Welcome to the %s Configuration Wizard")) _L("Welcome to the %s Configuration Wizard")
#endif #endif
) % SLIC3R_APP_NAME).str()), _L("Welcome")) , SLIC3R_APP_NAME), _L("Welcome"))
, welcome_text(append_text(from_u8((boost::format( , welcome_text(append_text(format_wxstr(
_utf8(L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print."))) _L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")
% SLIC3R_APP_NAME , SLIC3R_APP_NAME
% _utf8(ConfigWizard::name())).str()) , _(ConfigWizard::name()))
)) ))
, cbox_reset(append( , cbox_reset(append(
new wxCheckBox(this, wxID_ANY, _L("Remove user profiles (a snapshot will be taken beforehand)")) new wxCheckBox(this, wxID_ANY, _L("Remove user profiles (a snapshot will be taken beforehand)"))
@ -576,7 +577,7 @@ PagePrinters::PagePrinters(ConfigWizard *parent,
continue; continue;
} }
const auto picker_title = family.empty() ? wxString() : from_u8((boost::format(_utf8(L("%s Family"))) % family).str()); const auto picker_title = family.empty() ? wxString() : format_wxstr(_L("%s Family"), family);
auto *picker = new PrinterPicker(this, vendor, picker_title, MAX_COLS, *appconfig, filter); auto *picker = new PrinterPicker(this, vendor, picker_title, MAX_COLS, *appconfig, filter);
picker->Bind(EVT_PRINTER_PICK, [this, appconfig](const PrinterPickerEvent &evt) { picker->Bind(EVT_PRINTER_PICK, [this, appconfig](const PrinterPickerEvent &evt) {
@ -786,11 +787,14 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector<std::s
const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue())); const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
wxString text; wxString text;
if (materials->technology == T_FFF && template_shown) { if (materials->technology == T_FFF && template_shown) {
// TRN ConfigWizard: Materials : "%1%" = "Filaments"/"SLA materials"
text = format_wxstr(_L("%1% visible for <b>(\"Template\")</b> printer are universal profiles available for all printers. These might not be compatible with your printer."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials")); text = format_wxstr(_L("%1% visible for <b>(\"Template\")</b> printer are universal profiles available for all printers. These might not be compatible with your printer."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
} else { } else {
// TRN ConfigWizard: Materials : "%1%" = "Filaments"/"SLA materials"
wxString first_line = format_wxstr(_L("%1% marked with <b>*</b> are <b>not</b> compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials")); wxString first_line = format_wxstr(_L("%1% marked with <b>*</b> are <b>not</b> compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
if (all_printers) { if (all_printers) {
// TRN ConfigWizard: Materials : "%1%" = "filament"/"SLA material"
wxString second_line = format_wxstr(_L("All installed printers are compatible with the selected %1%."), materials->technology == T_FFF ? _L("filament") : _L("SLA material")); wxString second_line = format_wxstr(_L("All installed printers are compatible with the selected %1%."), materials->technology == T_FFF ? _L("filament") : _L("SLA material"));
text = wxString::Format( text = wxString::Format(
"<html>" "<html>"
@ -1368,7 +1372,7 @@ Worker::Worker(wxWindow* parent)
button_path->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { button_path->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) {
boost::filesystem::path chosen_dest(boost::nowide::narrow(m_input_path->GetValue())); boost::filesystem::path chosen_dest(boost::nowide::narrow(m_input_path->GetValue()));
wxDirDialog dialog(m_parent, L("Choose folder:"), chosen_dest.string() ); wxDirDialog dialog(m_parent, _L("Choose folder") + ":", chosen_dest.string() );
if (dialog.ShowModal() == wxID_OK) if (dialog.ShowModal() == wxID_OK)
this->m_input_path->SetValue(dialog.GetPath()); this->m_input_path->SetValue(dialog.GetPath());
}); });
@ -1420,11 +1424,12 @@ PageDownloader::PageDownloader(ConfigWizard* parent)
box_allow_downloads->SetValue(box_allow_value); box_allow_downloads->SetValue(box_allow_value);
append(box_allow_downloads); append(box_allow_downloads);
append_text(wxString::Format(_L( // TRN ConfigWizard : Downloader : %1% = "PrusaSlicer"
"If enabled, %s registers to start on custom URL on www.printables.com." append_text(format_wxstr(_L(
" You will be able to use button with %s logo to open models in this %s." "If enabled, %1% registers to start on custom URL on www.printables.com."
" You will be able to use button with %1% logo to open models in this %1%."
" The model will be downloaded into folder you choose bellow." " The model will be downloaded into folder you choose bellow."
), SLIC3R_APP_NAME, SLIC3R_APP_NAME, SLIC3R_APP_NAME)); ), SLIC3R_APP_NAME));
#ifdef __linux__ #ifdef __linux__
append_text(wxString::Format(_L( append_text(wxString::Format(_L(
@ -1455,7 +1460,7 @@ bool DownloaderUtils::Worker::perform_register(const std::string& path_override/
chosen_dest = aux_dest; chosen_dest = aux_dest;
ec.clear(); ec.clear();
if (chosen_dest.empty() || !boost::filesystem::is_directory(chosen_dest, ec) || ec) { if (chosen_dest.empty() || !boost::filesystem::is_directory(chosen_dest, ec) || ec) {
std::string err_msg = GUI::format("%1%\n\n%2%",_L("Chosen directory for downloads does not Exists.") ,chosen_dest.string()); std::string err_msg = GUI::format("%1%\n\n%2%",_L("Chosen directory for downloads does not exist.") ,chosen_dest.string());
BOOST_LOG_TRIVIAL(error) << err_msg; BOOST_LOG_TRIVIAL(error) << err_msg;
show_error(m_parent, err_msg); show_error(m_parent, err_msg);
return false; return false;
@ -1752,6 +1757,7 @@ void PageBedShape::apply_custom_config(DynamicPrintConfig &config)
} }
PageBuildVolume::PageBuildVolume(ConfigWizard* parent) PageBuildVolume::PageBuildVolume(ConfigWizard* parent)
// TRN ConfigWizard : Size of possible print, related on printer size
: ConfigWizardPage(parent, _L("Build Volume"), _L("Build Volume"), 1) : ConfigWizardPage(parent, _L("Build Volume"), _L("Build Volume"), 1)
, build_volume(new DiamTextCtrl(this)) , build_volume(new DiamTextCtrl(this))
{ {
@ -1792,7 +1798,7 @@ PageBuildVolume::PageBuildVolume(ConfigWizard* parent)
}, build_volume->GetId()); }, build_volume->GetId());
auto* sizer_volume = new wxFlexGridSizer(3, 5, 5); auto* sizer_volume = new wxFlexGridSizer(3, 5, 5);
auto* text_volume = new wxStaticText(this, wxID_ANY, _L("Max print height:")); auto* text_volume = new wxStaticText(this, wxID_ANY, _L("Max print height") + ":");
auto* unit_volume = new wxStaticText(this, wxID_ANY, _L("mm")); auto* unit_volume = new wxStaticText(this, wxID_ANY, _L("mm"));
sizer_volume->AddGrowableCol(0, 1); sizer_volume->AddGrowableCol(0, 1);
sizer_volume->Add(text_volume, 0, wxALIGN_CENTRE_VERTICAL); sizer_volume->Add(text_volume, 0, wxALIGN_CENTRE_VERTICAL);
@ -1828,7 +1834,7 @@ PageDiameters::PageDiameters(ConfigWizard *parent)
append_text(_L("Enter the diameter of your printer's hot end nozzle.")); append_text(_L("Enter the diameter of your printer's hot end nozzle."));
auto *sizer_nozzle = new wxFlexGridSizer(3, 5, 5); auto *sizer_nozzle = new wxFlexGridSizer(3, 5, 5);
auto *text_nozzle = new wxStaticText(this, wxID_ANY, _L("Nozzle Diameter:")); auto *text_nozzle = new wxStaticText(this, wxID_ANY, _L("Nozzle Diameter") + ":");
auto *unit_nozzle = new wxStaticText(this, wxID_ANY, _L("mm")); auto *unit_nozzle = new wxStaticText(this, wxID_ANY, _L("mm"));
sizer_nozzle->AddGrowableCol(0, 1); sizer_nozzle->AddGrowableCol(0, 1);
sizer_nozzle->Add(text_nozzle, 0, wxALIGN_CENTRE_VERTICAL); sizer_nozzle->Add(text_nozzle, 0, wxALIGN_CENTRE_VERTICAL);
@ -1842,7 +1848,7 @@ PageDiameters::PageDiameters(ConfigWizard *parent)
append_text(_L("Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average.")); append_text(_L("Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average."));
auto *sizer_filam = new wxFlexGridSizer(3, 5, 5); auto *sizer_filam = new wxFlexGridSizer(3, 5, 5);
auto *text_filam = new wxStaticText(this, wxID_ANY, _L("Filament Diameter:")); auto *text_filam = new wxStaticText(this, wxID_ANY, _L("Filament Diameter") + ":");
auto *unit_filam = new wxStaticText(this, wxID_ANY, _L("mm")); auto *unit_filam = new wxStaticText(this, wxID_ANY, _L("mm"));
sizer_filam->AddGrowableCol(0, 1); sizer_filam->AddGrowableCol(0, 1);
sizer_filam->Add(text_filam, 0, wxALIGN_CENTRE_VERTICAL); sizer_filam->Add(text_filam, 0, wxALIGN_CENTRE_VERTICAL);
@ -1934,7 +1940,7 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent)
append_text(_L("A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have no heated bed.")); append_text(_L("A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have no heated bed."));
auto *sizer_bed = new wxFlexGridSizer(3, 5, 5); auto *sizer_bed = new wxFlexGridSizer(3, 5, 5);
auto *text_bed = new wxStaticText(this, wxID_ANY, _L("Bed Temperature:")); auto *text_bed = new wxStaticText(this, wxID_ANY, _L("Bed Temperature") + ":");
auto *unit_bed = new wxStaticText(this, wxID_ANY, _L("°C")); auto *unit_bed = new wxStaticText(this, wxID_ANY, _L("°C"));
sizer_bed->AddGrowableCol(0, 1); sizer_bed->AddGrowableCol(0, 1);
sizer_bed->Add(text_bed, 0, wxALIGN_CENTRE_VERTICAL); sizer_bed->Add(text_bed, 0, wxALIGN_CENTRE_VERTICAL);

View File

@ -42,17 +42,23 @@ void CoordAxes::render(const Transform3d& trafo, float emission_factor)
shader->start_using(); shader->start_using();
shader->set_uniform("emission_factor", emission_factor); shader->set_uniform("emission_factor", emission_factor);
// Scale the axes if the camera is close to them to avoid issues
// such as https://github.com/prusa3d/PrusaSlicer/issues/9483
const Camera& camera = wxGetApp().plater()->get_camera();
Transform3d scale_tr = Transform3d::Identity();
scale_tr.scale(std::min(1., camera.get_inv_zoom() * 10.));
// x axis // x axis
m_arrow.set_color(ColorRGBA::X()); m_arrow.set_color(ColorRGBA::X());
render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * Geometry::rotation_transform({ 0.0, 0.5 * M_PI, 0.0 })); render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * Geometry::rotation_transform({ 0.0, 0.5 * M_PI, 0.0 }) * scale_tr);
// y axis // y axis
m_arrow.set_color(ColorRGBA::Y()); m_arrow.set_color(ColorRGBA::Y());
render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * Geometry::rotation_transform({ -0.5 * M_PI, 0.0, 0.0 })); render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * Geometry::rotation_transform({ -0.5 * M_PI, 0.0, 0.0 }) * scale_tr);
// z axis // z axis
m_arrow.set_color(ColorRGBA::Z()); m_arrow.set_color(ColorRGBA::Z());
render_axis(*shader, trafo * Geometry::translation_transform(m_origin)); render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * scale_tr);
shader->stop_using(); shader->stop_using();
if (curr_shader != nullptr) if (curr_shader != nullptr)

View File

@ -106,7 +106,7 @@ Control::Control( wxWindow *parent,
m_cog_icon_dim = m_bmp_cog.GetWidth(); m_cog_icon_dim = m_bmp_cog.GetWidth();
m_selection = ssUndef; m_selection = ssUndef;
m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume printing"))); m_ticks.set_pause_print_msg(_u8L("Place bearings in slots and resume printing"));
m_ticks.set_extruder_colors(&m_extruder_colors); m_ticks.set_extruder_colors(&m_extruder_colors);
// slider events // slider events

View File

@ -178,7 +178,7 @@ void Downloader::on_error(wxCommandEvent& event)
BOOST_LOG_TRIVIAL(error) << "Download error: " << event.GetString(); BOOST_LOG_TRIVIAL(error) << "Download error: " << event.GetString();
NotificationManager* ntf_mngr = wxGetApp().notification_manager(); NotificationManager* ntf_mngr = wxGetApp().notification_manager();
ntf_mngr->set_download_URL_error(id, boost::nowide::narrow(event.GetString())); ntf_mngr->set_download_URL_error(id, boost::nowide::narrow(event.GetString()));
show_error(nullptr, format_wxstr(L"%1%\n%2%", _L("The download has failed:"), event.GetString())); show_error(nullptr, format_wxstr(L"%1%\n%2%", _L("The download has failed") + ":", event.GetString()));
} }
void Downloader::on_complete(wxCommandEvent& event) void Downloader::on_complete(wxCommandEvent& event)
{ {

View File

@ -190,6 +190,7 @@ void FileGet::priv::get_perform()
//assert(file != NULL); //assert(file != NULL);
if (file == NULL) { if (file == NULL) {
wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_ERROR); wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_ERROR);
// TRN %1% = file path
evt->SetString(GUI::format_wxstr(_L("Can't create file at %1%."), temp_path_wstring)); evt->SetString(GUI::format_wxstr(_L("Can't create file at %1%."), temp_path_wstring));
evt->SetInt(m_id); evt->SetInt(m_id);
m_evt_handler->QueueEvent(evt); m_evt_handler->QueueEvent(evt);

View File

@ -226,7 +226,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
} }
wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label); wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label);
show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str())); show_error(m_parent, format_wxstr(_L("%s doesn't support percentage"), label));
set_value(double_to_string(m_opt.min), true); set_value(double_to_string(m_opt.min), true);
m_value = double(m_opt.min); m_value = double(m_opt.min);
break; break;
@ -299,7 +299,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
// Workaroud to avoid of using of the % for first layer height // Workaroud to avoid of using of the % for first layer height
// see https://github.com/prusa3d/PrusaSlicer/issues/7418 // see https://github.com/prusa3d/PrusaSlicer/issues/7418
wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label); wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label);
show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str())); show_error(m_parent, format_wxstr(_L("%s doesn't support percentage"), label));
const wxString stVal = double_to_string(0.01, 2); const wxString stVal = double_to_string(0.01, 2);
set_value(stVal, true); set_value(stVal, true);
m_value = into_u8(stVal);; m_value = into_u8(stVal);;
@ -341,9 +341,10 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm"; const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm";
const wxString stVal = double_to_string(val, 2); const wxString stVal = double_to_string(val, 2);
const wxString msg_text = from_u8((boost::format(_utf8(L("Do you mean %s%% instead of %s %s?\n" // TRN %1% = Value, %2% = units
"Select YES if you want to change this value to %s%%, \n" const wxString msg_text = format_wxstr(_L("Do you mean %1%%% instead of %1% %2%?\n"
"or NO if you are sure that %s %s is a correct value."))) % stVal % stVal % sidetext % stVal % stVal % sidetext).str()); "Select YES if you want to change this value to %1%%%, \n"
"or NO if you are sure that %1% %2% is a correct value."), stVal, sidetext);
WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO); WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO);
if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) { if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) {
set_value(from_u8((boost::format("%s%%") % stVal).str()), false/*true*/); set_value(from_u8((boost::format("%s%%") % stVal).str()), false/*true*/);

View File

@ -166,11 +166,11 @@ ArchiveViewCtrl::~ArchiveViewCtrl()
} }
} }
FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* archive, std::vector<boost::filesystem::path>& selected_paths) FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* archive, std::vector<std::pair<boost::filesystem::path, size_t>>& selected_paths_w_size)
: DPIDialog(parent_window, wxID_ANY, _(L("Archive preview")), wxDefaultPosition, : DPIDialog(parent_window, wxID_ANY, _(L("Archive preview")), wxDefaultPosition,
wxSize(45 * wxGetApp().em_unit(), 40 * wxGetApp().em_unit()), wxSize(45 * wxGetApp().em_unit(), 40 * wxGetApp().em_unit()),
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX) wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX)
, m_selected_paths (selected_paths) , m_selected_paths_w_size (selected_paths_w_size)
{ {
#ifdef _WIN32 #ifdef _WIN32
wxGetApp().UpdateDarkUI(this); wxGetApp().UpdateDarkUI(this);
@ -206,14 +206,14 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar
reduce_stack(stack, struct_size); reduce_stack(stack, struct_size);
} }
if (!file.has_extension() && stack.size() == struct_size) if (!file.has_extension() && stack.size() == struct_size)
stack.push_back(avc->get_model()->AddFile((stack.empty() ? std::shared_ptr<ArchiveViewNode>(nullptr) : stack.back()), GUI::format_wxstr(file.filename().string()), true)); // filename string to wstring? stack.push_back(avc->get_model()->AddFile((stack.empty() ? std::shared_ptr<ArchiveViewNode>(nullptr) : stack.back()), boost::nowide::widen(file.filename().string()), true)); // filename string to wstring?
return struct_size + 1; return struct_size + 1;
}; };
const std::regex pattern_drop(".*[.](stl|obj|amf|3mf|prusa|step|stp)", std::regex::icase); const std::regex pattern_drop(".*[.](stl|obj|amf|3mf|prusa|step|stp)", std::regex::icase);
mz_uint num_entries = mz_zip_reader_get_num_files(archive); mz_uint num_entries = mz_zip_reader_get_num_files(archive);
mz_zip_archive_file_stat stat; mz_zip_archive_file_stat stat;
std::vector<boost::filesystem::path> filtered_entries; std::vector<std::pair<boost::filesystem::path, size_t>> filtered_entries; // second is unzipped size
for (mz_uint i = 0; i < num_entries; ++i) { for (mz_uint i = 0; i < num_entries; ++i) {
if (mz_zip_reader_file_stat(archive, i, &stat)) { if (mz_zip_reader_file_stat(archive, i, &stat)) {
std::string extra(1024, 0); std::string extra(1024, 0);
@ -223,7 +223,7 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar
path = boost::filesystem::path(extra.substr(0, extra_size)); path = boost::filesystem::path(extra.substr(0, extra_size));
} else { } else {
wxString wname = boost::nowide::widen(stat.m_filename); wxString wname = boost::nowide::widen(stat.m_filename);
std::string name = GUI::format(wname); std::string name = boost::nowide::narrow(wname);
path = boost::filesystem::path(name); path = boost::filesystem::path(name);
} }
assert(!path.empty()); assert(!path.empty());
@ -232,22 +232,25 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar
// filter out MACOS specific hidden files // filter out MACOS specific hidden files
if (boost::algorithm::starts_with(path.string(), "__MACOSX")) if (boost::algorithm::starts_with(path.string(), "__MACOSX"))
continue; continue;
filtered_entries.emplace_back(std::move(path)); filtered_entries.emplace_back(std::move(path), stat.m_uncomp_size);
} }
} }
// sorting files will help adjust_stack function to not create multiple same folders // sorting files will help adjust_stack function to not create multiple same folders
std::sort(filtered_entries.begin(), filtered_entries.end(), [](const boost::filesystem::path& p1, const boost::filesystem::path& p2){ return p1.string() > p2.string(); }); std::sort(filtered_entries.begin(), filtered_entries.end(), [](const std::pair<boost::filesystem::path, size_t>& p1, const std::pair<boost::filesystem::path, size_t>& p2){ return p1.first.string() < p2.first.string(); });
size_t entry_count = 0; size_t entry_count = 0;
size_t depth = 1; size_t depth = 1;
for (const boost::filesystem::path& path : filtered_entries) for (const auto& entry : filtered_entries)
{ {
const boost::filesystem::path& path = entry.first;
std::shared_ptr<ArchiveViewNode> parent(nullptr); std::shared_ptr<ArchiveViewNode> parent(nullptr);
depth = std::max(depth, adjust_stack(path, stack)); depth = std::max(depth, adjust_stack(path, stack));
if (!stack.empty()) if (!stack.empty())
parent = stack.back(); parent = stack.back();
if (std::regex_match(path.extension().string(), pattern_drop)) { // this leaves out non-compatible files if (std::regex_match(path.extension().string(), pattern_drop)) { // this leaves out non-compatible files
m_avc->get_model()->AddFile(parent, GUI::format_wxstr(path.filename().string()), false)->set_fullpath(/*std::move(path)*/path); // filename string to wstring? std::shared_ptr<ArchiveViewNode> new_node = m_avc->get_model()->AddFile(parent, boost::nowide::widen(path.filename().string()), false);
new_node->set_fullpath(/*std::move(path)*/path); // filename string to wstring?
new_node->set_size(entry.second);
entry_count++; entry_count++;
} }
} }
@ -305,12 +308,12 @@ void FileArchiveDialog::on_open_button()
wxDataViewItemArray top_items; wxDataViewItemArray top_items;
m_avc->get_model()->GetChildren(wxDataViewItem(nullptr), top_items); m_avc->get_model()->GetChildren(wxDataViewItem(nullptr), top_items);
std::function<void(ArchiveViewNode*)> deep_fill = [&paths = m_selected_paths, &deep_fill](ArchiveViewNode* node){ std::function<void(ArchiveViewNode*)> deep_fill = [&paths = m_selected_paths_w_size, &deep_fill](ArchiveViewNode* node){
if (node == nullptr) if (node == nullptr)
return; return;
if (node->get_children().empty()) { if (node->get_children().empty()) {
if (node->get_toggle()) if (node->get_toggle())
paths.emplace_back(node->get_fullpath()); paths.emplace_back(node->get_fullpath(), node->get_size());
} else { } else {
for (std::shared_ptr<ArchiveViewNode> child : node->get_children()) for (std::shared_ptr<ArchiveViewNode> child : node->get_children())
deep_fill(child.get()); deep_fill(child.get());

View File

@ -33,6 +33,8 @@ public:
void set_is_folder(bool is_folder) { m_folder = is_folder; } void set_is_folder(bool is_folder) { m_folder = is_folder; }
void set_fullpath(boost::filesystem::path path) { m_fullpath = path; } void set_fullpath(boost::filesystem::path path) { m_fullpath = path; }
boost::filesystem::path get_fullpath() const { return m_fullpath; } boost::filesystem::path get_fullpath() const { return m_fullpath; }
void set_size(size_t size) { m_size = size; }
size_t get_size() const { return m_size; }
private: private:
wxString m_name; wxString m_name;
@ -43,6 +45,7 @@ private:
bool m_folder { false }; bool m_folder { false };
boost::filesystem::path m_fullpath; boost::filesystem::path m_fullpath;
bool m_container { false }; bool m_container { false };
size_t m_size { 0 };
}; };
class ArchiveViewModel : public wxDataViewModel class ArchiveViewModel : public wxDataViewModel
@ -100,7 +103,7 @@ protected:
class FileArchiveDialog : public DPIDialog class FileArchiveDialog : public DPIDialog
{ {
public: public:
FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* archive, std::vector<boost::filesystem::path>& selected_paths); FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* archive, std::vector<std::pair<boost::filesystem::path, size_t>>& selected_paths_w_size);
protected: protected:
void on_dpi_changed(const wxRect& suggested_rect) override; void on_dpi_changed(const wxRect& suggested_rect) override;
@ -109,7 +112,9 @@ protected:
void on_all_button(); void on_all_button();
void on_none_button(); void on_none_button();
std::vector<boost::filesystem::path>& m_selected_paths; // chosen files are written into this vector and returned to caller via reference.
// path in archive and decompressed size. The size can be used to distinguish between files with same path.
std::vector<std::pair<boost::filesystem::path,size_t>>& m_selected_paths_w_size;
ArchiveViewCtrl* m_avc; ArchiveViewCtrl* m_avc;
}; };

View File

@ -2253,7 +2253,7 @@ void GCodeViewer::load_shells(const Print& print)
const WipeTowerData& wipe_tower_data = print.wipe_tower_data(extruders_count); const WipeTowerData& wipe_tower_data = print.wipe_tower_data(extruders_count);
const float depth = wipe_tower_data.depth; const float depth = wipe_tower_data.depth;
const float brim_width = wipe_tower_data.brim_width; const float brim_width = wipe_tower_data.brim_width;
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_cone_angle, config.wipe_tower_rotation_angle,
!print.is_step_done(psWipeTower), brim_width); !print.is_step_done(psWipeTower), brim_width);
} }
} }

View File

@ -728,7 +728,7 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
return owner.model_instance_id == id; return owner.model_instance_id == id;
}); });
if (it != owners.end()) if (it != owners.end())
it->print_order = std::string((_(L("Seq."))).ToUTF8()) + "#: " + std::to_string(i + 1); it->print_order = _u8L("Seq.") + "#: " + std::to_string(i + 1);
} }
} }
@ -1405,7 +1405,6 @@ void GLCanvas3D::enable_legend_texture(bool enable)
void GLCanvas3D::enable_picking(bool enable) void GLCanvas3D::enable_picking(bool enable)
{ {
m_picking_enabled = enable; m_picking_enabled = enable;
m_selection.set_mode(Selection::Instance);
} }
void GLCanvas3D::enable_moving(bool enable) void GLCanvas3D::enable_moving(bool enable)
@ -1571,8 +1570,9 @@ void GLCanvas3D::render()
_render_objects(GLVolumeCollection::ERenderType::Opaque); _render_objects(GLVolumeCollection::ERenderType::Opaque);
_render_sla_slices(); _render_sla_slices();
_render_selection(); _render_selection();
_render_bed_axes();
if (is_looking_downward) if (is_looking_downward)
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), false, true); _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), false);
if (!m_main_toolbar.is_enabled()) if (!m_main_toolbar.is_enabled())
_render_gcode(); _render_gcode();
_render_objects(GLVolumeCollection::ERenderType::Transparent); _render_objects(GLVolumeCollection::ERenderType::Transparent);
@ -1595,7 +1595,7 @@ void GLCanvas3D::render()
_render_selection_sidebar_hints(); _render_selection_sidebar_hints();
_render_current_gizmo(); _render_current_gizmo();
if (!is_looking_downward) if (!is_looking_downward)
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), true, true); _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), true);
#if ENABLE_RAYCAST_PICKING_DEBUG #if ENABLE_RAYCAST_PICKING_DEBUG
if (m_picking_enabled && !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging()) if (m_picking_enabled && !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging())
@ -1877,6 +1877,15 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
size_t volume_idx; size_t volume_idx;
}; };
// SLA steps to pull the preview meshes for.
typedef std::array<SLAPrintObjectStep, 3> SLASteps;
SLASteps sla_steps = { slaposDrillHoles, slaposSupportTree, slaposPad };
struct SLASupportState {
std::array<PrintStateBase::StateWithTimeStamp, std::tuple_size<SLASteps>::value> step;
};
// State of the sla_steps for all SLAPrintObjects.
std::vector<SLASupportState> sla_support_state;
std::vector<size_t> instance_ids_selected; std::vector<size_t> instance_ids_selected;
std::vector<size_t> map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1)); std::vector<size_t> map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1));
std::vector<GLVolumeState> deleted_volumes; std::vector<GLVolumeState> deleted_volumes;
@ -1902,6 +1911,37 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
} }
} }
if (printer_technology == ptSLA) {
const SLAPrint* sla_print = this->sla_print();
#ifndef NDEBUG
// Verify that the SLAPrint object is synchronized with m_model.
check_model_ids_equal(*m_model, sla_print->model());
#endif // NDEBUG
sla_support_state.reserve(sla_print->objects().size());
for (const SLAPrintObject* print_object : sla_print->objects()) {
SLASupportState state;
for (size_t istep = 0; istep < sla_steps.size(); ++istep) {
state.step[istep] = print_object->step_state_with_timestamp(sla_steps[istep]);
if (state.step[istep].state == PrintStateBase::State::Done) {
std::shared_ptr<const indexed_triangle_set> m = print_object->get_mesh_to_print();
if (m == nullptr || m->empty())
// Consider the DONE step without a valid mesh as invalid for the purpose
// of mesh visualization.
state.step[istep].state = PrintStateBase::State::Invalidated;
else {
for (const ModelInstance* model_instance : print_object->model_object()->instances) {
// Only the instances, which are currently printable, will have the SLA support structures kept.
// The instances outside the print bed will have the GLVolumes of their support structures released.
if (model_instance->is_printable())
aux_volume_state.emplace_back(state.step[istep].timestamp, model_instance->id());
}
}
}
}
sla_support_state.emplace_back(state);
}
}
std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower); std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower);
std::sort(aux_volume_state.begin(), aux_volume_state.end(), model_volume_state_lower); std::sort(aux_volume_state.begin(), aux_volume_state.end(), model_volume_state_lower);
// Release all ModelVolume based GLVolumes not found in the current Model. Find the GLVolume of a hollowed mesh. // Release all ModelVolume based GLVolumes not found in the current Model. Find the GLVolume of a hollowed mesh.
@ -2016,6 +2056,75 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
} }
} }
if (printer_technology == ptSLA) {
size_t idx = 0;
const SLAPrint *sla_print = this->sla_print();
std::vector<double> shift_zs(m_model->objects.size(), 0);
double relative_correction_z = sla_print->relative_correction().z();
if (relative_correction_z <= EPSILON)
relative_correction_z = 1.;
for (const SLAPrintObject *print_object : sla_print->objects()) {
SLASupportState &state = sla_support_state[idx ++];
const ModelObject *model_object = print_object->model_object();
// Find an index of the ModelObject
int object_idx;
// There may be new SLA volumes added to the scene for this print_object.
// Find the object index of this print_object in the Model::objects list.
auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object);
assert(it != sla_print->model().objects.end());
object_idx = it - sla_print->model().objects.begin();
// Cache the Z offset to be applied to all volumes with this object_idx.
shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z;
// Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene.
// pairs of <instance_idx, print_instance_idx>
std::vector<std::pair<size_t, size_t>> instances[std::tuple_size<SLASteps>::value];
for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) {
const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx];
// Find index of ModelInstance corresponding to this SLAPrintObject::Instance.
auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(),
[&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; });
assert(it != model_object->instances.end());
int instance_idx = it - model_object->instances.begin();
for (size_t istep = 0; istep < sla_steps.size(); ++istep) {
if (state.step[istep].state == PrintStateBase::State::Done) {
// Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id);
if (it->new_geometry()) {
// This can be an SLA support structure that should not be rendered (in case someone used undo
// to revert to before it was generated). If that's the case, we should not generate anything.
if (model_object->sla_points_status != sla::PointsStatus::NoPoints)
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
else
shift_zs[object_idx] = 0.;
}
else {
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
}
}
}
}
for (size_t istep = 0; istep < sla_steps.size(); ++istep) {
if (!instances[istep].empty())
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
}
}
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
for (GLVolume* volume : m_volumes.volumes) {
const ModelObject* model_object = (volume->object_idx() < (int)m_model->objects.size()) ? m_model->objects[volume->object_idx()] : nullptr;
if (model_object != nullptr && model_object->instances[volume->instance_idx()]->is_printable()) {
const SLAPrintObject* po = sla_print->get_print_object_by_model_object_id(model_object->id());
if (po != nullptr)
volume->set_sla_shift_z(po->get_current_elevation() / sla_print->relative_correction().z());
}
}
}
if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) { if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) {
// Should the wipe tower be visualized ? // Should the wipe tower be visualized ?
unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size(); unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size();
@ -2032,17 +2141,18 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
const float w = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_width"))->value; const float w = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_width"))->value;
const float a = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_rotation_angle"))->value; const float a = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_rotation_angle"))->value;
const float bw = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_brim_width"))->value; const float bw = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_brim_width"))->value;
const float ca = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_cone_angle"))->value;
const Print *print = m_process->fff_print(); const Print *print = m_process->fff_print();
const float depth = print->wipe_tower_data(extruders_count).depth; const float depth = print->wipe_tower_data(extruders_count).depth;
#if ENABLE_OPENGL_ES #if ENABLE_OPENGL_ES
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), x, y, w, depth, (float)height, ca, a, !print->is_step_done(psWipeTower),
bw, &m_wipe_tower_mesh); bw, &m_wipe_tower_mesh);
#else #else
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), x, y, w, depth, (float)height, ca, a, !print->is_step_done(psWipeTower),
bw); bw);
#endif // ENABLE_OPENGL_ES #endif // ENABLE_OPENGL_ES
if (volume_idx_wipe_tower_old != -1) if (volume_idx_wipe_tower_old != -1)
@ -2051,7 +2161,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
} }
update_volumes_colors_by_extruder(); update_volumes_colors_by_extruder();
// Update selection indices based on the old/new GLVolumeCollection. // Update selection indices based on the old/new GLVolumeCollection.
if (m_selection.get_mode() == Selection::Instance) if (m_selection.get_mode() == Selection::Instance)
m_selection.instances_changed(instance_ids_selected); m_selection.instances_changed(instance_ids_selected);
else else
@ -2347,15 +2457,6 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
#endif /* __APPLE__ */ #endif /* __APPLE__ */
post_event(SimpleEvent(EVT_GLTOOLBAR_COPY)); post_event(SimpleEvent(EVT_GLTOOLBAR_COPY));
break; break;
#ifdef __APPLE__
case 'd':
case 'D':
#else /* __APPLE__ */
case WXK_CONTROL_D:
#endif /* __APPLE__ */
m_bed.toggle_show_axes();
m_dirty = true;
break;
#ifdef __APPLE__ #ifdef __APPLE__
case 'f': case 'f':
case 'F': case 'F':
@ -3484,6 +3585,9 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
int instance_idx = v->instance_idx(); int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx(); int volume_idx = v->volume_idx();
if (volume_idx < 0)
continue;
std::pair<int, int> done_id(object_idx, instance_idx); std::pair<int, int> done_id(object_idx, instance_idx);
if (0 <= object_idx && object_idx < (int)m_model->objects.size()) { if (0 <= object_idx && object_idx < (int)m_model->objects.size()) {
@ -3494,7 +3598,7 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) if (selection_mode == Selection::Instance)
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation()); model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
else if (volume_idx >= 0 && selection_mode == Selection::Volume) else if (selection_mode == Selection::Volume)
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
object_moved = true; object_moved = true;
@ -3577,6 +3681,9 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
const int instance_idx = v->instance_idx(); const int instance_idx = v->instance_idx();
const int volume_idx = v->volume_idx(); const int volume_idx = v->volume_idx();
if (volume_idx < 0)
continue;
done.insert(std::pair<int, int>(object_idx, instance_idx)); done.insert(std::pair<int, int>(object_idx, instance_idx));
// Rotate instances/volumes. // Rotate instances/volumes.
@ -3641,6 +3748,9 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
const int instance_idx = v->instance_idx(); const int instance_idx = v->instance_idx();
const int volume_idx = v->volume_idx(); const int volume_idx = v->volume_idx();
if (volume_idx < 0)
continue;
done.insert(std::pair<int, int>(object_idx, instance_idx)); done.insert(std::pair<int, int>(object_idx, instance_idx));
// Rotate instances/volumes // Rotate instances/volumes
@ -3648,7 +3758,7 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) if (selection_mode == Selection::Instance)
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation()); model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
else if (selection_mode == Selection::Volume && volume_idx >= 0) { else if (selection_mode == Selection::Volume) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation()); model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
} }
@ -4357,7 +4467,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
if (thumbnail_params.show_bed) if (thumbnail_params.show_bed)
_render_bed(view_matrix, projection_matrix, !camera.is_looking_downward(), false); _render_bed(view_matrix, projection_matrix, !camera.is_looking_downward());
// restore background color // restore background color
if (thumbnail_params.transparent_background) if (thumbnail_params.transparent_background)
@ -4643,7 +4753,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "add"; item.name = "add";
item.icon_filename = "add.svg"; item.icon_filename = "add.svg";
item.tooltip = _utf8(L("Add...")) + " [" + GUI::shortkey_ctrl_prefix() + "I]"; item.tooltip = _u8L("Add...") + " [" + GUI::shortkey_ctrl_prefix() + "I]";
item.sprite_id = 0; item.sprite_id = 0;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD)); };
if (!m_main_toolbar.add_item(item)) if (!m_main_toolbar.add_item(item))
@ -4651,7 +4761,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "delete"; item.name = "delete";
item.icon_filename = "remove.svg"; item.icon_filename = "remove.svg";
item.tooltip = _utf8(L("Delete")) + " [Del]"; item.tooltip = _u8L("Delete") + " [Del]";
item.sprite_id = 1; item.sprite_id = 1;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete(); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete(); };
@ -4660,7 +4770,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "deleteall"; item.name = "deleteall";
item.icon_filename = "delete_all.svg"; item.icon_filename = "delete_all.svg";
item.tooltip = _utf8(L("Delete all")) + " [" + GUI::shortkey_ctrl_prefix() + "Del]"; item.tooltip = _u8L("Delete all") + " [" + GUI::shortkey_ctrl_prefix() + "Del]";
item.sprite_id = 2; item.sprite_id = 2;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete_all(); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete_all(); };
@ -4669,7 +4779,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "arrange"; item.name = "arrange";
item.icon_filename = "arrange.svg"; item.icon_filename = "arrange.svg";
item.tooltip = _utf8(L("Arrange")) + " [A]\n" + _utf8(L("Arrange selection")) + " [Shift+A]\n" + _utf8(L("Click right mouse button to show arrangement options")); item.tooltip = _u8L("Arrange") + " [A]\n" + _u8L("Arrange selection") + " [Shift+A]\n" + _u8L("Click right mouse button to show arrangement options");
item.sprite_id = 3; item.sprite_id = 3;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_arrange(); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_arrange(); };
@ -4689,7 +4799,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "copy"; item.name = "copy";
item.icon_filename = "copy.svg"; item.icon_filename = "copy.svg";
item.tooltip = _utf8(L("Copy")) + " [" + GUI::shortkey_ctrl_prefix() + "C]"; item.tooltip = _u8L("Copy") + " [" + GUI::shortkey_ctrl_prefix() + "C]";
item.sprite_id = 4; item.sprite_id = 4;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_copy_to_clipboard(); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_copy_to_clipboard(); };
@ -4698,7 +4808,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "paste"; item.name = "paste";
item.icon_filename = "paste.svg"; item.icon_filename = "paste.svg";
item.tooltip = _utf8(L("Paste")) + " [" + GUI::shortkey_ctrl_prefix() + "V]"; item.tooltip = _u8L("Paste") + " [" + GUI::shortkey_ctrl_prefix() + "V]";
item.sprite_id = 5; item.sprite_id = 5;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_paste_from_clipboard(); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_paste_from_clipboard(); };
@ -4710,7 +4820,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "more"; item.name = "more";
item.icon_filename = "instance_add.svg"; item.icon_filename = "instance_add.svg";
item.tooltip = _utf8(L("Add instance")) + " [+]"; item.tooltip = _u8L("Add instance") + " [+]";
item.sprite_id = 6; item.sprite_id = 6;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); };
item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; };
@ -4721,7 +4831,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "fewer"; item.name = "fewer";
item.icon_filename = "instance_remove.svg"; item.icon_filename = "instance_remove.svg";
item.tooltip = _utf8(L("Remove instance")) + " [-]"; item.tooltip = _u8L("Remove instance") + " [-]";
item.sprite_id = 7; item.sprite_id = 7;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); };
item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; };
@ -4734,7 +4844,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "splitobjects"; item.name = "splitobjects";
item.icon_filename = "split_objects.svg"; item.icon_filename = "split_objects.svg";
item.tooltip = _utf8(L("Split to objects")); item.tooltip = _u8L("Split to objects");
item.sprite_id = 8; item.sprite_id = 8;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); };
item.visibility_callback = GLToolbarItem::Default_Visibility_Callback; item.visibility_callback = GLToolbarItem::Default_Visibility_Callback;
@ -4744,7 +4854,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "splitvolumes"; item.name = "splitvolumes";
item.icon_filename = "split_parts.svg"; item.icon_filename = "split_parts.svg";
item.tooltip = _utf8(L("Split to parts")); item.tooltip = _u8L("Split to parts");
item.sprite_id = 9; item.sprite_id = 9;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); };
item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; };
@ -4758,8 +4868,8 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "settings"; item.name = "settings";
item.icon_filename = "settings.svg"; item.icon_filename = "settings.svg";
item.tooltip = _u8L("Switch to Settings") + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "2] - " + _u8L("Print Settings Tab") + item.tooltip = _u8L("Switch to Settings") + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "2] - " + _u8L("Print Settings Tab") +
"\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab") +
"\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Printer Settings Tab") ; "\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Printer Settings Tab")) ;
item.sprite_id = 10; item.sprite_id = 10;
item.enabling_callback = GLToolbarItem::Default_Enabling_Callback; item.enabling_callback = GLToolbarItem::Default_Enabling_Callback;
item.visibility_callback = []() { return wxGetApp().app_config->get_bool("new_settings_layout_mode") || item.visibility_callback = []() { return wxGetApp().app_config->get_bool("new_settings_layout_mode") ||
@ -4775,7 +4885,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "search"; item.name = "search";
item.icon_filename = "search_.svg"; item.icon_filename = "search_.svg";
item.tooltip = _utf8(L("Search")) + " [" + GUI::shortkey_ctrl_prefix() + "F]"; item.tooltip = _u8L("Search") + " [" + GUI::shortkey_ctrl_prefix() + "F]";
item.sprite_id = 11; item.sprite_id = 11;
item.left.toggable = true; item.left.toggable = true;
item.left.render_callback = [this](float left, float right, float, float) { item.left.render_callback = [this](float left, float right, float, float) {
@ -4797,7 +4907,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "layersediting"; item.name = "layersediting";
item.icon_filename = "layers_white.svg"; item.icon_filename = "layers_white.svg";
item.tooltip = _utf8(L("Variable layer height")); item.tooltip = _u8L("Variable layer height");
item.sprite_id = 12; item.sprite_id = 12;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); }; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); };
item.visibility_callback = [this]()->bool { item.visibility_callback = [this]()->bool {
@ -4850,7 +4960,7 @@ bool GLCanvas3D::_init_undoredo_toolbar()
item.name = "undo"; item.name = "undo";
item.icon_filename = "undo_toolbar.svg"; item.icon_filename = "undo_toolbar.svg";
item.tooltip = _utf8(L("Undo")) + " [" + GUI::shortkey_ctrl_prefix() + "Z]\n" + _utf8(L("Click right mouse button to open/close History")); item.tooltip = _u8L("Undo") + " [" + GUI::shortkey_ctrl_prefix() + "Z]\n" + _u8L("Click right mouse button to open/close History");
item.sprite_id = 0; item.sprite_id = 0;
item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_UNDO)); }; item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_UNDO)); };
item.right.toggable = true; item.right.toggable = true;
@ -4872,7 +4982,7 @@ bool GLCanvas3D::_init_undoredo_toolbar()
if (can_undo) { if (can_undo) {
std::string action; std::string action;
wxGetApp().plater()->undo_redo_topmost_string_getter(true, action); wxGetApp().plater()->undo_redo_topmost_string_getter(true, action);
new_additional_tooltip = (boost::format(_utf8(L("Next Undo action: %1%"))) % action).str(); new_additional_tooltip = format(_L("Next Undo action: %1%"), action);
} }
if (new_additional_tooltip != curr_additional_tooltip) { if (new_additional_tooltip != curr_additional_tooltip) {
@ -4887,7 +4997,7 @@ bool GLCanvas3D::_init_undoredo_toolbar()
item.name = "redo"; item.name = "redo";
item.icon_filename = "redo_toolbar.svg"; item.icon_filename = "redo_toolbar.svg";
item.tooltip = _utf8(L("Redo")) + " [" + GUI::shortkey_ctrl_prefix() + "Y]\n" + _utf8(L("Click right mouse button to open/close History")); item.tooltip = _u8L("Redo") + " [" + GUI::shortkey_ctrl_prefix() + "Y]\n" + _u8L("Click right mouse button to open/close History");
item.sprite_id = 1; item.sprite_id = 1;
item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_REDO)); }; item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_REDO)); };
item.right.action_callback = [this]() { m_imgui_undo_redo_hovered_pos = -1; }; item.right.action_callback = [this]() { m_imgui_undo_redo_hovered_pos = -1; };
@ -4908,7 +5018,7 @@ bool GLCanvas3D::_init_undoredo_toolbar()
if (can_redo) { if (can_redo) {
std::string action; std::string action;
wxGetApp().plater()->undo_redo_topmost_string_getter(false, action); wxGetApp().plater()->undo_redo_topmost_string_getter(false, action);
new_additional_tooltip = (boost::format(_utf8(L("Next Redo action: %1%"))) % action).str(); new_additional_tooltip = format(_L("Next Redo action: %1%"), action);
} }
if (new_additional_tooltip != curr_additional_tooltip) { if (new_additional_tooltip != curr_additional_tooltip) {
@ -5411,7 +5521,7 @@ void GLCanvas3D::_render_background()
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
} }
void GLCanvas3D::_render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_axes) void GLCanvas3D::_render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom)
{ {
float scale_factor = 1.0; float scale_factor = 1.0;
#if ENABLE_RETINA_GL #if ENABLE_RETINA_GL
@ -5425,7 +5535,12 @@ void GLCanvas3D::_render_bed(const Transform3d& view_matrix, const Transform3d&
&& m_gizmos.get_current_type() != GLGizmosManager::Seam && m_gizmos.get_current_type() != GLGizmosManager::Seam
&& m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation); && m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation);
m_bed.render(*this, view_matrix, projection_matrix, bottom, scale_factor, show_axes, show_texture); m_bed.render(*this, view_matrix, projection_matrix, bottom, scale_factor, show_texture);
}
void GLCanvas3D::_render_bed_axes()
{
m_bed.render_axes();
} }
void GLCanvas3D::_render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom) void GLCanvas3D::_render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom)
@ -6725,9 +6840,9 @@ void GLCanvas3D::_load_sla_shells()
// adds objects' volumes // adds objects' volumes
for (const SLAPrintObject* obj : print->objects()) { for (const SLAPrintObject* obj : print->objects()) {
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
for (const SLAPrintObject::Instance& instance : obj->instances()) { std::shared_ptr<const indexed_triangle_set> m = obj->get_mesh_to_print();
std::shared_ptr<const indexed_triangle_set> m = obj->get_mesh_to_print(); if (m && !m->empty()) {
if (m && !m->empty()) { for (const SLAPrintObject::Instance& instance : obj->instances()) {
add_volume(*obj, 0, instance, *m, GLVolume::MODEL_COLOR[0], true); add_volume(*obj, 0, instance, *m, GLVolume::MODEL_COLOR[0], true);
// Set the extruder_id and volume_id to achieve the same color as in the 3D scene when // Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
// through the update_volumes_colors_by_extruder() call. // through the update_volumes_colors_by_extruder() call.
@ -6738,7 +6853,7 @@ void GLCanvas3D::_load_sla_shells()
add_volume(*obj, -int(slaposPad), instance, pad_mesh, GLVolume::SLA_PAD_COLOR, false); add_volume(*obj, -int(slaposPad), instance, pad_mesh, GLVolume::SLA_PAD_COLOR, false);
} }
} }
double shift_z = obj->get_current_elevation(); const double shift_z = obj->get_current_elevation();
for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) { for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) {
// apply shift z // apply shift z
m_volumes.volumes[i]->set_sla_shift_z(shift_z); m_volumes.volumes[i]->set_sla_shift_z(shift_z);
@ -7146,5 +7261,95 @@ const ModelVolume *get_model_volume(const GLVolume &v, const Model &model)
return ret; return ret;
} }
const ModelVolume *get_model_volume(const ObjectID &volume_id, const ModelObjectPtrs &objects)
{
for (const ModelObject *obj : objects)
for (const ModelVolume *vol : obj->volumes)
if (vol->id() == volume_id)
return vol;
return nullptr;
}
ModelVolume *get_model_volume(const GLVolume &v, const ModelObject& object) {
if (v.volume_idx() < 0)
return nullptr;
size_t volume_idx = static_cast<size_t>(v.volume_idx());
if (volume_idx >= object.volumes.size())
return nullptr;
return object.volumes[volume_idx];
}
ModelVolume *get_model_volume(const GLVolume &v, const ModelObjectPtrs &objects)
{
if (v.object_idx() < 0)
return nullptr;
size_t objext_idx = static_cast<size_t>(v.object_idx());
if (objext_idx >= objects.size())
return nullptr;
if (objects[objext_idx] == nullptr)
return nullptr;
return get_model_volume(v, *objects[objext_idx]);
}
GLVolume *get_first_hovered_gl_volume(const GLCanvas3D &canvas) {
int hovered_id_signed = canvas.get_first_hover_volume_idx();
if (hovered_id_signed < 0)
return nullptr;
size_t hovered_id = static_cast<size_t>(hovered_id_signed);
const GLVolumePtrs &volumes = canvas.get_volumes().volumes;
if (hovered_id >= volumes.size())
return nullptr;
return volumes[hovered_id];
}
GLVolume *get_selected_gl_volume(const GLCanvas3D &canvas) {
const GLVolume *gl_volume = get_selected_gl_volume(canvas.get_selection());
if (gl_volume == nullptr)
return nullptr;
const GLVolumePtrs &gl_volumes = canvas.get_volumes().volumes;
for (GLVolume *v : gl_volumes)
if (v->composite_id == gl_volume->composite_id)
return v;
return nullptr;
}
ModelObject *get_model_object(const GLVolume &gl_volume, const Model &model) {
return get_model_object(gl_volume, model.objects);
}
ModelObject *get_model_object(const GLVolume &gl_volume, const ModelObjectPtrs &objects) {
if (gl_volume.object_idx() < 0)
return nullptr;
size_t objext_idx = static_cast<size_t>(gl_volume.object_idx());
if (objext_idx >= objects.size())
return nullptr;
return objects[objext_idx];
}
ModelInstance *get_model_instance(const GLVolume &gl_volume, const Model& model) {
return get_model_instance(gl_volume, model.objects);
}
ModelInstance *get_model_instance(const GLVolume &gl_volume, const ModelObjectPtrs &objects) {
if (gl_volume.instance_idx() < 0)
return nullptr;
ModelObject *object = get_model_object(gl_volume, objects);
return get_model_instance(gl_volume, *object);
}
ModelInstance *get_model_instance(const GLVolume &gl_volume, const ModelObject &object) {
if (gl_volume.instance_idx() < 0)
return nullptr;
size_t instance_idx = static_cast<size_t>(gl_volume.instance_idx());
if (instance_idx >= object.instances.size())
return nullptr;
return object.instances[instance_idx];
}
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -976,7 +976,8 @@ private:
void _picking_pass(); void _picking_pass();
void _rectangular_selection_picking_pass(); void _rectangular_selection_picking_pass();
void _render_background(); void _render_background();
void _render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_axes); void _render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom);
void _render_bed_axes();
void _render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom); void _render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom);
void _render_objects(GLVolumeCollection::ERenderType type); void _render_objects(GLVolumeCollection::ERenderType type);
void _render_gcode(); void _render_gcode();
@ -1058,7 +1059,20 @@ private:
float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); } float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); }
}; };
const ModelVolume * get_model_volume(const GLVolume &v, const Model &model); const ModelVolume *get_model_volume(const GLVolume &v, const Model &model);
const ModelVolume *get_model_volume(const ObjectID &volume_id, const ModelObjectPtrs &objects);
ModelVolume *get_model_volume(const GLVolume &v, const ModelObjectPtrs &objects);
ModelVolume *get_model_volume(const GLVolume &v, const ModelObject &object);
GLVolume *get_first_hovered_gl_volume(const GLCanvas3D &canvas);
GLVolume *get_selected_gl_volume(const GLCanvas3D &canvas);
ModelObject *get_model_object(const GLVolume &gl_volume, const Model &model);
ModelObject *get_model_object(const GLVolume &gl_volume, const ModelObjectPtrs &objects);
ModelInstance *get_model_instance(const GLVolume &gl_volume, const Model &model);
ModelInstance *get_model_instance(const GLVolume &gl_volume, const ModelObjectPtrs &objects);
ModelInstance *get_model_instance(const GLVolume &gl_volume, const ModelObject &object);
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -5,7 +5,15 @@
#include "GUI_ObjectManipulation.hpp" #include "GUI_ObjectManipulation.hpp"
#include "GUI_Factories.hpp" #include "GUI_Factories.hpp"
#include "format.hpp" #include "format.hpp"
#include "I18N.hpp"
// Localization headers: include libslic3r version first so everything in this file
// uses the slic3r/GUI version (the macros will take precedence over the functions).
// Also, there is a check that the former is not included from slic3r module.
// This is the only place where we want to allow that, so define an override macro.
#define SLIC3R_ALLOW_LIBSLIC3R_I18N_IN_SLIC3R
#include "libslic3r/I18N.hpp"
#undef SLIC3R_ALLOW_LIBSLIC3R_I18N_IN_SLIC3R
#include "slic3r/GUI/I18N.hpp"
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
@ -44,7 +52,6 @@
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/I18N.hpp"
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "libslic3r/Color.hpp" #include "libslic3r/Color.hpp"
@ -1315,7 +1322,7 @@ bool GUI_App::on_init_inner()
if (!delayed_error_load_presets.empty()) if (!delayed_error_load_presets.empty())
show_error(nullptr, delayed_error_load_presets); show_error(nullptr, delayed_error_load_presets);
mainframe = new MainFrame(); mainframe = new MainFrame(app_config->has("font_size") ? atoi(app_config->get("font_size").c_str()) : -1);
// hide settings tabs after first Layout // hide settings tabs after first Layout
if (is_editor()) if (is_editor())
mainframe->select_tab(size_t(0)); mainframe->select_tab(size_t(0));
@ -1803,7 +1810,7 @@ void GUI_App::recreate_GUI(const wxString& msg_name)
dlg.Update(10, _L("Recreating") + dots); dlg.Update(10, _L("Recreating") + dots);
MainFrame *old_main_frame = mainframe; MainFrame *old_main_frame = mainframe;
mainframe = new MainFrame(); mainframe = new MainFrame(app_config->has("font_size") ? atoi(app_config->get("font_size").c_str()) : -1);
if (is_editor()) if (is_editor())
// hide settings tabs after first Layout // hide settings tabs after first Layout
mainframe->select_tab(size_t(0)); mainframe->select_tab(size_t(0));
@ -1981,7 +1988,7 @@ void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const
void GUI_App::import_zip(wxWindow* parent, wxString& input_file) const void GUI_App::import_zip(wxWindow* parent, wxString& input_file) const
{ {
wxFileDialog dialog(parent ? parent : GetTopWindow(), wxFileDialog dialog(parent ? parent : GetTopWindow(),
_L("Choose ZIP file:"), _L("Choose ZIP file") + ":",
from_u8(app_config->get_last_dir()), "", from_u8(app_config->get_last_dir()), "",
file_wildcards(FT_ZIP), wxFD_OPEN | wxFD_FILE_MUST_EXIST); file_wildcards(FT_ZIP), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
@ -2305,18 +2312,6 @@ bool GUI_App::load_language(wxString language, bool initial)
// Override language at the active wxTranslations class (which is stored in the active m_wxLocale) // Override language at the active wxTranslations class (which is stored in the active m_wxLocale)
// to load possibly different dictionary, for example, load Czech dictionary for Slovak language. // to load possibly different dictionary, for example, load Czech dictionary for Slovak language.
wxTranslations::Get()->SetLanguage(language_dict); wxTranslations::Get()->SetLanguage(language_dict);
{
// ysFIXME after fix for wxWidgets issue (https://github.com/wxWidgets/wxWidgets/issues/23210)
// UKR Localization specific workaround till the wxWidgets doesn't fixed:
// From wxWidgets 3.1.6 calls setlocation(0, wxInfoLanguage->LocaleTag), see (https://github.com/prusa3d/wxWidgets/commit/deef116a09748796711d1e3509965ee208dcdf0b#diff-7de25e9a71c4dce61bbf76492c589623d5b93fd1bb105ceaf0662075d15f4472),
// where LocaleTag is a Tag of locale in BCP 47 - like notation.
// For Ukrainian Language LocaleTag is "uk".
// But setlocale(0, "uk") returns "English_United Kingdom.1252" instead of "uk",
// and, as a result, locales are set to English_United Kingdom
if (language_info->CanonicalName == "uk")
setlocale(0, language_info->GetCanonicalWithRegion().data());
}
m_wxLocale->AddCatalog(SLIC3R_APP_KEY); m_wxLocale->AddCatalog(SLIC3R_APP_KEY);
m_imgui->set_language(into_u8(language_info->CanonicalName)); m_imgui->set_language(into_u8(language_info->CanonicalName));
//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only. //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
@ -2393,8 +2388,8 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
auto local_menu = new wxMenu(); auto local_menu = new wxMenu();
wxWindowID config_id_base = wxWindow::NewControlId(int(ConfigMenuCnt)); wxWindowID config_id_base = wxWindow::NewControlId(int(ConfigMenuCnt));
const auto config_wizard_name = _(ConfigWizard::name(true)); const wxString config_wizard_name = _(ConfigWizard::name(true));
const auto config_wizard_tooltip = from_u8((boost::format(_utf8(L("Run %s"))) % config_wizard_name).str()); const wxString config_wizard_tooltip = from_u8((boost::format(_u8L("Run %s")) % config_wizard_name).str());
// Cmd+, is standard on OS X - what about other operating systems? // Cmd+, is standard on OS X - what about other operating systems?
if (is_editor()) { if (is_editor()) {
local_menu->Append(config_id_base + ConfigMenuWizard, config_wizard_name + dots, config_wizard_tooltip); local_menu->Append(config_id_base + ConfigMenuWizard, config_wizard_name + dots, config_wizard_tooltip);
@ -2421,7 +2416,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
mode_menu = new wxMenu(); mode_menu = new wxMenu();
mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeSimple, _L("Simple"), _L("Simple View Mode")); mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeSimple, _L("Simple"), _L("Simple View Mode"));
// mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeAdvanced, _L("Advanced"), _L("Advanced View Mode")); // mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeAdvanced, _L("Advanced"), _L("Advanced View Mode"));
mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeAdvanced, _CTX(L_CONTEXT("Advanced", "Mode"), "Mode"), _L("Advanced View Mode")); mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeAdvanced, _CTX("Advanced", "Mode"), _L("Advanced View Mode"));
mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeExpert, _L("Expert"), _L("Expert View Mode")); mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeExpert, _L("Expert"), _L("Expert View Mode"));
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { if (get_mode() == comSimple) evt.Check(true); }, config_id_base + ConfigMenuModeSimple); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { if (get_mode() == comSimple) evt.Check(true); }, config_id_base + ConfigMenuModeSimple);
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { if (get_mode() == comAdvanced) evt.Check(true); }, config_id_base + ConfigMenuModeAdvanced); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { if (get_mode() == comAdvanced) evt.Check(true); }, config_id_base + ConfigMenuModeAdvanced);
@ -3445,7 +3440,7 @@ void GUI_App::app_updater(bool from_user)
} }
app_data.target_path =dwnld_dlg.get_download_path(); app_data.target_path =dwnld_dlg.get_download_path();
// start download // start download
this->plater_->get_notification_manager()->push_download_progress_notification(GUI::format(_utf8("Downloading %1%"), app_data.target_path.filename().string()), std::bind(&AppUpdater::cancel_callback, this->m_app_updater.get())); this->plater_->get_notification_manager()->push_download_progress_notification(GUI::format(_L("Downloading %1%"), app_data.target_path.filename().string()), std::bind(&AppUpdater::cancel_callback, this->m_app_updater.get()));
app_data.start_after = dwnld_dlg.run_after_download(); app_data.start_after = dwnld_dlg.run_after_download();
m_app_updater->set_app_data(std::move(app_data)); m_app_updater->set_app_data(std::move(app_data));
m_app_updater->sync_download(); m_app_updater->sync_download();
@ -3473,7 +3468,7 @@ void GUI_App::start_download(std::string url)
//lets always init so if the download dest folder was changed, new dest is used //lets always init so if the download dest folder was changed, new dest is used
boost::filesystem::path dest_folder(app_config->get("url_downloader_dest")); boost::filesystem::path dest_folder(app_config->get("url_downloader_dest"));
if (dest_folder.empty() || !boost::filesystem::is_directory(dest_folder)) { if (dest_folder.empty() || !boost::filesystem::is_directory(dest_folder)) {
std::string msg = _utf8("Could not start URL download. Destination folder is not set. Please choose destination folder in Configuration Wizard."); std::string msg = _u8L("Could not start URL download. Destination folder is not set. Please choose destination folder in Configuration Wizard.");
BOOST_LOG_TRIVIAL(error) << msg; BOOST_LOG_TRIVIAL(error) << msg;
show_error(nullptr, msg); show_error(nullptr, msg);
return; return;

View File

@ -411,7 +411,7 @@ static void create_freq_settings_popupmenu(wxMenu* menu, const bool is_object_se
if (is_improper_category(category.first, extruders_cnt)) if (is_improper_category(category.first, extruders_cnt))
continue; continue;
append_menu_item(menu, wxID_ANY, from_u8((boost::format(_utf8(L("Quick Add Settings (%s)"))) % _(it.first)).str()), "", append_menu_item(menu, wxID_ANY, format_wxstr(_L("Quick Add Settings (%s)"), _(it.first)), "",
[menu, item, is_object_settings, bundle](wxCommandEvent& event) { [menu, item, is_object_settings, bundle](wxCommandEvent& event) {
wxString category_name = menu->GetLabel(event.GetId()); wxString category_name = menu->GetLabel(event.GetId());
std::vector<std::string> options; std::vector<std::string> options;
@ -622,13 +622,13 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_)
#if 0 #if 0
for (auto& it : m_freq_settings_fff) for (auto& it : m_freq_settings_fff)
{ {
settings_id = menu->FindItem(from_u8((boost::format(_utf8(L("Quick Add Settings (%s)"))) % _(it.first)).str())); settings_id = menu->FindItem(format_wxstr(_L("Quick Add Settings (%s)"), _(it.first)));
if (settings_id != wxNOT_FOUND) if (settings_id != wxNOT_FOUND)
menu->Destroy(settings_id); menu->Destroy(settings_id);
} }
for (auto& it : m_freq_settings_sla) for (auto& it : m_freq_settings_sla)
{ {
settings_id = menu->FindItem(from_u8((boost::format(_utf8(L("Quick Add Settings (%s)"))) % _(it.first)).str())); settings_id = menu->FindItem(format_wxstr(_L("Quick Add Settings (%s)"), _(it.first)));
if (settings_id != wxNOT_FOUND) if (settings_id != wxNOT_FOUND)
menu->Destroy(settings_id); menu->Destroy(settings_id);
} }
@ -1000,7 +1000,7 @@ void MenuFactory::append_menu_item_edit_text(wxMenu *menu)
std::string icon = ""; std::string icon = "";
append_menu_item( append_menu_item(
menu, wxID_ANY, name, description, menu, wxID_ANY, name, description,
[can_edit_text](wxCommandEvent &) { [](wxCommandEvent &) {
plater()->canvas3D()->get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss); plater()->canvas3D()->get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss);
}, },
icon, nullptr, can_edit_text, m_parent); icon, nullptr, can_edit_text, m_parent);

View File

@ -420,7 +420,7 @@ MeshErrorsInfo ObjectList::get_mesh_errors_info(const int obj_idx, const int vol
const ModelObject* object = (*m_objects)[obj_idx]; const ModelObject* object = (*m_objects)[obj_idx];
if (vol_idx != -1 && vol_idx >= int(object->volumes.size())) { if (vol_idx != -1 && vol_idx >= int(object->volumes.size())) {
if (sidebar_info) if (sidebar_info)
*sidebar_info = _L("Wrong volume index "); *sidebar_info = _L("Wrong volume index") + " ";
return { {}, {} }; // hide tooltip return { {}, {} }; // hide tooltip
} }
@ -2043,9 +2043,8 @@ bool ObjectList::del_from_cut_object(bool is_cut_connector, bool is_model_part/*
InfoDialog dialog(wxGetApp().plater(), title, InfoDialog dialog(wxGetApp().plater(), title,
_L("This action will break a cut information.\n" _L("This action will break a cut information.\n"
"After that PrusaSlicer can't guarantee model consistency.\n" "After that PrusaSlicer can't guarantee model consistency.") + "\n\n" +
"\n" _L("To manipulate with solid parts or negative volumes you have to invalidate cut infornation first." + msg_end ),
"To manipulate with solid parts or negative volumes you have to invalidate cut infornation first." + msg_end ),
false, buttons_style | wxCANCEL_DEFAULT | wxICON_WARNING); false, buttons_style | wxCANCEL_DEFAULT | wxICON_WARNING);
dialog.SetButtonLabel(wxID_YES, _L("Invalidate cut info")); dialog.SetButtonLabel(wxID_YES, _L("Invalidate cut info"));
@ -2924,6 +2923,16 @@ void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selectio
if (obj_idx >= m_objects->size()) if (obj_idx >= m_objects->size())
return; return;
wxDataViewItemArray sels;
if (!selections) {
GetSelections(sels);
for (wxDataViewItem item : sels)
if (item.IsOk() && m_objects_model->GetItemType(item) == itVolume) {
selections = &sels;
break;
}
}
const ModelObject* model_object = (*m_objects)[obj_idx]; const ModelObject* model_object = (*m_objects)[obj_idx];
wxDataViewItem item_obj = m_objects_model->GetItemById(obj_idx); wxDataViewItem item_obj = m_objects_model->GetItemById(obj_idx);
assert(item_obj.IsOk()); assert(item_obj.IsOk());

View File

@ -1,5 +1,6 @@
#include "GUI_ObjectManipulation.hpp" #include "GUI_ObjectManipulation.hpp"
#include "I18N.hpp" #include "I18N.hpp"
#include "format.hpp"
#include "BitmapComboBox.hpp" #include "BitmapComboBox.hpp"
#include "GLCanvas3D.hpp" #include "GLCanvas3D.hpp"
@ -245,8 +246,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
// We will add a button to toggle mirroring to each axis: // We will add a button to toggle mirroring to each axis:
auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
btn->SetToolTip(_L("Mirror along") + wxString::Format(_L(" %c "), (int)label) + _L("axis")); btn->SetToolTip(format_wxstr(_L("Mirror along %1% axis"), label));
m_mirror_buttons[axis_idx] = btn; m_mirror_buttons[axis_idx] = btn;
sizer->AddStretchSpacer(2); sizer->AddStretchSpacer(2);
@ -596,6 +596,12 @@ void ObjectManipulation::update_ui_from_settings()
void ObjectManipulation::update_settings_value(const Selection& selection) void ObjectManipulation::update_settings_value(const Selection& selection)
{ {
if (selection.is_empty()) {
// No selection, reset the cache.
reset_settings_value();
return;
}
m_new_move_label_string = L("Position"); m_new_move_label_string = L("Position");
m_new_rotate_label_string = L("Rotation"); m_new_rotate_label_string = L("Rotation");
m_new_scale_label_string = L("Scale factors"); m_new_scale_label_string = L("Scale factors");
@ -674,11 +680,6 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
m_new_enabled = true; m_new_enabled = true;
} }
else {
// No selection, reset the cache.
// assert(selection.is_empty());
reset_settings_value();
}
} }
void ObjectManipulation::update_if_dirty() void ObjectManipulation::update_if_dirty()
@ -1066,8 +1067,9 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double
if (new_value > 0.0) if (new_value > 0.0)
change_size_value(axis, new_value); change_size_value(axis, new_value);
else { else {
new_value = m_cache.size(axis); Vec3d& size = m_imperial_units ? m_cache.size_inches : m_cache.size;
m_cache.size(axis) = 0.0; new_value = size(axis);
size(axis) = 0.0;
m_cache.size_rounded(axis) = DBL_MAX; m_cache.size_rounded(axis) = DBL_MAX;
change_size_value(axis, new_value); change_size_value(axis, new_value);
} }

View File

@ -12,6 +12,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "I18N.hpp" #include "I18N.hpp"
#include "format.hpp"
#include "ConfigManipulation.hpp" #include "ConfigManipulation.hpp"
#include <wx/wupdlock.h> #include <wx/wupdlock.h>
@ -102,7 +103,7 @@ bool ObjectSettings::update_settings_list()
btn->SetBitmapCurrent(m_bmp_delete_focus.bmp()); btn->SetBitmapCurrent(m_bmp_delete_focus.bmp());
btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) { btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) {
wxGetApp().plater()->take_snapshot(from_u8((boost::format(_utf8(L("Delete Option %s"))) % opt_key).str())); wxGetApp().plater()->take_snapshot(format_wxstr(_L("Delete Option %s"), opt_key));
config->erase(opt_key); config->erase(opt_key);
wxGetApp().obj_list()->changed_object(); wxGetApp().obj_list()->changed_object();
wxTheApp->CallAfter([this]() { wxTheApp->CallAfter([this]() {
@ -151,7 +152,7 @@ bool ObjectSettings::update_settings_list()
for (auto& opt : cat.second) for (auto& opt : cat.second)
optgroup->get_field(opt)->m_on_change = [optgroup](const std::string& opt_id, const boost::any& value) { optgroup->get_field(opt)->m_on_change = [optgroup](const std::string& opt_id, const boost::any& value) {
// first of all take a snapshot and then change value in configuration // first of all take a snapshot and then change value in configuration
wxGetApp().plater()->take_snapshot(from_u8((boost::format(_utf8(L("Change Option %s"))) % opt_id).str())); wxGetApp().plater()->take_snapshot(format_wxstr(_L("Change Option %s"), opt_id));
optgroup->on_change_OG(opt_id, value); optgroup->on_change_OG(opt_id, value);
}; };

Some files were not shown because too many files have changed in this diff Show More