diff --git a/resources/profiles/Anker/process/fdm_process_common.json b/resources/profiles/Anker/process/fdm_process_common.json index 7bf242ddb9..2a277cfd01 100644 --- a/resources/profiles/Anker/process/fdm_process_common.json +++ b/resources/profiles/Anker/process/fdm_process_common.json @@ -86,7 +86,7 @@ "top_solid_infill_flow_ratio": "1", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "layer_height": "0.2", diff --git a/resources/profiles/Anycubic/machine/Anycubic 4Max Pro 2 0.4 nozzle.json b/resources/profiles/Anycubic/machine/Anycubic 4Max Pro 2 0.4 nozzle.json index 144ca30f68..583653ce6e 100644 --- a/resources/profiles/Anycubic/machine/Anycubic 4Max Pro 2 0.4 nozzle.json +++ b/resources/profiles/Anycubic/machine/Anycubic 4Max Pro 2 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "25" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M601", "default_filament_profile": [ diff --git a/resources/profiles/Anycubic/machine/Anycubic Chiron 0.4 nozzle.json b/resources/profiles/Anycubic/machine/Anycubic Chiron 0.4 nozzle.json index 0f437d53fa..b9b38159e2 100644 --- a/resources/profiles/Anycubic/machine/Anycubic Chiron 0.4 nozzle.json +++ b/resources/profiles/Anycubic/machine/Anycubic Chiron 0.4 nozzle.json @@ -104,7 +104,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M601", "default_filament_profile": [ diff --git a/resources/profiles/Anycubic/machine/Anycubic Kobra 2 0.4 nozzle.json b/resources/profiles/Anycubic/machine/Anycubic Kobra 2 0.4 nozzle.json index 454f3b49ff..67939352a5 100644 --- a/resources/profiles/Anycubic/machine/Anycubic Kobra 2 0.4 nozzle.json +++ b/resources/profiles/Anycubic/machine/Anycubic Kobra 2 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "80" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M601", "default_filament_profile": [ diff --git a/resources/profiles/Anycubic/machine/Anycubic Kobra Max 0.4 nozzle.json b/resources/profiles/Anycubic/machine/Anycubic Kobra Max 0.4 nozzle.json index e1c2fa6f2c..8c8c4c12b9 100644 --- a/resources/profiles/Anycubic/machine/Anycubic Kobra Max 0.4 nozzle.json +++ b/resources/profiles/Anycubic/machine/Anycubic Kobra Max 0.4 nozzle.json @@ -104,7 +104,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M601", "default_filament_profile": [ diff --git a/resources/profiles/Anycubic/machine/Anycubic Kobra Plus 0.4 nozzle.json b/resources/profiles/Anycubic/machine/Anycubic Kobra Plus 0.4 nozzle.json index 71cfbf4e38..942e3e45d6 100644 --- a/resources/profiles/Anycubic/machine/Anycubic Kobra Plus 0.4 nozzle.json +++ b/resources/profiles/Anycubic/machine/Anycubic Kobra Plus 0.4 nozzle.json @@ -104,7 +104,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M601", "default_filament_profile": [ diff --git a/resources/profiles/Anycubic/machine/Anycubic Vyper 0.4 nozzle.json b/resources/profiles/Anycubic/machine/Anycubic Vyper 0.4 nozzle.json index 781dc9f953..01c8ff1d74 100644 --- a/resources/profiles/Anycubic/machine/Anycubic Vyper 0.4 nozzle.json +++ b/resources/profiles/Anycubic/machine/Anycubic Vyper 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M601", "default_filament_profile": [ diff --git a/resources/profiles/Anycubic/machine/Anycubic i3 Mega S 0.4 nozzle.json b/resources/profiles/Anycubic/machine/Anycubic i3 Mega S 0.4 nozzle.json index 2281ae72ed..709dcf918f 100644 --- a/resources/profiles/Anycubic/machine/Anycubic i3 Mega S 0.4 nozzle.json +++ b/resources/profiles/Anycubic/machine/Anycubic i3 Mega S 0.4 nozzle.json @@ -104,7 +104,7 @@ "deretraction_speed": [ "50" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M25", "default_filament_profile": [ diff --git a/resources/profiles/Anycubic/process/fdm_process_common.json b/resources/profiles/Anycubic/process/fdm_process_common.json index fd05875b11..faf2d9af79 100644 --- a/resources/profiles/Anycubic/process/fdm_process_common.json +++ b/resources/profiles/Anycubic/process/fdm_process_common.json @@ -84,9 +84,9 @@ "top_surface_pattern": "monotonic", "top_surface_line_width": "0.4", "top_shell_thickness": "0.8", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "layer_height": "0.2", diff --git a/resources/profiles/Artillery/machine/Artillery Genius 0.4 nozzle.json b/resources/profiles/Artillery/machine/Artillery Genius 0.4 nozzle.json index 818f20279b..01535d296d 100644 --- a/resources/profiles/Artillery/machine/Artillery Genius 0.4 nozzle.json +++ b/resources/profiles/Artillery/machine/Artillery Genius 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Artillery/machine/Artillery Hornet 0.4 nozzle.json b/resources/profiles/Artillery/machine/Artillery Hornet 0.4 nozzle.json index e051b9cab0..17f7d71ff0 100644 --- a/resources/profiles/Artillery/machine/Artillery Hornet 0.4 nozzle.json +++ b/resources/profiles/Artillery/machine/Artillery Hornet 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Artillery/machine/Artillery Sidewinder X1 0.4 nozzle.json b/resources/profiles/Artillery/machine/Artillery Sidewinder X1 0.4 nozzle.json index e97a22f38f..7fbfaf193e 100644 --- a/resources/profiles/Artillery/machine/Artillery Sidewinder X1 0.4 nozzle.json +++ b/resources/profiles/Artillery/machine/Artillery Sidewinder X1 0.4 nozzle.json @@ -103,7 +103,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Artillery/machine/Artillery Sidewinder X2 0.4 nozzle.json b/resources/profiles/Artillery/machine/Artillery Sidewinder X2 0.4 nozzle.json index 75f01e0ad6..bcf95b85ed 100644 --- a/resources/profiles/Artillery/machine/Artillery Sidewinder X2 0.4 nozzle.json +++ b/resources/profiles/Artillery/machine/Artillery Sidewinder X2 0.4 nozzle.json @@ -103,7 +103,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Artillery/process/fdm_process_common.json b/resources/profiles/Artillery/process/fdm_process_common.json index fd05875b11..faf2d9af79 100644 --- a/resources/profiles/Artillery/process/fdm_process_common.json +++ b/resources/profiles/Artillery/process/fdm_process_common.json @@ -84,9 +84,9 @@ "top_surface_pattern": "monotonic", "top_surface_line_width": "0.4", "top_shell_thickness": "0.8", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "layer_height": "0.2", diff --git a/resources/profiles/BBL.json b/resources/profiles/BBL.json index ef63d15ef6..e1e011d4da 100644 --- a/resources/profiles/BBL.json +++ b/resources/profiles/BBL.json @@ -1,7 +1,7 @@ { "name": "Bambulab", "url": "http://www.bambulab.com/Parameters/vendor/BBL.json", - "version": "01.07.00.10", + "version": "01.07.00.11", "force_update": "0", "description": "the initial version of BBL configurations", "machine_model_list": [ diff --git a/resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json index fd4c684639..6118ac4bda 100644 --- a/resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json @@ -10,7 +10,7 @@ ], "printer_model": "Bambu Lab P1P", "printer_variant": "0.4", - "auxiliary_fan": "0", + "auxiliary_fan": "1", "bed_exclude_area": [ "0x0", "18x0", diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 0.4 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab X1 0.4 nozzle.json index b0ed303050..c7999d6cab 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 0.4 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 0.4 nozzle.json @@ -10,7 +10,7 @@ ], "printer_model": "Bambu Lab X1", "printer_variant": "0.4", - "auxiliary_fan": "0", + "auxiliary_fan": "1", "bed_exclude_area": [ "0x0", "18x0", diff --git a/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json b/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json index c217e13022..4abdcc61e1 100644 --- a/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json +++ b/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json @@ -160,5 +160,7 @@ "machine_pause_gcode": "M400 U1", "wipe": [ "1" - ] + ], + "purge_in_prime_tower": "0", + "enable_filament_ramming": "0" } diff --git a/resources/profiles/BBL/process/fdm_process_bbl_common.json b/resources/profiles/BBL/process/fdm_process_bbl_common.json index 43e5a02b8b..5cfd7e111c 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_common.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_common.json @@ -108,5 +108,6 @@ "xy_hole_compensation": "0", "xy_contour_compensation": "0", "wall_generator": "arachne", - "gcode_label_objects": "0" + "gcode_label_objects": "0", + "flush_multiplier": "1.0" } diff --git a/resources/profiles/BIQU/machine/fdm_machine_common.json b/resources/profiles/BIQU/machine/fdm_machine_common.json index 4852f32686..4fc5f26bd7 100644 --- a/resources/profiles/BIQU/machine/fdm_machine_common.json +++ b/resources/profiles/BIQU/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/BIQU/process/fdm_process_biqu_common.json b/resources/profiles/BIQU/process/fdm_process_biqu_common.json index 7fef4b7f6a..f6f264c868 100644 --- a/resources/profiles/BIQU/process/fdm_process_biqu_common.json +++ b/resources/profiles/BIQU/process/fdm_process_biqu_common.json @@ -98,7 +98,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0" } diff --git a/resources/profiles/BIQU/process/fdm_process_hurakan_common.json b/resources/profiles/BIQU/process/fdm_process_hurakan_common.json index e1bf276aa6..2519589647 100644 --- a/resources/profiles/BIQU/process/fdm_process_hurakan_common.json +++ b/resources/profiles/BIQU/process/fdm_process_hurakan_common.json @@ -98,7 +98,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0" } diff --git a/resources/profiles/Creality/machine/Creality CR-10 V2 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality CR-10 V2 0.4 nozzle.json index ded563e91b..8d042e902c 100644 --- a/resources/profiles/Creality/machine/Creality CR-10 V2 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality CR-10 V2 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Creality/machine/Creality Ender-3 S1 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-3 S1 0.4 nozzle.json index 783367e78f..eb73fdd825 100644 --- a/resources/profiles/Creality/machine/Creality Ender-3 S1 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-3 S1 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M25", "default_filament_profile": [ diff --git a/resources/profiles/Creality/machine/Creality Ender-3 S1 Pro 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-3 S1 Pro 0.4 nozzle.json index dedb887c0c..b1206d1273 100644 --- a/resources/profiles/Creality/machine/Creality Ender-3 S1 Pro 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-3 S1 Pro 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "30" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M25", "default_filament_profile": [ diff --git a/resources/profiles/Creality/machine/Creality Ender-5 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-5 0.4 nozzle.json index 5bf2ad400d..393659da71 100644 --- a/resources/profiles/Creality/machine/Creality Ender-5 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-5 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Creality/machine/Creality Ender-5 Plus 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-5 Plus 0.4 nozzle.json index f8542c6a76..0b101422a1 100644 --- a/resources/profiles/Creality/machine/Creality Ender-5 Plus 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-5 Plus 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Creality/machine/Creality Ender-5 S1 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-5 S1 0.4 nozzle.json index b9a4d10279..84f23c9f25 100644 --- a/resources/profiles/Creality/machine/Creality Ender-5 S1 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-5 S1 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "30" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M25", "default_filament_profile": [ diff --git a/resources/profiles/Creality/machine/Creality Ender-5S 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-5S 0.4 nozzle.json index 69a8e150b1..79c73d5d14 100644 --- a/resources/profiles/Creality/machine/Creality Ender-5S 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-5S 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Creality/machine/Creality Ender-6 0.4 nozzle.json b/resources/profiles/Creality/machine/Creality Ender-6 0.4 nozzle.json index 938f7ad0ac..6fe8d0ff19 100644 --- a/resources/profiles/Creality/machine/Creality Ender-6 0.4 nozzle.json +++ b/resources/profiles/Creality/machine/Creality Ender-6 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Creality/machine/fdm_machine_common.json b/resources/profiles/Creality/machine/fdm_machine_common.json index 96af9a8090..1c38dd8cc5 100644 --- a/resources/profiles/Creality/machine/fdm_machine_common.json +++ b/resources/profiles/Creality/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Creality/process/0.12mm Fine @Creality CR10Max.json b/resources/profiles/Creality/process/0.12mm Fine @Creality CR10Max.json index 8e0a80a141..1c3cefe233 100644 --- a/resources/profiles/Creality/process/0.12mm Fine @Creality CR10Max.json +++ b/resources/profiles/Creality/process/0.12mm Fine @Creality CR10Max.json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.12mm Fine @Creality Ender3V2.json b/resources/profiles/Creality/process/0.12mm Fine @Creality Ender3V2.json index 7fda785011..e4fff81299 100644 --- a/resources/profiles/Creality/process/0.12mm Fine @Creality Ender3V2.json +++ b/resources/profiles/Creality/process/0.12mm Fine @Creality Ender3V2.json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.12mm Fine @Creality Ender5Pro (2019).json b/resources/profiles/Creality/process/0.12mm Fine @Creality Ender5Pro (2019).json index 2274637001..3613ada505 100644 --- a/resources/profiles/Creality/process/0.12mm Fine @Creality Ender5Pro (2019).json +++ b/resources/profiles/Creality/process/0.12mm Fine @Creality Ender5Pro (2019).json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.15mm Optimal @Creality CR10Max.json b/resources/profiles/Creality/process/0.15mm Optimal @Creality CR10Max.json index f901ff890e..3d0db3caa7 100644 --- a/resources/profiles/Creality/process/0.15mm Optimal @Creality CR10Max.json +++ b/resources/profiles/Creality/process/0.15mm Optimal @Creality CR10Max.json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.15mm Optimal @Creality Ender3V2.json b/resources/profiles/Creality/process/0.15mm Optimal @Creality Ender3V2.json index 7f26e1d90e..6856368697 100644 --- a/resources/profiles/Creality/process/0.15mm Optimal @Creality Ender3V2.json +++ b/resources/profiles/Creality/process/0.15mm Optimal @Creality Ender3V2.json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.15mm Optimal @Creality Ender5Pro (2019).json b/resources/profiles/Creality/process/0.15mm Optimal @Creality Ender5Pro (2019).json index 5cf210d5e6..c67ceeda6a 100644 --- a/resources/profiles/Creality/process/0.15mm Optimal @Creality Ender5Pro (2019).json +++ b/resources/profiles/Creality/process/0.15mm Optimal @Creality Ender5Pro (2019).json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 (0.4 nozzle).json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 (0.4 nozzle).json index 16c82e9fa7..d40f18e953 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1 (0.4 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1Max (0.4 nozzle).json b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1Max (0.4 nozzle).json index cb9b8205ae..30ac1cc624 100644 --- a/resources/profiles/Creality/process/0.16mm Optimal @Creality K1Max (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.16mm Optimal @Creality K1Max (0.4 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality CR10Max.json b/resources/profiles/Creality/process/0.20mm Standard @Creality CR10Max.json index 70b82a7b80..a2ca2e66c9 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality CR10Max.json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality CR10Max.json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality Ender3V2.json b/resources/profiles/Creality/process/0.20mm Standard @Creality Ender3V2.json index b1e5c03750..b7bcff8bbb 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality Ender3V2.json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality Ender3V2.json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality Ender5Pro (2019).json b/resources/profiles/Creality/process/0.20mm Standard @Creality Ender5Pro (2019).json index 8e58693e9f..48d4d98e51 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality Ender5Pro (2019).json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality Ender5Pro (2019).json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 (0.4 nozzle).json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 (0.4 nozzle).json index e9a8ad5cec..370d3cf6c9 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1 (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1 (0.4 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.20mm Standard @Creality K1Max (0.4 nozzle).json b/resources/profiles/Creality/process/0.20mm Standard @Creality K1Max (0.4 nozzle).json index bc75a6fef9..acb91b51bf 100644 --- a/resources/profiles/Creality/process/0.20mm Standard @Creality K1Max (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.20mm Standard @Creality K1Max (0.4 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality CR10Max.json b/resources/profiles/Creality/process/0.24mm Draft @Creality CR10Max.json index bd675a7caa..209ded8211 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality CR10Max.json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality CR10Max.json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality Ender3V2.json b/resources/profiles/Creality/process/0.24mm Draft @Creality Ender3V2.json index dfc051573a..b2db3fb562 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality Ender3V2.json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality Ender3V2.json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality Ender5Pro (2019).json b/resources/profiles/Creality/process/0.24mm Draft @Creality Ender5Pro (2019).json index 2eb20a75e5..7354faf490 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality Ender5Pro (2019).json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality Ender5Pro (2019).json @@ -99,7 +99,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 (0.4 nozzle).json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 (0.4 nozzle).json index 37ddb20730..aff9685f8b 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1 (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1 (0.4 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.24mm Draft @Creality K1Max (0.4 nozzle).json b/resources/profiles/Creality/process/0.24mm Draft @Creality K1Max (0.4 nozzle).json index 583c2c4790..7e7d68f574 100644 --- a/resources/profiles/Creality/process/0.24mm Draft @Creality K1Max (0.4 nozzle).json +++ b/resources/profiles/Creality/process/0.24mm Draft @Creality K1Max (0.4 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.24mm Optimal @Creality K1 (0.6 nozzle).json b/resources/profiles/Creality/process/0.24mm Optimal @Creality K1 (0.6 nozzle).json index 8e75b10259..14ddd750eb 100644 --- a/resources/profiles/Creality/process/0.24mm Optimal @Creality K1 (0.6 nozzle).json +++ b/resources/profiles/Creality/process/0.24mm Optimal @Creality K1 (0.6 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.24mm Optimal @Creality K1Max (0.6 nozzle).json b/resources/profiles/Creality/process/0.24mm Optimal @Creality K1Max (0.6 nozzle).json index de3663270f..7ac9cbe9f1 100644 --- a/resources/profiles/Creality/process/0.24mm Optimal @Creality K1Max (0.6 nozzle).json +++ b/resources/profiles/Creality/process/0.24mm Optimal @Creality K1Max (0.6 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.30mm Standard @Creality K1 (0.6 nozzle).json b/resources/profiles/Creality/process/0.30mm Standard @Creality K1 (0.6 nozzle).json index 62b98ee4fb..9c47f7d942 100644 --- a/resources/profiles/Creality/process/0.30mm Standard @Creality K1 (0.6 nozzle).json +++ b/resources/profiles/Creality/process/0.30mm Standard @Creality K1 (0.6 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.30mm Standard @Creality K1Max (0.6 nozzle).json b/resources/profiles/Creality/process/0.30mm Standard @Creality K1Max (0.6 nozzle).json index 35c05bc788..ead330c693 100644 --- a/resources/profiles/Creality/process/0.30mm Standard @Creality K1Max (0.6 nozzle).json +++ b/resources/profiles/Creality/process/0.30mm Standard @Creality K1Max (0.6 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.32mm Optimal @Creality K1 (0.8 nozzle).json b/resources/profiles/Creality/process/0.32mm Optimal @Creality K1 (0.8 nozzle).json index 9d6215dd60..4349548d87 100644 --- a/resources/profiles/Creality/process/0.32mm Optimal @Creality K1 (0.8 nozzle).json +++ b/resources/profiles/Creality/process/0.32mm Optimal @Creality K1 (0.8 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.32mm Optimal @Creality K1Max (0.8 nozzle).json b/resources/profiles/Creality/process/0.32mm Optimal @Creality K1Max (0.8 nozzle).json index a1f34a2032..21eac2347e 100644 --- a/resources/profiles/Creality/process/0.32mm Optimal @Creality K1Max (0.8 nozzle).json +++ b/resources/profiles/Creality/process/0.32mm Optimal @Creality K1Max (0.8 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.36mm Draft @Creality K1 (0.6 nozzle).json b/resources/profiles/Creality/process/0.36mm Draft @Creality K1 (0.6 nozzle).json index 75b62fe90d..6b54d3c3e6 100644 --- a/resources/profiles/Creality/process/0.36mm Draft @Creality K1 (0.6 nozzle).json +++ b/resources/profiles/Creality/process/0.36mm Draft @Creality K1 (0.6 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.36mm Draft @Creality K1Max (0.6 nozzle).json b/resources/profiles/Creality/process/0.36mm Draft @Creality K1Max (0.6 nozzle).json index 7b1b504554..cf796e77cf 100644 --- a/resources/profiles/Creality/process/0.36mm Draft @Creality K1Max (0.6 nozzle).json +++ b/resources/profiles/Creality/process/0.36mm Draft @Creality K1Max (0.6 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.40mm Standard @Creality K1 (0.8 nozzle).json b/resources/profiles/Creality/process/0.40mm Standard @Creality K1 (0.8 nozzle).json index 10e4403891..a4c4cef212 100644 --- a/resources/profiles/Creality/process/0.40mm Standard @Creality K1 (0.8 nozzle).json +++ b/resources/profiles/Creality/process/0.40mm Standard @Creality K1 (0.8 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.40mm Standard @Creality K1Max (0.8 nozzle).json b/resources/profiles/Creality/process/0.40mm Standard @Creality K1Max (0.8 nozzle).json index b7697a2126..73ffc4dcd5 100644 --- a/resources/profiles/Creality/process/0.40mm Standard @Creality K1Max (0.8 nozzle).json +++ b/resources/profiles/Creality/process/0.40mm Standard @Creality K1Max (0.8 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.48mm Draft @Creality K1 (0.8 nozzle).json b/resources/profiles/Creality/process/0.48mm Draft @Creality K1 (0.8 nozzle).json index e15bea7c19..aa22d082e0 100644 --- a/resources/profiles/Creality/process/0.48mm Draft @Creality K1 (0.8 nozzle).json +++ b/resources/profiles/Creality/process/0.48mm Draft @Creality K1 (0.8 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/0.48mm Draft @Creality K1Max (0.8 nozzle).json b/resources/profiles/Creality/process/0.48mm Draft @Creality K1Max (0.8 nozzle).json index e095329a9d..3f50fcec4c 100644 --- a/resources/profiles/Creality/process/0.48mm Draft @Creality K1Max (0.8 nozzle).json +++ b/resources/profiles/Creality/process/0.48mm Draft @Creality K1Max (0.8 nozzle).json @@ -103,9 +103,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.6", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0", diff --git a/resources/profiles/Creality/process/fdm_process_creality_common.json b/resources/profiles/Creality/process/fdm_process_creality_common.json index c652dd2960..5d6c90e849 100644 --- a/resources/profiles/Creality/process/fdm_process_creality_common.json +++ b/resources/profiles/Creality/process/fdm_process_creality_common.json @@ -98,7 +98,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0" } diff --git a/resources/profiles/Custom/machine/fdm_machine_common.json b/resources/profiles/Custom/machine/fdm_machine_common.json index 76cfe3d36c..28ee8f30b5 100644 --- a/resources/profiles/Custom/machine/fdm_machine_common.json +++ b/resources/profiles/Custom/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Custom/process/fdm_process_klipper_common.json b/resources/profiles/Custom/process/fdm_process_klipper_common.json index 99e4d84fe1..111573307d 100644 --- a/resources/profiles/Custom/process/fdm_process_klipper_common.json +++ b/resources/profiles/Custom/process/fdm_process_klipper_common.json @@ -98,7 +98,7 @@ "travel_speed": "350", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "enable_arc_fitting": "0", diff --git a/resources/profiles/Custom/process/fdm_process_marlin_common.json b/resources/profiles/Custom/process/fdm_process_marlin_common.json index 125431d1ea..4ca361a2ed 100644 --- a/resources/profiles/Custom/process/fdm_process_marlin_common.json +++ b/resources/profiles/Custom/process/fdm_process_marlin_common.json @@ -98,7 +98,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "enable_arc_fitting": "0", diff --git a/resources/profiles/Elegoo/machine/Elegoo Neptune 0.4 nozzle.json b/resources/profiles/Elegoo/machine/Elegoo Neptune 0.4 nozzle.json index d0e7069db6..6a143def8d 100644 --- a/resources/profiles/Elegoo/machine/Elegoo Neptune 0.4 nozzle.json +++ b/resources/profiles/Elegoo/machine/Elegoo Neptune 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Elegoo/machine/Elegoo Neptune 2 0.4 nozzle.json b/resources/profiles/Elegoo/machine/Elegoo Neptune 2 0.4 nozzle.json index 1829a28c7f..12232ca4c6 100644 --- a/resources/profiles/Elegoo/machine/Elegoo Neptune 2 0.4 nozzle.json +++ b/resources/profiles/Elegoo/machine/Elegoo Neptune 2 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Elegoo/machine/Elegoo Neptune 2S 0.4 nozzle.json b/resources/profiles/Elegoo/machine/Elegoo Neptune 2S 0.4 nozzle.json index f1f9bb254f..8a8a25be54 100644 --- a/resources/profiles/Elegoo/machine/Elegoo Neptune 2S 0.4 nozzle.json +++ b/resources/profiles/Elegoo/machine/Elegoo Neptune 2S 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Elegoo/machine/Elegoo Neptune 3 0.4 nozzle.json b/resources/profiles/Elegoo/machine/Elegoo Neptune 3 0.4 nozzle.json index e948cdf344..2797bf8141 100644 --- a/resources/profiles/Elegoo/machine/Elegoo Neptune 3 0.4 nozzle.json +++ b/resources/profiles/Elegoo/machine/Elegoo Neptune 3 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Max 0.4 nozzle.json b/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Max 0.4 nozzle.json index 7976ac0c94..444ec5061d 100644 --- a/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Max 0.4 nozzle.json +++ b/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Max 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Plus 0.4 nozzle.json b/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Plus 0.4 nozzle.json index e6b96b2bf0..307a349215 100644 --- a/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Plus 0.4 nozzle.json +++ b/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Plus 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Pro 0.4 nozzle.json b/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Pro 0.4 nozzle.json index 84b1084216..25f1a5dad6 100644 --- a/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Pro 0.4 nozzle.json +++ b/resources/profiles/Elegoo/machine/Elegoo Neptune 3 Pro 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Elegoo/machine/Elegoo Neptune X 0.4 nozzle.json b/resources/profiles/Elegoo/machine/Elegoo Neptune X 0.4 nozzle.json index 25055f6b2b..8f108f6865 100644 --- a/resources/profiles/Elegoo/machine/Elegoo Neptune X 0.4 nozzle.json +++ b/resources/profiles/Elegoo/machine/Elegoo Neptune X 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Elegoo/machine/fdm_machine_common.json b/resources/profiles/Elegoo/machine/fdm_machine_common.json index 41b1832169..a1dc826252 100644 --- a/resources/profiles/Elegoo/machine/fdm_machine_common.json +++ b/resources/profiles/Elegoo/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "35" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/FLSun/machine/FLSun Q5 0.4 nozzle.json b/resources/profiles/FLSun/machine/FLSun Q5 0.4 nozzle.json index 2960a0f2fd..0e17d1200a 100644 --- a/resources/profiles/FLSun/machine/FLSun Q5 0.4 nozzle.json +++ b/resources/profiles/FLSun/machine/FLSun Q5 0.4 nozzle.json @@ -176,7 +176,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M400 U1\n", "default_filament_profile": [ diff --git a/resources/profiles/FLSun/machine/FLSun QQ-S Pro 0.4 nozzle.json b/resources/profiles/FLSun/machine/FLSun QQ-S Pro 0.4 nozzle.json index b49b467e5c..6b62e0e2fc 100644 --- a/resources/profiles/FLSun/machine/FLSun QQ-S Pro 0.4 nozzle.json +++ b/resources/profiles/FLSun/machine/FLSun QQ-S Pro 0.4 nozzle.json @@ -176,7 +176,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M400 U1\n", "default_filament_profile": [ diff --git a/resources/profiles/FLSun/process/fdm_process_common.json b/resources/profiles/FLSun/process/fdm_process_common.json index f2bc39f18c..ec9c890150 100644 --- a/resources/profiles/FLSun/process/fdm_process_common.json +++ b/resources/profiles/FLSun/process/fdm_process_common.json @@ -84,9 +84,9 @@ "top_surface_pattern": "monotonic", "top_surface_line_width": "0.4", "top_shell_thickness": "0.8", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "layer_height": "0.2", diff --git a/resources/profiles/Folgertech/machine/fdm_machine_common.json b/resources/profiles/Folgertech/machine/fdm_machine_common.json index 41d458f5b2..fe27b6027b 100644 --- a/resources/profiles/Folgertech/machine/fdm_machine_common.json +++ b/resources/profiles/Folgertech/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Folgertech/process/fdm_process_folgertech_common.json b/resources/profiles/Folgertech/process/fdm_process_folgertech_common.json index be856a99a3..8a37312557 100644 --- a/resources/profiles/Folgertech/process/fdm_process_folgertech_common.json +++ b/resources/profiles/Folgertech/process/fdm_process_folgertech_common.json @@ -98,7 +98,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0" } \ No newline at end of file diff --git a/resources/profiles/Kingroon/process/fdm_process_common.json b/resources/profiles/Kingroon/process/fdm_process_common.json index 919b751d28..daf672e289 100644 --- a/resources/profiles/Kingroon/process/fdm_process_common.json +++ b/resources/profiles/Kingroon/process/fdm_process_common.json @@ -94,7 +94,7 @@ "post_process": [], "precise_outer_wall": "0", "prime_tower_brim_width": "3", - "prime_tower_width": "35", + "prime_tower_width": "60", "prime_volume": "45", "print_flow_ratio": "1", "print_sequence": "by layer", diff --git a/resources/profiles/OrcaArena/machine/fdm_machine_common.json b/resources/profiles/OrcaArena/machine/fdm_machine_common.json index fc6f3492c5..7552d1251f 100644 --- a/resources/profiles/OrcaArena/machine/fdm_machine_common.json +++ b/resources/profiles/OrcaArena/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/OrcaArena/process/0.20mm Bambu Support W @Arena X1C.json b/resources/profiles/OrcaArena/process/0.20mm Bambu Support W @Arena X1C.json index 5b43bbb1c3..b31526453e 100644 --- a/resources/profiles/OrcaArena/process/0.20mm Bambu Support W @Arena X1C.json +++ b/resources/profiles/OrcaArena/process/0.20mm Bambu Support W @Arena X1C.json @@ -13,7 +13,7 @@ "support_interface_speed": "80", "support_filament": "0", "support_interface_filament": "0", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "compatible_printers": [ "Orca Arena X1 Carbon 0.4 nozzle", "Orca Arena X1 0.4 nozzle" diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_common.json b/resources/profiles/OrcaArena/process/fdm_process_bbl_common.json index 9115d69522..c5505d4381 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_common.json +++ b/resources/profiles/OrcaArena/process/fdm_process_bbl_common.json @@ -102,9 +102,9 @@ "top_shell_layers": "3", "top_shell_thickness": "0.8", "travel_speed": "500", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "gcode_label_objects": "0" diff --git a/resources/profiles/Prusa/process/fdm_process_common.json b/resources/profiles/Prusa/process/fdm_process_common.json index 9bff8921f6..59955bd92b 100644 --- a/resources/profiles/Prusa/process/fdm_process_common.json +++ b/resources/profiles/Prusa/process/fdm_process_common.json @@ -85,7 +85,7 @@ "detect_thin_wall": "0", "top_surface_pattern": "monotonic", "top_shell_thickness": "0.8", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", "prime_tower_width": "60", "xy_hole_compensation": "0", @@ -102,5 +102,6 @@ "internal_solid_infill_speed": "150", "top_surface_speed": "50", "gap_infill_speed": "30", - "travel_speed": "200" + "travel_speed": "200", + "prime_tower_width": "60" } diff --git a/resources/profiles/Qidi/machine/Qidi X-CF Pro 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-CF Pro 0.4 nozzle.json index 62a6acc62c..0ac09ea7ac 100644 --- a/resources/profiles/Qidi/machine/Qidi X-CF Pro 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi X-CF Pro 0.4 nozzle.json @@ -94,7 +94,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Qidi/machine/Qidi X-Max 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Max 0.4 nozzle.json index 2505730d9e..4415483f2c 100644 --- a/resources/profiles/Qidi/machine/Qidi X-Max 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi X-Max 0.4 nozzle.json @@ -94,7 +94,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Qidi/machine/Qidi X-Max 3 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Max 3 0.4 nozzle.json index b2c8a1840c..4ae4633743 100644 --- a/resources/profiles/Qidi/machine/Qidi X-Max 3 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi X-Max 3 0.4 nozzle.json @@ -39,7 +39,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Qidi/machine/Qidi X-Plus 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Plus 0.4 nozzle.json index c722d7ca34..678df6a8d8 100644 --- a/resources/profiles/Qidi/machine/Qidi X-Plus 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi X-Plus 0.4 nozzle.json @@ -94,7 +94,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Qidi/machine/Qidi X-Plus 3 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Plus 3 0.4 nozzle.json index 71723a2a86..21b889fdff 100644 --- a/resources/profiles/Qidi/machine/Qidi X-Plus 3 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi X-Plus 3 0.4 nozzle.json @@ -38,7 +38,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Qidi/machine/Qidi X-Smart 3 0.4 nozzle.json b/resources/profiles/Qidi/machine/Qidi X-Smart 3 0.4 nozzle.json index 6b366aad7a..960088e7b7 100644 --- a/resources/profiles/Qidi/machine/Qidi X-Smart 3 0.4 nozzle.json +++ b/resources/profiles/Qidi/machine/Qidi X-Smart 3 0.4 nozzle.json @@ -39,7 +39,7 @@ "deretraction_speed": [ "0" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Qidi/machine/fdm_machine_common.json b/resources/profiles/Qidi/machine/fdm_machine_common.json index 41d458f5b2..fe27b6027b 100644 --- a/resources/profiles/Qidi/machine/fdm_machine_common.json +++ b/resources/profiles/Qidi/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Qidi/process/fdm_process_qidi_common.json b/resources/profiles/Qidi/process/fdm_process_qidi_common.json index 1f0df8f0b9..5edeca4933 100644 --- a/resources/profiles/Qidi/process/fdm_process_qidi_common.json +++ b/resources/profiles/Qidi/process/fdm_process_qidi_common.json @@ -97,7 +97,7 @@ "travel_speed": "150", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0" } diff --git a/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Dual).json b/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Dual).json index 5dace67d12..e4d75cb2b4 100644 --- a/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Dual).json +++ b/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Dual).json @@ -137,7 +137,7 @@ "1", "1" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "; pause print\nM2000", "default_filament_profile": [ diff --git a/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Left).json b/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Left).json index d79d069db5..8c89040903 100644 --- a/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Left).json +++ b/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Left).json @@ -137,7 +137,7 @@ "1", "1" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "; pause print\nM2000", "default_filament_profile": [ diff --git a/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Right).json b/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Right).json index 4ebee246cd..6c1eb6a984 100644 --- a/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Right).json +++ b/resources/profiles/Raise3D/machine/Raise3D Pro3 0.4 nozzle (Right).json @@ -137,7 +137,7 @@ "1", "1" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "; pause print\nM2000", "default_filament_profile": [ diff --git a/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Dual).json b/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Dual).json index 27d82e0508..dd127639e6 100644 --- a/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Dual).json +++ b/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Dual).json @@ -137,7 +137,7 @@ "1", "1" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "; pause print\nM2000", "default_filament_profile": [ diff --git a/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Left).json b/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Left).json index ea2ec01cd3..de1b5a6412 100644 --- a/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Left).json +++ b/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Left).json @@ -137,7 +137,7 @@ "1", "1" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "; pause print\nM2000", "default_filament_profile": [ diff --git a/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Right).json b/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Right).json index d03f8ff915..a341ff76f8 100644 --- a/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Right).json +++ b/resources/profiles/Raise3D/machine/Raise3D Pro3 Plus 0.4 nozzle (Right).json @@ -137,7 +137,7 @@ "1", "1" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "; pause print\nM2000", "default_filament_profile": [ diff --git a/resources/profiles/Raise3D/machine/fdm_machine_common.json b/resources/profiles/Raise3D/machine/fdm_machine_common.json index 56e8374ef7..f537b78c6f 100644 --- a/resources/profiles/Raise3D/machine/fdm_machine_common.json +++ b/resources/profiles/Raise3D/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Ratrig/machine/fdm_machine_common.json b/resources/profiles/Ratrig/machine/fdm_machine_common.json index f99c783367..a18c3333ca 100644 --- a/resources/profiles/Ratrig/machine/fdm_machine_common.json +++ b/resources/profiles/Ratrig/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Ratrig/process/0.20mm Bambu Support W @RatRig.json b/resources/profiles/Ratrig/process/0.20mm Bambu Support W @RatRig.json index 6a253ce865..80f22216af 100644 --- a/resources/profiles/Ratrig/process/0.20mm Bambu Support W @RatRig.json +++ b/resources/profiles/Ratrig/process/0.20mm Bambu Support W @RatRig.json @@ -13,7 +13,7 @@ "support_interface_speed": "80", "support_filament": "0", "support_interface_filament": "0", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "initial_layer_speed": "50", "initial_layer_infill_speed": "105", "outer_wall_speed": "120", diff --git a/resources/profiles/Ratrig/process/fdm_process_ratrig_common.json b/resources/profiles/Ratrig/process/fdm_process_ratrig_common.json index 57e768e1ac..136a4295d2 100644 --- a/resources/profiles/Ratrig/process/fdm_process_ratrig_common.json +++ b/resources/profiles/Ratrig/process/fdm_process_ratrig_common.json @@ -99,7 +99,7 @@ "travel_speed": "350", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "enable_arc_fitting": "0", diff --git a/resources/profiles/SecKit/machine/fdm_machine_common.json b/resources/profiles/SecKit/machine/fdm_machine_common.json index 9163690443..1e8a72ddfc 100644 --- a/resources/profiles/SecKit/machine/fdm_machine_common.json +++ b/resources/profiles/SecKit/machine/fdm_machine_common.json @@ -108,7 +108,7 @@ "retraction_speed": [ "120" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/SecKit/process/fdm_process_seckit_common.json b/resources/profiles/SecKit/process/fdm_process_seckit_common.json index 7c8e6df434..1ad7b2d9a7 100644 --- a/resources/profiles/SecKit/process/fdm_process_seckit_common.json +++ b/resources/profiles/SecKit/process/fdm_process_seckit_common.json @@ -97,7 +97,7 @@ "travel_speed": "235", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "enable_arc_fitting": "0", diff --git a/resources/profiles/Snapmaker/process/fdm_process_common.json b/resources/profiles/Snapmaker/process/fdm_process_common.json index 877f08b9fb..6cfb587794 100644 --- a/resources/profiles/Snapmaker/process/fdm_process_common.json +++ b/resources/profiles/Snapmaker/process/fdm_process_common.json @@ -83,9 +83,9 @@ "top_surface_pattern": "monotonic", "top_surface_line_width": "0.4", "top_shell_thickness": "0.8", - "enable_prime_tower": "1", + "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "layer_height": "0.2", diff --git a/resources/profiles/Sovol/machine/Sovol SV01 Pro 0.4 nozzle.json b/resources/profiles/Sovol/machine/Sovol SV01 Pro 0.4 nozzle.json index 6e74b58852..5702397a43 100644 --- a/resources/profiles/Sovol/machine/Sovol SV01 Pro 0.4 nozzle.json +++ b/resources/profiles/Sovol/machine/Sovol SV01 Pro 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Sovol/machine/Sovol SV05 0.4 nozzle.json b/resources/profiles/Sovol/machine/Sovol SV05 0.4 nozzle.json index ee4c86210a..dc3a2aa435 100644 --- a/resources/profiles/Sovol/machine/Sovol SV05 0.4 nozzle.json +++ b/resources/profiles/Sovol/machine/Sovol SV05 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Sovol/machine/Sovol SV06 0.4 nozzle.json b/resources/profiles/Sovol/machine/Sovol SV06 0.4 nozzle.json index 2db824de74..fec43b9303 100644 --- a/resources/profiles/Sovol/machine/Sovol SV06 0.4 nozzle.json +++ b/resources/profiles/Sovol/machine/Sovol SV06 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "30" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600\nG1 E0.4 F1500 ; prime after color change", "machine_pause_gcode": "M601", "default_filament_profile": [ diff --git a/resources/profiles/Sovol/machine/Sovol SV06 Plus 0.4 nozzle.json b/resources/profiles/Sovol/machine/Sovol SV06 Plus 0.4 nozzle.json index 63133e1b1a..d75d181a11 100644 --- a/resources/profiles/Sovol/machine/Sovol SV06 Plus 0.4 nozzle.json +++ b/resources/profiles/Sovol/machine/Sovol SV06 Plus 0.4 nozzle.json @@ -100,7 +100,7 @@ "deretraction_speed": [ "30" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600\nG1 E0.4 F1500 ; prime after color change", "machine_pause_gcode": "M601", "default_filament_profile": [ diff --git a/resources/profiles/Sovol/machine/fdm_machine_common.json b/resources/profiles/Sovol/machine/fdm_machine_common.json index 56e8374ef7..f537b78c6f 100644 --- a/resources/profiles/Sovol/machine/fdm_machine_common.json +++ b/resources/profiles/Sovol/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Tronxy/machine/fdm_machine_common.json b/resources/profiles/Tronxy/machine/fdm_machine_common.json index 08a818ba46..5eaa07e526 100644 --- a/resources/profiles/Tronxy/machine/fdm_machine_common.json +++ b/resources/profiles/Tronxy/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Tronxy/process/fdm_process_common.json b/resources/profiles/Tronxy/process/fdm_process_common.json index 0513467cac..d9b11e2551 100644 --- a/resources/profiles/Tronxy/process/fdm_process_common.json +++ b/resources/profiles/Tronxy/process/fdm_process_common.json @@ -94,7 +94,7 @@ "travel_speed": "350", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Tronxy/process/fdm_process_tronxy_common.json b/resources/profiles/Tronxy/process/fdm_process_tronxy_common.json index 2d6fa3ff06..99b1ec95ff 100644 --- a/resources/profiles/Tronxy/process/fdm_process_tronxy_common.json +++ b/resources/profiles/Tronxy/process/fdm_process_tronxy_common.json @@ -95,7 +95,7 @@ "travel_speed": "350", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/TwoTrees/machine/fdm_machine_common.json b/resources/profiles/TwoTrees/machine/fdm_machine_common.json index 08a818ba46..5eaa07e526 100644 --- a/resources/profiles/TwoTrees/machine/fdm_machine_common.json +++ b/resources/profiles/TwoTrees/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/TwoTrees/process/fdm_process_TwoTrees_common.json b/resources/profiles/TwoTrees/process/fdm_process_TwoTrees_common.json index 80927634fd..73b67bc1c3 100644 --- a/resources/profiles/TwoTrees/process/fdm_process_TwoTrees_common.json +++ b/resources/profiles/TwoTrees/process/fdm_process_TwoTrees_common.json @@ -95,7 +95,7 @@ "travel_speed": "350", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/TwoTrees/process/fdm_process_common.json b/resources/profiles/TwoTrees/process/fdm_process_common.json index fd2dbb99ee..f3033727b3 100644 --- a/resources/profiles/TwoTrees/process/fdm_process_common.json +++ b/resources/profiles/TwoTrees/process/fdm_process_common.json @@ -93,7 +93,7 @@ "travel_speed": "350", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "enable_arc_fitting": "0", diff --git a/resources/profiles/UltiMaker/machine/UltiMaker 2 0.4 nozzle.json b/resources/profiles/UltiMaker/machine/UltiMaker 2 0.4 nozzle.json index c7166bc030..70f54edf1b 100644 --- a/resources/profiles/UltiMaker/machine/UltiMaker 2 0.4 nozzle.json +++ b/resources/profiles/UltiMaker/machine/UltiMaker 2 0.4 nozzle.json @@ -103,7 +103,7 @@ "wipe_distance": [ "0.2" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/UltiMaker/machine/fdm_machine_common.json b/resources/profiles/UltiMaker/machine/fdm_machine_common.json index bb2cfc5823..b048451fd8 100644 --- a/resources/profiles/UltiMaker/machine/fdm_machine_common.json +++ b/resources/profiles/UltiMaker/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "50" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Vivedino/machine/fdm_machine_common.json b/resources/profiles/Vivedino/machine/fdm_machine_common.json index 76cfe3d36c..28ee8f30b5 100644 --- a/resources/profiles/Vivedino/machine/fdm_machine_common.json +++ b/resources/profiles/Vivedino/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Vivedino/process/fdm_process_klipper_common.json b/resources/profiles/Vivedino/process/fdm_process_klipper_common.json index 8f4936a889..19176b5504 100644 --- a/resources/profiles/Vivedino/process/fdm_process_klipper_common.json +++ b/resources/profiles/Vivedino/process/fdm_process_klipper_common.json @@ -99,7 +99,7 @@ "travel_speed": "350", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "enable_arc_fitting": "0", diff --git a/resources/profiles/Voron/machine/fdm_machine_common.json b/resources/profiles/Voron/machine/fdm_machine_common.json index 5d141cce1b..8d4fb897f1 100644 --- a/resources/profiles/Voron/machine/fdm_machine_common.json +++ b/resources/profiles/Voron/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Voron/process/fdm_process_voron_common.json b/resources/profiles/Voron/process/fdm_process_voron_common.json index 48d8772e96..5701d30664 100644 --- a/resources/profiles/Voron/process/fdm_process_voron_common.json +++ b/resources/profiles/Voron/process/fdm_process_voron_common.json @@ -99,7 +99,7 @@ "travel_speed": "350", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0", "xy_contour_compensation": "0", "enable_arc_fitting": "0", diff --git a/resources/profiles/Voxelab/machine/Voxelab Aquila X2 0.4 nozzle.json b/resources/profiles/Voxelab/machine/Voxelab Aquila X2 0.4 nozzle.json index 23674b2f26..9fbb7e6cda 100644 --- a/resources/profiles/Voxelab/machine/Voxelab Aquila X2 0.4 nozzle.json +++ b/resources/profiles/Voxelab/machine/Voxelab Aquila X2 0.4 nozzle.json @@ -97,7 +97,7 @@ "deretraction_speed": [ "40" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "M600", "machine_pause_gcode": "M0", "default_filament_profile": [ diff --git a/resources/profiles/Voxelab/machine/fdm_machine_common.json b/resources/profiles/Voxelab/machine/fdm_machine_common.json index 56e8374ef7..f537b78c6f 100644 --- a/resources/profiles/Voxelab/machine/fdm_machine_common.json +++ b/resources/profiles/Voxelab/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Vzbot/machine/fdm_machine_common.json b/resources/profiles/Vzbot/machine/fdm_machine_common.json index 885d9dfd69..52345bfae7 100644 --- a/resources/profiles/Vzbot/machine/fdm_machine_common.json +++ b/resources/profiles/Vzbot/machine/fdm_machine_common.json @@ -105,7 +105,7 @@ "retraction_speed": [ "60" ], - "single_extruder_multi_material": "0", + "single_extruder_multi_material": "1", "change_filament_gcode": "", "wipe": [ "1" diff --git a/resources/profiles/Vzbot/process/fdm_process_Vzbot_common.json b/resources/profiles/Vzbot/process/fdm_process_Vzbot_common.json index b4e8f184f4..bf6689508d 100644 --- a/resources/profiles/Vzbot/process/fdm_process_Vzbot_common.json +++ b/resources/profiles/Vzbot/process/fdm_process_Vzbot_common.json @@ -101,7 +101,7 @@ "travel_speed": "800", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0.075", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Vzbot/process/fdm_process_Vzbot_common_0.5_nozzle.json b/resources/profiles/Vzbot/process/fdm_process_Vzbot_common_0.5_nozzle.json index 2aa584dd86..c496eb764b 100644 --- a/resources/profiles/Vzbot/process/fdm_process_Vzbot_common_0.5_nozzle.json +++ b/resources/profiles/Vzbot/process/fdm_process_Vzbot_common_0.5_nozzle.json @@ -100,7 +100,7 @@ "travel_speed": "800", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0.075", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/resources/profiles/Vzbot/process/fdm_process_Vzbot_common_0.6_nozzle.json b/resources/profiles/Vzbot/process/fdm_process_Vzbot_common_0.6_nozzle.json index 8a22c5d9be..b3d54e197e 100644 --- a/resources/profiles/Vzbot/process/fdm_process_Vzbot_common_0.6_nozzle.json +++ b/resources/profiles/Vzbot/process/fdm_process_Vzbot_common_0.6_nozzle.json @@ -100,7 +100,7 @@ "travel_speed": "800", "enable_prime_tower": "0", "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", + "prime_tower_width": "60", "xy_hole_compensation": "0.075", "xy_contour_compensation": "0", "compatible_printers": [ diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index d8cf96c547..76b6c3061c 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -142,6 +142,8 @@ set(lisbslic3r_sources GCode/ToolOrdering.hpp GCode/WipeTower.cpp GCode/WipeTower.hpp + GCode/WipeTower2.cpp + GCode/WipeTower2.hpp GCode/GCodeProcessor.cpp GCode/GCodeProcessor.hpp GCode/AvoidCrossingPerimeters.cpp diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 2472fe45cc..f14be40fcb 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -380,7 +381,7 @@ static std::vector get_path_of_change_filament(const Print& print) return Point(scale_(wipe_tower_pt.x() - gcodegen.origin()(0)), scale_(wipe_tower_pt.y() - gcodegen.origin()(1))); } - std::string WipeTowerIntegration::append_tcr(GCode& gcodegen, const WipeTower::ToolChangeResult& tcr, int new_extruder_id, double z) const + std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z) const { if (new_extruder_id != -1 && new_extruder_id != tcr.new_tool) throw Slic3r::InvalidArgument("Error: WipeTowerIntegration::append_tcr was asked to do a toolchange it didn't expect."); @@ -391,20 +392,20 @@ static std::vector get_path_of_change_filament(const Print& print) // We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position float alpha = m_wipe_tower_rotation / 180.f * float(M_PI); - auto transform_wt_pt = [&alpha, this](const Vec2f& pt) -> Vec2f { + auto transform_wt_pt = [&alpha, this](const Vec2f &pt) -> Vec2f { Vec2f out = Eigen::Rotation2Df(alpha) * pt; out += m_wipe_tower_pos; return out; }; Vec2f start_pos = tcr.start_pos; - Vec2f end_pos = tcr.end_pos; - if (! tcr.priming) { + Vec2f end_pos = tcr.end_pos; + if (!tcr.priming) { start_pos = transform_wt_pt(start_pos); - end_pos = transform_wt_pt(end_pos); + end_pos = transform_wt_pt(end_pos); } - Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos; + Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos; float wipe_tower_rotation = tcr.priming ? 0.f : alpha; std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation); @@ -415,42 +416,39 @@ static std::vector get_path_of_change_filament(const Print& print) // BBS: toolchange gcode will move to start_pos, // so only perform movement when printing sparse partition to support upper layer. // start_pos is the position in plate coordinate. - if (! tcr.priming && tcr.is_finish_first) { + if (!tcr.priming && tcr.is_finish_first) { // Move over the wipe tower. gcode += gcodegen.retract(); gcodegen.m_avoid_crossing_perimeters.use_external_mp_once(); - gcode += gcodegen.travel_to( - wipe_tower_point_to_object_point(gcodegen, start_pos + plate_origin_2d), - erMixed, - "Travel to a Wipe Tower"); + gcode += gcodegen.travel_to(wipe_tower_point_to_object_point(gcodegen, start_pos + plate_origin_2d), erMixed, + "Travel to a Wipe Tower"); gcode += gcodegen.unretract(); } - //BBS: if needed, write the gcode_label_objects_end then priming tower, if the retract, didn't did it. + // BBS: if needed, write the gcode_label_objects_end then priming tower, if the retract, didn't did it. gcodegen.m_writer.add_object_end_labels(gcode); double current_z = gcodegen.writer().get_position().z(); if (z == -1.) // in case no specific z was provided, print at current_z pos z = current_z; - if (! is_approx(z, current_z)) { + if (!is_approx(z, current_z)) { gcode += gcodegen.writer().retract(); gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer."); gcode += gcodegen.writer().unretract(); } - // Process the end filament gcode. std::string end_filament_gcode_str; if (gcodegen.writer().extruder() != nullptr) { // Process the custom filament_end_gcode in case of single_extruder_multi_material. - unsigned int old_extruder_id = gcodegen.writer().extruder()->id(); - const std::string& filament_end_gcode = gcodegen.config().filament_end_gcode.get_at(old_extruder_id); + unsigned int old_extruder_id = gcodegen.writer().extruder()->id(); + const std::string &filament_end_gcode = gcodegen.config().filament_end_gcode.get_at(old_extruder_id); if (gcodegen.writer().extruder() != nullptr && !filament_end_gcode.empty()) { end_filament_gcode_str = gcodegen.placeholder_parser_process("filament_end_gcode", filament_end_gcode, old_extruder_id); check_add_eol(end_filament_gcode_str); } } - //BBS: increase toolchange count + // BBS: increase toolchange count gcodegen.m_toolchange_count++; // BBS: should be placed before toolchange parsing @@ -459,45 +457,57 @@ static std::vector get_path_of_change_filament(const Print& print) // Process the custom change_filament_gcode. If it is empty, provide a simple Tn command to change the filament. // Otherwise, leave control to the user completely. - std::string toolchange_gcode_str; - const std::string& change_filament_gcode = gcodegen.config().change_filament_gcode.value; -// m_max_layer_z = std::max(m_max_layer_z, tcr.print_z); - if (! change_filament_gcode.empty()) { + std::string toolchange_gcode_str; + const std::string &change_filament_gcode = gcodegen.config().change_filament_gcode.value; + // m_max_layer_z = std::max(m_max_layer_z, tcr.print_z); + if (!change_filament_gcode.empty()) { DynamicConfig config; - int previous_extruder_id = gcodegen.writer().extruder() ? (int)gcodegen.writer().extruder()->id() : -1; + int previous_extruder_id = gcodegen.writer().extruder() ? (int) gcodegen.writer().extruder()->id() : -1; config.set_key_value("previous_extruder", new ConfigOptionInt(previous_extruder_id)); - config.set_key_value("next_extruder", new ConfigOptionInt((int)new_extruder_id)); + config.set_key_value("next_extruder", new ConfigOptionInt((int) new_extruder_id)); config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index)); config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z)); config.set_key_value("toolchange_z", new ConfigOptionFloat(z)); -// 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)); // BBS { - GCodeWriter& gcode_writer = gcodegen.m_writer; - FullPrintConfig& full_config = gcodegen.m_config; - float old_retract_length = gcode_writer.extruder() != nullptr ? full_config.retraction_length.get_at(previous_extruder_id) : 0; + GCodeWriter &gcode_writer = gcodegen.m_writer; + FullPrintConfig &full_config = gcodegen.m_config; + float old_retract_length = gcode_writer.extruder() != nullptr ? full_config.retraction_length.get_at(previous_extruder_id) : + 0; float new_retract_length = full_config.retraction_length.get_at(new_extruder_id); - float old_retract_length_toolchange = gcode_writer.extruder() != nullptr ? full_config.retract_length_toolchange.get_at(previous_extruder_id) : 0; + float old_retract_length_toolchange = gcode_writer.extruder() != nullptr ? + full_config.retract_length_toolchange.get_at(previous_extruder_id) : + 0; float new_retract_length_toolchange = full_config.retract_length_toolchange.get_at(new_extruder_id); - int old_filament_temp = gcode_writer.extruder() != nullptr ? (gcodegen.on_first_layer()? full_config.nozzle_temperature_initial_layer.get_at(previous_extruder_id) : full_config.nozzle_temperature.get_at(previous_extruder_id)) : 210; - int new_filament_temp = gcodegen.on_first_layer() ? full_config.nozzle_temperature_initial_layer.get_at(new_extruder_id) : full_config.nozzle_temperature.get_at(new_extruder_id); - Vec3d nozzle_pos = gcode_writer.get_position(); + int old_filament_temp = gcode_writer.extruder() != nullptr ? + (gcodegen.on_first_layer() ? + full_config.nozzle_temperature_initial_layer.get_at(previous_extruder_id) : + full_config.nozzle_temperature.get_at(previous_extruder_id)) : + 210; + int new_filament_temp = gcodegen.on_first_layer() ? full_config.nozzle_temperature_initial_layer.get_at(new_extruder_id) : + full_config.nozzle_temperature.get_at(new_extruder_id); + Vec3d nozzle_pos = gcode_writer.get_position(); - float purge_volume = tcr.purge_volume < EPSILON ? 0 : std::max(tcr.purge_volume, g_min_purge_volume); + float purge_volume = tcr.purge_volume < EPSILON ? 0 : std::max(tcr.purge_volume, g_min_purge_volume); float filament_area = float((M_PI / 4.f) * pow(full_config.filament_diameter.get_at(new_extruder_id), 2)); - float purge_length = purge_volume / filament_area; + float purge_length = purge_volume / filament_area; - int old_filament_e_feedrate = gcode_writer.extruder() != nullptr ? (int)(60.0 * full_config.filament_max_volumetric_speed.get_at(previous_extruder_id) / filament_area) : 200; - old_filament_e_feedrate = old_filament_e_feedrate == 0 ? 100 : old_filament_e_feedrate; - int new_filament_e_feedrate = (int)(60.0 * full_config.filament_max_volumetric_speed.get_at(new_extruder_id) / filament_area); - new_filament_e_feedrate = new_filament_e_feedrate == 0 ? 100 : new_filament_e_feedrate; + int old_filament_e_feedrate = gcode_writer.extruder() != nullptr ? + (int) (60.0 * full_config.filament_max_volumetric_speed.get_at(previous_extruder_id) / + filament_area) : + 200; + old_filament_e_feedrate = old_filament_e_feedrate == 0 ? 100 : old_filament_e_feedrate; + int new_filament_e_feedrate = (int) (60.0 * full_config.filament_max_volumetric_speed.get_at(new_extruder_id) / + filament_area); + new_filament_e_feedrate = new_filament_e_feedrate == 0 ? 100 : new_filament_e_feedrate; config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z)); config.set_key_value("relative_e_axis", new ConfigOptionBool(full_config.use_relative_e_distances)); - config.set_key_value("toolchange_count", new ConfigOptionInt((int)gcodegen.m_toolchange_count)); - //BBS: fan speed is useless placeholer now, but we don't remove it to avoid - //slicing error in old change_filament_gcode in old 3MF - config.set_key_value("fan_speed", new ConfigOptionInt((int)0)); + config.set_key_value("toolchange_count", new ConfigOptionInt((int) gcodegen.m_toolchange_count)); + // BBS: fan speed is useless placeholer now, but we don't remove it to avoid + // slicing error in old change_filament_gcode in old 3MF + config.set_key_value("fan_speed", new ConfigOptionInt((int) 0)); config.set_key_value("old_retract_length", new ConfigOptionFloat(old_retract_length)); config.set_key_value("new_retract_length", new ConfigOptionFloat(new_retract_length)); config.set_key_value("old_retract_length_toolchange", new ConfigOptionFloat(old_retract_length_toolchange)); @@ -518,44 +528,46 @@ static std::vector get_path_of_change_filament(const Print& print) config.set_key_value("travel_point_3_x", new ConfigOptionFloat(float(travel_point_3.x()))); config.set_key_value("travel_point_3_y", new ConfigOptionFloat(float(travel_point_3.y()))); - int flush_count = std::min(g_max_flush_count, (int)std::round(purge_volume / g_purge_volume_one_time)); - float flush_unit = purge_length / flush_count; - int flush_idx = 0; + int flush_count = std::min(g_max_flush_count, (int) std::round(purge_volume / g_purge_volume_one_time)); + float flush_unit = purge_length / flush_count; + int flush_idx = 0; for (; flush_idx < flush_count; flush_idx++) { - char key_value[64] = { 0 }; + char key_value[64] = {0}; snprintf(key_value, sizeof(key_value), "flush_length_%d", flush_idx + 1); config.set_key_value(key_value, new ConfigOptionFloat(flush_unit)); } for (; flush_idx < g_max_flush_count; flush_idx++) { - char key_value[64] = { 0 }; + char key_value[64] = {0}; snprintf(key_value, sizeof(key_value), "flush_length_%d", flush_idx + 1); config.set_key_value(key_value, new ConfigOptionFloat(0.f)); } } - toolchange_gcode_str = gcodegen.placeholder_parser_process("change_filament_gcode", change_filament_gcode, new_extruder_id, &config); + toolchange_gcode_str = gcodegen.placeholder_parser_process("change_filament_gcode", change_filament_gcode, new_extruder_id, + &config); check_add_eol(toolchange_gcode_str); // retract before toolchange toolchange_gcode_str = toolchange_retract_str + toolchange_gcode_str; - //BBS + // BBS { - //BBS: current position and fan_speed is unclear after interting change_filament_gcode + // BBS: current position and fan_speed is unclear after interting change_filament_gcode check_add_eol(toolchange_gcode_str); toolchange_gcode_str += ";_FORCE_RESUME_FAN_SPEED\n"; gcodegen.writer().set_current_position_clear(false); - //BBS: check whether custom gcode changes the z position. Update if changed + // BBS: check whether custom gcode changes the z position. Update if changed double temp_z_after_tool_change; if (GCodeProcessor::get_last_z_from_gcode(toolchange_gcode_str, temp_z_after_tool_change)) { Vec3d pos = gcodegen.writer().get_position(); - pos(2) = temp_z_after_tool_change; + pos(2) = temp_z_after_tool_change; gcodegen.writer().set_position(pos); } } // move to start_pos for wiping after toolchange std::string start_pos_str; - start_pos_str = gcodegen.travel_to(wipe_tower_point_to_object_point(gcodegen, start_pos + plate_origin_2d), erMixed, "Move to start pos"); + start_pos_str = gcodegen.travel_to(wipe_tower_point_to_object_point(gcodegen, start_pos + plate_origin_2d), erMixed, + "Move to start pos"); check_add_eol(start_pos_str); toolchange_gcode_str += start_pos_str; @@ -576,13 +588,14 @@ static std::vector get_path_of_change_filament(const Print& print) gcodegen.placeholder_parser().set("current_extruder", new_extruder_id); // Process the start filament gcode. - std::string start_filament_gcode_str; - const std::string& filament_start_gcode = gcodegen.config().filament_start_gcode.get_at(new_extruder_id); + std::string start_filament_gcode_str; + const std::string &filament_start_gcode = gcodegen.config().filament_start_gcode.get_at(new_extruder_id); if (!filament_start_gcode.empty()) { // Process the filament_start_gcode for the active filament only. DynamicConfig config; config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id)); - start_filament_gcode_str = gcodegen.placeholder_parser_process("filament_start_gcode", filament_start_gcode, new_extruder_id, &config); + start_filament_gcode_str = gcodegen.placeholder_parser_process("filament_start_gcode", filament_start_gcode, new_extruder_id, + &config); check_add_eol(start_filament_gcode_str); } @@ -591,12 +604,13 @@ static std::vector get_path_of_change_filament(const Print& print) config.set_key_value("filament_end_gcode", new ConfigOptionString(end_filament_gcode_str)); config.set_key_value("change_filament_gcode", new ConfigOptionString(toolchange_gcode_str)); config.set_key_value("filament_start_gcode", new ConfigOptionString(start_filament_gcode_str)); - std::string tcr_gcode, tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config); + std::string tcr_gcode, + tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config); unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode); gcode += tcr_gcode; check_add_eol(toolchange_gcode_str); - //SoftFever: set new PA for new filament + // SoftFever: set new PA for new filament if (gcodegen.config().enable_pressure_advance.get_at(new_extruder_id)) { gcode += gcodegen.writer().set_pressure_advance(gcodegen.config().pressure_advance.get_at(new_extruder_id)); } @@ -613,7 +627,193 @@ static std::vector get_path_of_change_filament(const Print& print) else { // Prepare a future wipe. gcodegen.m_wipe.reset_path(); - for (const Vec2f& wipe_pt : tcr.wipe_path) + for (const Vec2f &wipe_pt : tcr.wipe_path) + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, transform_wt_pt(wipe_pt))); + } + + // Let the planner know we are traveling between objects. + gcodegen.m_avoid_crossing_perimeters.use_external_mp_once(); + return gcode; + } + + std::string WipeTowerIntegration::append_tcr2(GCode &gcodegen, + const WipeTower::ToolChangeResult &tcr, + int new_extruder_id, + double z) const + { + if (new_extruder_id != -1 && new_extruder_id != tcr.new_tool) + throw Slic3r::InvalidArgument("Error: WipeTowerIntegration::append_tcr was asked to do a toolchange it didn't expect."); + + std::string gcode; + + // Toolchangeresult.gcode assumes the wipe tower corner is at the origin (except for priming lines) + // We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position + float alpha = m_wipe_tower_rotation / 180.f * float(M_PI); + + auto transform_wt_pt = [&alpha, this](const Vec2f &pt) -> Vec2f { + Vec2f out = Eigen::Rotation2Df(alpha) * pt; + out += m_wipe_tower_pos; + return out; + }; + + Vec2f start_pos = tcr.start_pos; + Vec2f end_pos = tcr.end_pos; + if (!tcr.priming) { + start_pos = transform_wt_pt(start_pos); + end_pos = transform_wt_pt(end_pos); + } + + Vec2f wipe_tower_offset = tcr.priming ? Vec2f::Zero() : m_wipe_tower_pos; + float wipe_tower_rotation = tcr.priming ? 0.f : alpha; + + std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation); + + gcode += gcodegen.writer().unlift(); // Make sure there is no z-hop (in most cases, there isn't). + + double current_z = gcodegen.writer().get_position().z(); + if (z == -1.) // in case no specific z was provided, print at current_z pos + z = current_z; + + const bool needs_toolchange = gcodegen.writer().need_toolchange(new_extruder_id); + const bool will_go_down = !is_approx(z, current_z); + const bool is_ramming = (gcodegen.config().single_extruder_multi_material) || + (!gcodegen.config().single_extruder_multi_material && + gcodegen.config().filament_multitool_ramming.get_at(tcr.initial_tool)); + const bool should_travel_to_tower = !tcr.priming && (tcr.force_travel // wipe tower says so + || !needs_toolchange // this is just finishing the tower with no toolchange + || is_ramming); + + if (should_travel_to_tower) { + // FIXME: It would be better if the wipe tower set the force_travel flag for all toolchanges, + // then we could simplify the condition and make it more readable. + gcode += gcodegen.retract(); + gcodegen.m_avoid_crossing_perimeters.use_external_mp_once(); + gcode += gcodegen.travel_to(wipe_tower_point_to_object_point(gcodegen, start_pos), erMixed, "Travel to a Wipe Tower"); + gcode += gcodegen.unretract(); + } else { + // When this is multiextruder printer without any ramming, we can just change + // the tool without travelling to the tower. + } + + if (will_go_down) { + gcode += gcodegen.writer().retract(); + gcode += gcodegen.writer().travel_to_z(z, "Travel down to the last wipe tower layer."); + gcode += gcodegen.writer().unretract(); + } + + std::string toolchange_gcode_str; + std::string deretraction_str; + if (tcr.priming || (new_extruder_id >= 0 && needs_toolchange)) { + if (is_ramming) + gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines. + toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z + if (gcodegen.config().has_prime_tower) + deretraction_str = gcodegen.unretract(); + } + + // Insert the toolchange and deretraction gcode into the generated gcode. + + DynamicConfig config; + config.set_key_value("change_filament_gcode", new ConfigOptionString(toolchange_gcode_str)); + config.set_key_value("deretraction_from_wipe_tower_generator", new ConfigOptionString(deretraction_str)); + + int previous_extruder_id = gcodegen.writer().extruder() ? (int) gcodegen.writer().extruder()->id() : -1; + config.set_key_value("previous_extruder", new ConfigOptionInt(previous_extruder_id)); + config.set_key_value("next_extruder", new ConfigOptionInt((int) new_extruder_id)); + config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index)); + config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z)); + config.set_key_value("toolchange_z", new ConfigOptionFloat(z)); + GCodeWriter &gcode_writer = gcodegen.m_writer; + FullPrintConfig &full_config = gcodegen.m_config; + float old_retract_length = gcode_writer.extruder() != nullptr ? full_config.retraction_length.get_at(previous_extruder_id) : 0; + float new_retract_length = full_config.retraction_length.get_at(new_extruder_id); + float old_retract_length_toolchange = gcode_writer.extruder() != nullptr ? + full_config.retract_length_toolchange.get_at(previous_extruder_id) : + 0; + float new_retract_length_toolchange = full_config.retract_length_toolchange.get_at(new_extruder_id); + int old_filament_temp = gcode_writer.extruder() != nullptr ? + (gcodegen.on_first_layer() ? full_config.nozzle_temperature_initial_layer.get_at(previous_extruder_id) : + full_config.nozzle_temperature.get_at(previous_extruder_id)) : + 210; + int new_filament_temp = gcodegen.on_first_layer() ? full_config.nozzle_temperature_initial_layer.get_at(new_extruder_id) : + full_config.nozzle_temperature.get_at(new_extruder_id); + Vec3d nozzle_pos = gcode_writer.get_position(); + + float purge_volume = tcr.purge_volume < EPSILON ? 0 : std::max(tcr.purge_volume, g_min_purge_volume); + float filament_area = float((M_PI / 4.f) * pow(full_config.filament_diameter.get_at(new_extruder_id), 2)); + float purge_length = purge_volume / filament_area; + + int old_filament_e_feedrate = gcode_writer.extruder() != nullptr ? + (int) (60.0 * full_config.filament_max_volumetric_speed.get_at(previous_extruder_id) / + filament_area) : + 200; + old_filament_e_feedrate = old_filament_e_feedrate == 0 ? 100 : old_filament_e_feedrate; + int new_filament_e_feedrate = (int) (60.0 * full_config.filament_max_volumetric_speed.get_at(new_extruder_id) / filament_area); + new_filament_e_feedrate = new_filament_e_feedrate == 0 ? 100 : new_filament_e_feedrate; + + config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z)); + config.set_key_value("relative_e_axis", new ConfigOptionBool(full_config.use_relative_e_distances)); + config.set_key_value("toolchange_count", new ConfigOptionInt((int) gcodegen.m_toolchange_count)); + config.set_key_value("fan_speed", new ConfigOptionInt((int) 0)); + config.set_key_value("old_retract_length", new ConfigOptionFloat(old_retract_length)); + config.set_key_value("new_retract_length", new ConfigOptionFloat(new_retract_length)); + config.set_key_value("old_retract_length_toolchange", new ConfigOptionFloat(old_retract_length_toolchange)); + config.set_key_value("new_retract_length_toolchange", new ConfigOptionFloat(new_retract_length_toolchange)); + config.set_key_value("old_filament_temp", new ConfigOptionInt(old_filament_temp)); + config.set_key_value("new_filament_temp", new ConfigOptionInt(new_filament_temp)); + config.set_key_value("x_after_toolchange", new ConfigOptionFloat(start_pos(0))); + config.set_key_value("y_after_toolchange", new ConfigOptionFloat(start_pos(1))); + config.set_key_value("z_after_toolchange", new ConfigOptionFloat(nozzle_pos(2))); + config.set_key_value("first_flush_volume", new ConfigOptionFloat(purge_length / 2.f)); + config.set_key_value("second_flush_volume", new ConfigOptionFloat(purge_length / 2.f)); + config.set_key_value("old_filament_e_feedrate", new ConfigOptionInt(old_filament_e_feedrate)); + config.set_key_value("new_filament_e_feedrate", new ConfigOptionInt(new_filament_e_feedrate)); + config.set_key_value("travel_point_1_x", new ConfigOptionFloat(float(travel_point_1.x()))); + config.set_key_value("travel_point_1_y", new ConfigOptionFloat(float(travel_point_1.y()))); + config.set_key_value("travel_point_2_x", new ConfigOptionFloat(float(travel_point_2.x()))); + config.set_key_value("travel_point_2_y", new ConfigOptionFloat(float(travel_point_2.y()))); + config.set_key_value("travel_point_3_x", new ConfigOptionFloat(float(travel_point_3.x()))); + config.set_key_value("travel_point_3_y", new ConfigOptionFloat(float(travel_point_3.y()))); + + int flush_count = std::min(g_max_flush_count, (int) std::round(purge_volume / g_purge_volume_one_time)); + float flush_unit = purge_length / flush_count; + int flush_idx = 0; + for (; flush_idx < flush_count; flush_idx++) { + char key_value[64] = {0}; + snprintf(key_value, sizeof(key_value), "flush_length_%d", flush_idx + 1); + config.set_key_value(key_value, new ConfigOptionFloat(flush_unit)); + } + + for (; flush_idx < g_max_flush_count; flush_idx++) { + char key_value[64] = {0}; + snprintf(key_value, sizeof(key_value), "flush_length_%d", flush_idx + 1); + config.set_key_value(key_value, new ConfigOptionFloat(0.f)); + } + + std::string tcr_gcode, + tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config); + unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode); + gcode += tcr_gcode; + check_add_eol(toolchange_gcode_str); + + // SoftFever: set new PA for new filament + if (gcodegen.config().enable_pressure_advance.get_at(new_extruder_id)) { + gcode += gcodegen.writer().set_pressure_advance(gcodegen.config().pressure_advance.get_at(new_extruder_id)); + } + + // A phony move to the end position at the wipe tower. + gcodegen.writer().travel_to_xy(end_pos.cast()); + gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos)); + if (!is_approx(z, current_z)) { + gcode += gcodegen.writer().retract(); + gcode += gcodegen.writer().travel_to_z(current_z, "Travel back up to the topmost object layer."); + gcode += gcodegen.writer().unretract(); + } + + else { + // Prepare a future wipe. + gcodegen.m_wipe.reset_path(); + for (const Vec2f &wipe_pt : tcr.wipe_path) gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, transform_wt_pt(wipe_pt))); } @@ -703,49 +903,77 @@ static std::vector get_path_of_change_filament(const Print& print) return gcode_out; } - - std::string WipeTowerIntegration::prime(GCode& gcodegen) + std::string WipeTowerIntegration::prime(GCode &gcodegen) { std::string gcode; -#if 0 - for (const WipeTower::ToolChangeResult& tcr : m_priming) { - if (! tcr.extrusions.empty()) - gcode += append_tcr(gcodegen, tcr, tcr.new_tool); + if (!gcodegen.is_BBL_Printer()) { + for (const WipeTower::ToolChangeResult &tcr : m_priming) { + if (!tcr.extrusions.empty()) + gcode += append_tcr(gcodegen, tcr, tcr.new_tool); + } } -#endif return gcode; } - std::string WipeTowerIntegration::tool_change(GCode& gcodegen, int extruder_id, bool finish_layer) + std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, bool finish_layer) { std::string gcode; assert(m_layer_idx >= 0); - if (m_layer_idx >= (int) m_tool_changes.size()) return gcode; + if (m_layer_idx >= (int) m_tool_changes.size()) + return gcode; + if (gcodegen.config().purge_in_prime_tower) { + if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) { + if (m_layer_idx < (int) m_tool_changes.size()) { + if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size())) + throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer."); - // Calculate where the wipe tower layer will be printed. -1 means that print z will not change, - // resulting in a wipe tower with sparse layers. - double wipe_tower_z = -1; - bool ignore_sparse = false; - if (gcodegen.config().wipe_tower_no_sparse_layers.value) { - wipe_tower_z = m_last_wipe_tower_print_z; - ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool); - if (m_tool_change_idx == 0 && !ignore_sparse) - wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height; - } + // Calculate where the wipe tower layer will be printed. -1 means that print z will not change, + // resulting in a wipe tower with sparse layers. + double wipe_tower_z = -1; + bool ignore_sparse = false; + if (gcodegen.config().wipe_tower_no_sparse_layers.value) { + wipe_tower_z = m_last_wipe_tower_print_z; + ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && + m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool && + m_layer_idx != 0); + if (m_tool_change_idx == 0 && !ignore_sparse) + wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height; + } - if (m_enable_timelapse_print && m_is_first_print) { - gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][0], m_tool_changes[m_layer_idx][0].new_tool, wipe_tower_z); - m_tool_change_idx++; - m_is_first_print = false; - } + if (!ignore_sparse) { + gcode += append_tcr2(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z); + m_last_wipe_tower_print_z = wipe_tower_z; + } + } + } + } else { + // Calculate where the wipe tower layer will be printed. -1 means that print z will not change, + // resulting in a wipe tower with sparse layers. + double wipe_tower_z = -1; + bool ignore_sparse = false; + if (gcodegen.config().wipe_tower_no_sparse_layers.value) { + wipe_tower_z = m_last_wipe_tower_print_z; + ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && + m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool); + if (m_tool_change_idx == 0 && !ignore_sparse) + wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height; + } - if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) { - if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size())) throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer."); + if (m_enable_timelapse_print && m_is_first_print) { + gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][0], m_tool_changes[m_layer_idx][0].new_tool, wipe_tower_z); + m_tool_change_idx++; + m_is_first_print = false; + } - if (!ignore_sparse) { - gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z); - m_last_wipe_tower_print_z = wipe_tower_z; + if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) { + if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size())) + throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer."); + + if (!ignore_sparse) { + gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id, wipe_tower_z); + m_last_wipe_tower_print_z = wipe_tower_z; + } } } @@ -753,15 +981,15 @@ static std::vector get_path_of_change_filament(const Print& print) } // Print is finished. Now it remains to unload the filament safely with ramming over the wipe tower. - std::string WipeTowerIntegration::finalize(GCode& gcodegen) + std::string WipeTowerIntegration::finalize(GCode &gcodegen) { std::string gcode; - // BBS -#if 0 - if (std::abs(gcodegen.writer().get_position()(2) - m_final_purge.print_z) > EPSILON) - gcode += gcodegen.change_layer(m_final_purge.print_z); - gcode += append_tcr(gcodegen, m_final_purge, -1); -#endif + if (!gcodegen.is_BBL_Printer()) { + if (std::abs(gcodegen.writer().get_position().z() - m_final_purge.print_z) > EPSILON) + gcode += gcodegen.change_layer(m_final_purge.print_z); + gcode += append_tcr(gcodegen, m_final_purge, -1); + } + return gcode; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 5a6c6c4a8d..c604d200ef 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -104,10 +104,10 @@ public: private: WipeTowerIntegration& operator=(const WipeTowerIntegration&); std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const; + std::string append_tcr2(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const; // Postprocesses gcode: rotates and moves G1 extrusions and returns result std::string post_process_wipe_tower_moves(const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const; - // Left / right edges of the wipe tower, for the planning of wipe moves. const float m_left; const float m_right; diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 2d6d6d765f..f88e0d56a1 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -128,9 +128,9 @@ public: } WipeTowerWriter& disable_linear_advance() { - if(m_gcode_flavor == gcfKlipper) + if (m_gcode_flavor == gcfKlipper) m_gcode += "SET_PRESSURE_ADVANCE ADVANCE=0\n"; - else if(m_gcode_flavor == gcfRepRapFirmware) + else if (m_gcode_flavor == gcfRepRapFirmware) m_gcode += std::string("M572 D") + std::to_string(m_current_tool) + " S0\n"; else m_gcode += "M900 K0\n"; @@ -418,30 +418,36 @@ public: // Let the firmware back up the active speed override value. WipeTowerWriter& speed_override_backup() { - // This is only supported by Prusa at this point (https://github.com/prusa3d/PrusaSlicer/issues/3114) + // BBS: BBL machine don't support speed backup +#if 0 if (m_gcode_flavor == gcfMarlinLegacy || m_gcode_flavor == gcfMarlinFirmware) m_gcode += "M220 B\n"; +#endif return *this; } // Let the firmware restore the active speed override value. WipeTowerWriter& speed_override_restore() { + // BBS: BBL machine don't support speed restore +#if 0 if (m_gcode_flavor == gcfMarlinLegacy || m_gcode_flavor == gcfMarlinFirmware) m_gcode += "M220 R\n"; +#endif return *this; } // Set digital trimpot motor WipeTowerWriter& set_extruder_trimpot(int current) { - if (m_gcode_flavor == gcfKlipper) - return *this; + // BBS: don't control trimpot +#if 0 if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware) m_gcode += "M906 E"; else m_gcode += "M907 E"; m_gcode += std::to_string(current) + "\n"; +#endif return *this; } diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index dec8887019..e4dfcb67eb 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -93,6 +93,7 @@ public: } return e_length; } + bool force_travel = false; }; struct box_coordinates @@ -165,6 +166,9 @@ public: } } + void set_wipe_volume(std::vector>& wiping_matrix) { + wipe_volumes = wiping_matrix; + } // Switch to a next layer. void set_layer( @@ -251,15 +255,14 @@ public: bool is_support = false; int nozzle_temperature = 0; int nozzle_temperature_initial_layer = 0; - // BBS: remove useless config - //float loading_speed = 0.f; - //float loading_speed_start = 0.f; - //float unloading_speed = 0.f; - //float unloading_speed_start = 0.f; - //float delay = 0.f ; - //int cooling_moves = 0; - //float cooling_initial_speed = 0.f; - //float cooling_final_speed = 0.f; + float loading_speed = 0.f; + float loading_speed_start = 0.f; + float unloading_speed = 0.f; + float unloading_speed_start = 0.f; + float delay = 0.f ; + int cooling_moves = 0; + float cooling_initial_speed = 0.f; + float cooling_final_speed = 0.f; float ramming_line_width_multiplicator = 1.f; float ramming_step_multiplicator = 1.f; float max_e_speed = std::numeric_limits::max(); @@ -283,6 +286,7 @@ private: bool m_enable_timelapse_print = false; bool m_semm = true; // Are we using a single extruder multimaterial printer? + bool m_purge_in_prime_tower = false; // Do we purge in the prime tower? 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_depth = 0.f; // Depth of the wipe tower @@ -302,15 +306,13 @@ private: size_t m_first_layer_idx = size_t(-1); // G-code generator parameters. - // BBS: remove useless config - //float m_cooling_tube_retraction = 0.f; - //float m_cooling_tube_length = 0.f; - //float m_parking_pos_retraction = 0.f; - //float m_extra_loading_move = 0.f; + float m_cooling_tube_retraction = 0.f; + float m_cooling_tube_length = 0.f; + float m_parking_pos_retraction = 0.f; + float m_extra_loading_move = 0.f; float m_bridging = 0.f; bool m_no_sparse_layers = false; - // BBS: remove useless config - //bool m_set_extruder_trimpot = false; + bool m_set_extruder_trimpot = false; bool m_adhesion = true; GCodeFlavor m_gcode_flavor; @@ -338,8 +340,8 @@ private: // A fill-in direction (positive Y, negative Y) alternates with each layer. wipe_shape m_current_shape = SHAPE_NORMAL; size_t m_current_tool = 0; - // BBS - //const std::vector> wipe_volumes; + // Orca: support mmu wipe tower + std::vector> wipe_volumes; const float m_wipe_volume; float m_depth_traversed = 0.f; // Current y position at the wipe tower. diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp new file mode 100644 index 0000000000..d27a4052f9 --- /dev/null +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -0,0 +1,1642 @@ +// Orca: This file is ported from latest PrusaSlicer + +// Original PrusaSlicer Copyright: +///|/ Copyright (c) Prusa Research 2017 - 2023 Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966 +///|/ Copyright (c) SuperSlicer 2023 Remi Durand @supermerill +///|/ Copyright (c) 2020 Paul Arden @ardenpm +///|/ Copyright (c) 2019 Thomas Moore +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#include "WipeTower2.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "ClipperUtils.hpp" +#include "GCodeProcessor.hpp" +#include "BoundingBox.hpp" +#include "LocalesUtils.hpp" +#include "Geometry.hpp" +#include "PrintConfig.hpp" +#include "Surface.hpp" +#include "Fill/FillRectilinear.hpp" + +#include + + +namespace Slic3r +{ + +class WipeTowerWriter2 +{ +public: + WipeTowerWriter2(float layer_height, float line_width, GCodeFlavor flavor, const std::vector& filament_parameters) : + m_current_pos(std::numeric_limits::max(), std::numeric_limits::max()), + m_current_z(0.f), + m_current_feedrate(0.f), + m_layer_height(layer_height), + m_extrusion_flow(0.f), + m_preview_suppressed(false), + m_elapsed_time(0.f), +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + m_default_analyzer_line_width(line_width), +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + m_gcode_flavor(flavor), + m_filpar(filament_parameters) + { + // adds tag for analyzer: + std::ostringstream str; + str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) << m_layer_height << "\n"; // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming + str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role) << ExtrusionEntity::role_to_string(erWipeTower) << "\n"; + m_gcode += str.str(); + change_analyzer_line_width(line_width); + } + + WipeTowerWriter2& change_analyzer_line_width(float line_width) { + // adds tag for analyzer: + std::stringstream str; + str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width) << line_width << "\n"; + m_gcode += str.str(); + return *this; + } + +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + WipeTowerWriter2& change_analyzer_mm3_per_mm(float len, float e) { + static const float area = float(M_PI) * 1.75f * 1.75f / 4.f; + float mm3_per_mm = (len == 0.f ? 0.f : area * e / len); + // adds tag for processor: + std::stringstream str; + str << ";" << GCodeProcessor::Mm3_Per_Mm_Tag << mm3_per_mm << "\n"; + m_gcode += str.str(); + return *this; + } +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + + WipeTowerWriter2& set_initial_position(const Vec2f &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) { + m_wipe_tower_width = width; + m_wipe_tower_depth = depth; + m_internal_angle = internal_angle; + m_start_pos = this->rotate(pos); + m_current_pos = pos; + return *this; + } + + WipeTowerWriter2& set_position(const Vec2f &pos) { m_current_pos = pos; return *this; } + + WipeTowerWriter2& set_initial_tool(size_t tool) { m_current_tool = tool; return *this; } + + WipeTowerWriter2& set_z(float z) + { m_current_z = z; return *this; } + + WipeTowerWriter2& set_extrusion_flow(float flow) + { m_extrusion_flow = flow; return *this; } + + WipeTowerWriter2& set_y_shift(float shift) { + m_current_pos.y() -= shift-m_y_shift; + m_y_shift = shift; + return (*this); + } + + WipeTowerWriter2& disable_linear_advance() { + if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware) + m_gcode += (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n"); + else if (m_gcode_flavor == gcfKlipper) + m_gcode += "SET_PRESSURE_ADVANCE ADVANCE=0\n"; + else + m_gcode += "M900 K0\n"; + return *this; + } + + // Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various + // filament loading and cooling moves from normal extrusion moves. Therefore the writer + // is asked to suppres output of some lines, which look like extrusions. +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + WipeTowerWriter2& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; } + WipeTowerWriter2& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; } +#else + WipeTowerWriter2& suppress_preview() { m_preview_suppressed = true; return *this; } + WipeTowerWriter2& resume_preview() { m_preview_suppressed = false; return *this; } +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + + WipeTowerWriter2& feedrate(float f) + { + if (f != m_current_feedrate) { + m_gcode += "G1" + set_format_F(f) + "\n"; + m_current_feedrate = f; + } + return *this; + } + + const std::string& gcode() const { return m_gcode; } + const std::vector& extrusions() const { return m_extrusions; } + float x() const { return m_current_pos.x(); } + float y() const { return m_current_pos.y(); } + const Vec2f& pos() const { return m_current_pos; } + const Vec2f start_pos_rotated() const { return m_start_pos; } + const Vec2f pos_rotated() const { return this->rotate(m_current_pos); } + float elapsed_time() const { return m_elapsed_time; } + float get_and_reset_used_filament_length() { float temp = m_used_filament_length; m_used_filament_length = 0.f; return temp; } + + // Extrude with an explicitely provided amount of extrusion. + WipeTowerWriter2& extrude_explicit(float x, float y, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) + { + if (x == m_current_pos.x() && y == m_current_pos.y() && e == 0.f && (f == 0.f || f == m_current_feedrate)) + // Neither extrusion nor a travel move. + return *this; + + float dx = x - m_current_pos.x(); + float dy = y - m_current_pos.y(); + float len = std::sqrt(dx*dx+dy*dy); + if (record_length) + m_used_filament_length += e; + + // Now do the "internal rotation" with respect to the wipe tower center + Vec2f rotated_current_pos(this->pos_rotated()); + Vec2f rot(this->rotate(Vec2f(x,y))); // this is where we want to go + + if (! m_preview_suppressed && e > 0.f && len > 0.f) { +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + change_analyzer_mm3_per_mm(len, e); +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + // Width of a squished extrusion, corrected for the roundings of the squished extrusions. + // This is left zero if it is a travel move. + float width = e * m_filpar[0].filament_area / (len * m_layer_height); + // Correct for the roundings of a squished extrusion. + width += m_layer_height * float(1. - M_PI / 4.); + if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) + m_extrusions.emplace_back(WipeTower::Extrusion(rotated_current_pos, 0, m_current_tool)); + m_extrusions.emplace_back(WipeTower::Extrusion(rot, width, m_current_tool)); + } + + m_gcode += "G1"; + if (std::abs(rot.x() - rotated_current_pos.x()) > (float)EPSILON) + m_gcode += set_format_X(rot.x()); + + if (std::abs(rot.y() - rotated_current_pos.y()) > (float)EPSILON) + m_gcode += set_format_Y(rot.y()); + + + if (e != 0.f) + m_gcode += set_format_E(e); + + if (f != 0.f && f != m_current_feedrate) { + if (limit_volumetric_flow) { + float e_speed = e / (((len == 0.f) ? std::abs(e) : len) / f * 60.f); + f /= std::max(1.f, e_speed / m_filpar[m_current_tool].max_e_speed); + } + m_gcode += set_format_F(f); + } + + // Append newline if at least one of X,Y,E,F was changed. + // Otherwise, remove the "G1". + if (! boost::ends_with(m_gcode, "G1")) + m_gcode += "\n"; + else + m_gcode.erase(m_gcode.end()-2, m_gcode.end()); + + m_current_pos.x() = x; + m_current_pos.y() = y; + + // Update the elapsed time with a rough estimate. + m_elapsed_time += ((len == 0.f) ? std::abs(e) : len) / m_current_feedrate * 60.f; + return *this; + } + + WipeTowerWriter2& extrude_explicit(const Vec2f &dest, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) + { return extrude_explicit(dest.x(), dest.y(), e, f, record_length); } + + // Travel to a new XY position. f=0 means use the current value. + WipeTowerWriter2& travel(float x, float y, float f = 0.f) + { return extrude_explicit(x, y, 0.f, f); } + + WipeTowerWriter2& travel(const Vec2f &dest, float f = 0.f) + { return extrude_explicit(dest.x(), dest.y(), 0.f, f); } + + // Extrude a line from current position to x, y with the extrusion amount given by m_extrusion_flow. + WipeTowerWriter2& extrude(float x, float y, float f = 0.f) + { + float dx = x - m_current_pos.x(); + float dy = y - m_current_pos.y(); + return extrude_explicit(x, y, std::sqrt(dx*dx+dy*dy) * m_extrusion_flow, f, true); + } + + WipeTowerWriter2& extrude(const Vec2f &dest, const float f = 0.f) + { return extrude(dest.x(), dest.y(), f); } + + WipeTowerWriter2& rectangle(const Vec2f& ld,float width,float height,const float f = 0.f) + { + Vec2f corners[4]; + corners[0] = ld; + corners[1] = ld + Vec2f(width,0.f); + corners[2] = ld + Vec2f(width,height); + corners[3] = ld + Vec2f(0.f,height); + int index_of_closest = 0; + if (x()-ld.x() > ld.x()+width-x()) // closer to the right + index_of_closest = 1; + if (y()-ld.y() > ld.y()+height-y()) // closer to the top + index_of_closest = (index_of_closest==0 ? 3 : 2); + + travel(corners[index_of_closest].x(), y()); // travel to the closest corner + travel(x(),corners[index_of_closest].y()); + + int i = index_of_closest; + do { + ++i; + if (i==4) i=0; + extrude(corners[i], f); + } while (i != index_of_closest); + return (*this); + } + + WipeTowerWriter2& rectangle(const WipeTower::box_coordinates& box, const float f = 0.f) + { + rectangle(Vec2f(box.ld.x(), box.ld.y()), + box.ru.x() - box.lu.x(), + box.ru.y() - box.rd.y(), f); + return (*this); + } + + WipeTowerWriter2& load(float e, float f = 0.f) + { + if (e == 0.f && (f == 0.f || f == m_current_feedrate)) + return *this; + m_gcode += "G1"; + if (e != 0.f) + m_gcode += set_format_E(e); + if (f != 0.f && f != m_current_feedrate) + m_gcode += set_format_F(f); + m_gcode += "\n"; + return *this; + } + + WipeTowerWriter2& retract(float e, float f = 0.f) + { return load(-e, f); } + +// Loads filament while also moving towards given points in x-axis (x feedrate is limited by cutting the distance short if necessary) + WipeTowerWriter2& load_move_x_advanced(float farthest_x, float loading_dist, float loading_speed, float max_x_speed = 50.f) + { + float time = std::abs(loading_dist / loading_speed); // time that the move must take + float x_distance = std::abs(farthest_x - x()); // max x-distance that we can travel + float x_speed = x_distance / time; // x-speed to do it in that time + + if (x_speed > max_x_speed) { + // Necessary x_speed is too high - we must shorten the distance to achieve max_x_speed and still respect the time. + x_distance = max_x_speed * time; + x_speed = max_x_speed; + } + + float end_point = x() + (farthest_x > x() ? 1.f : -1.f) * x_distance; + return extrude_explicit(end_point, y(), loading_dist, x_speed * 60.f, false, false); + } + + // Elevate the extruder head above the current print_z position. + WipeTowerWriter2& z_hop(float hop, float f = 0.f) + { + m_gcode += std::string("G1") + set_format_Z(m_current_z + hop); + if (f != 0 && f != m_current_feedrate) + m_gcode += set_format_F(f); + m_gcode += "\n"; + return *this; + } + + // Lower the extruder head back to the current print_z position. + WipeTowerWriter2& z_hop_reset(float f = 0.f) + { return z_hop(0, f); } + + // Move to x1, +y_increment, + // extrude quickly amount e to x2 with feed f. + WipeTowerWriter2& ram(float x1, float x2, float dy, float e0, float e, float f) + { + extrude_explicit(x1, m_current_pos.y() + dy, e0, f, true, false); + extrude_explicit(x2, m_current_pos.y(), e, 0.f, true, false); + return *this; + } + + // Let the end of the pulled out filament cool down in the cooling tube + // by moving up and down and moving the print head left / right + // at the current Y position to spread the leaking material. + WipeTowerWriter2& cool(float x1, float x2, float e1, float e2, float f) + { + extrude_explicit(x1, m_current_pos.y(), e1, f, false, false); + extrude_explicit(x2, m_current_pos.y(), e2, false, false); + return *this; + } + + WipeTowerWriter2& set_tool(size_t tool) + { + m_current_tool = tool; + return *this; + } + + // Set extruder temperature, don't wait by default. + WipeTowerWriter2& set_extruder_temp(int temperature, bool wait = false) + { + m_gcode += "M" + std::to_string(wait ? 109 : 104) + " S" + std::to_string(temperature) + "\n"; + return *this; + } + + // Wait for a period of time (seconds). + WipeTowerWriter2& wait(float time) + { + if (time==0.f) + return *this; + m_gcode += "G4 S" + Slic3r::float_to_string_decimal_point(time, 3) + "\n"; + return *this; + } + + // Set speed factor override percentage. + WipeTowerWriter2& speed_override(int speed) + { + m_gcode += "M220 S" + std::to_string(speed) + "\n"; + return *this; + } + + // Let the firmware back up the active speed override value. + WipeTowerWriter2& speed_override_backup() + { + // This is only supported by Prusa at this point (https://github.com/prusa3d/PrusaSlicer/issues/3114) + if (m_gcode_flavor == gcfMarlinLegacy || m_gcode_flavor == gcfMarlinFirmware) + m_gcode += "M220 B\n"; + return *this; + } + + // Let the firmware restore the active speed override value. + WipeTowerWriter2& speed_override_restore() + { + if (m_gcode_flavor == gcfMarlinLegacy || m_gcode_flavor == gcfMarlinFirmware) + m_gcode += "M220 R\n"; + return *this; + } + + // Set digital trimpot motor + WipeTowerWriter2& set_extruder_trimpot(int current) + { + if (m_gcode_flavor == gcfKlipper) + return *this; + if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware) + m_gcode += "M906 E"; + else + m_gcode += "M907 E"; + m_gcode += std::to_string(current) + "\n"; + return *this; + } + + WipeTowerWriter2& flush_planner_queue() + { + m_gcode += "G4 S0\n"; + return *this; + } + + // Reset internal extruder counter. + WipeTowerWriter2& reset_extruder() + { + m_gcode += "G92 E0\n"; + return *this; + } + + WipeTowerWriter2& comment_with_value(const char *comment, int value) + { + m_gcode += std::string(";") + comment + std::to_string(value) + "\n"; + return *this; + } + + + WipeTowerWriter2& set_fan(unsigned speed) + { + if (speed == m_last_fan_speed) + return *this; + if (speed == 0) + m_gcode += "M107\n"; + else + m_gcode += "M106 S" + std::to_string(unsigned(255.0 * speed / 100.0)) + "\n"; + m_last_fan_speed = speed; + return *this; + } + + WipeTowerWriter2& append(const std::string& text) { m_gcode += text; return *this; } + + const std::vector& wipe_path() const + { + return m_wipe_path; + } + + WipeTowerWriter2& add_wipe_point(const Vec2f& pt) + { + m_wipe_path.push_back(rotate(pt)); + return *this; + } + + WipeTowerWriter2& add_wipe_point(float x, float y) + { + return add_wipe_point(Vec2f(x, y)); + } + +private: + Vec2f m_start_pos; + Vec2f m_current_pos; + std::vector m_wipe_path; + float m_current_z; + float m_current_feedrate; + size_t m_current_tool; + float m_layer_height; + float m_extrusion_flow; + bool m_preview_suppressed; + std::string m_gcode; + std::vector m_extrusions; + float m_elapsed_time; + float m_internal_angle = 0.f; + float m_y_shift = 0.f; + float m_wipe_tower_width = 0.f; + float m_wipe_tower_depth = 0.f; + unsigned m_last_fan_speed = 0; + int current_temp = -1; +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + const float m_default_analyzer_line_width; +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + float m_used_filament_length = 0.f; + GCodeFlavor m_gcode_flavor; + const std::vector& m_filpar; + + std::string set_format_X(float x) + { + m_current_pos.x() = x; + return " X" + Slic3r::float_to_string_decimal_point(x, 3); + } + + std::string set_format_Y(float y) { + m_current_pos.y() = y; + return " Y" + Slic3r::float_to_string_decimal_point(y, 3); + } + + std::string set_format_Z(float z) { + return " Z" + Slic3r::float_to_string_decimal_point(z, 3); + } + + std::string set_format_E(float e) { + return " E" + Slic3r::float_to_string_decimal_point(e, 4); + } + + std::string set_format_F(float f) { + char buf[64]; + sprintf(buf, " F%d", int(floor(f + 0.5f))); + m_current_feedrate = f; + return buf; + } + + WipeTowerWriter2& operator=(const WipeTowerWriter2 &rhs); + + // Rotate the point around center of the wipe tower about given angle (in degrees) + Vec2f rotate(Vec2f pt) const + { + pt.x() -= m_wipe_tower_width / 2.f; + pt.y() += m_y_shift - m_wipe_tower_depth / 2.f; + double angle = m_internal_angle * float(M_PI/180.); + double c = cos(angle); + double s = sin(angle); + return Vec2f(float(pt.x() * c - pt.y() * s) + m_wipe_tower_width / 2.f, float(pt.x() * s + pt.y() * c) + m_wipe_tower_depth / 2.f); + } + +}; // class WipeTowerWriter2 + + + +WipeTower::ToolChangeResult WipeTower2::construct_tcr(WipeTowerWriter2& writer, + bool priming, + size_t old_tool, + bool is_finish) const +{ + WipeTower::ToolChangeResult result; + result.priming = priming; + result.initial_tool = int(old_tool); + result.new_tool = int(m_current_tool); + result.print_z = m_z_pos; + result.layer_height = m_layer_height; + result.elapsed_time = writer.elapsed_time(); + result.start_pos = writer.start_pos_rotated(); + result.end_pos = priming ? writer.pos() : writer.pos_rotated(); + result.gcode = std::move(writer.gcode()); + result.extrusions = std::move(writer.extrusions()); + result.wipe_path = std::move(writer.wipe_path()); + result.is_finish_first = is_finish; + return result; +} + + + +WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& default_region_config,int plate_idx, Vec3d plate_origin, const std::vector>& wiping_matrix, size_t initial_tool) : + m_semm(config.single_extruder_multi_material.value), + m_enable_filament_ramming(config.enable_filament_ramming.value), + m_wipe_tower_pos(config.wipe_tower_x.get_at(plate_idx), config.wipe_tower_y.get_at(plate_idx)), + m_wipe_tower_width(float(config.prime_tower_width)), + m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)), + m_wipe_tower_brim_width(float(config.prime_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_z_pos(0.f), + m_bridging(float(config.wipe_tower_bridging)), + m_no_sparse_layers(config.wipe_tower_no_sparse_layers), + m_gcode_flavor(config.gcode_flavor), + m_travel_speed(config.travel_speed), + m_infill_speed(default_region_config.sparse_infill_speed), + m_perimeter_speed(default_region_config.inner_wall_speed), + m_current_tool(initial_tool), + wipe_volumes(wiping_matrix) +{ + // Read absolute value of first layer speed, if given as percentage, + // it is taken over following default. Speeds from config are not + // easily accessible here. + const float default_speed = 60.f; + m_first_layer_speed = config.initial_layer_speed; + if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it. + m_first_layer_speed = default_speed / 2.f; + + // Autospeed may be used... + if (m_infill_speed == 0.f) + m_infill_speed = 80.f; + if (m_perimeter_speed == 0.f) + m_perimeter_speed = 80.f; + + + // If this is a single extruder MM printer, we will use all the SE-specific config values. + // Otherwise, the defaults will be used to turn off the SE stuff. + if (m_semm) { + m_cooling_tube_retraction = float(config.cooling_tube_retraction); + m_cooling_tube_length = float(config.cooling_tube_length); + m_parking_pos_retraction = float(config.parking_pos_retraction); + m_extra_loading_move = float(config.extra_loading_move); + m_set_extruder_trimpot = config.high_current_on_filament_swap; + } + + // Calculate where the priming lines should be - very naive test not detecting parallelograms etc. + const std::vector& bed_points = config.printable_area.values; + BoundingBoxf bb(bed_points); + m_bed_width = float(bb.size().x()); + m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed); + + if (m_bed_shape == CircularBed) { + // this may still be a custom bed, check that the points are roughly on a circle + double r2 = std::pow(m_bed_width/2., 2.); + double lim2 = std::pow(m_bed_width/10., 2.); + Vec2d center = bb.center(); + for (const Vec2d& pt : bed_points) + if (std::abs(std::pow(pt.x()-center.x(), 2.) + std::pow(pt.y()-center.y(), 2.) - r2) > lim2) { + m_bed_shape = CustomBed; + break; + } + } + + m_bed_bottom_left = m_bed_shape == RectangularBed + ? Vec2f(bed_points.front().x(), bed_points.front().y()) + : Vec2f::Zero(); +} + + + +void WipeTower2::set_extruder(size_t idx, const PrintConfig& config) +{ + //while (m_filpar.size() < idx+1) // makes sure the required element is in the vector + m_filpar.push_back(FilamentParameters()); + + m_filpar[idx].material = config.filament_type.get_at(idx); + m_filpar[idx].is_soluble = config.filament_soluble.get_at(idx); + m_filpar[idx].temperature = config.nozzle_temperature.get_at(idx); + m_filpar[idx].first_layer_temperature = config.nozzle_temperature_initial_layer.get_at(idx); + + // If this is a single extruder MM printer, we will use all the SE-specific config values. + // Otherwise, the defaults will be used to turn off the SE stuff. + if (m_semm) { + m_filpar[idx].loading_speed = float(config.filament_loading_speed.get_at(idx)); + m_filpar[idx].loading_speed_start = float(config.filament_loading_speed_start.get_at(idx)); + m_filpar[idx].unloading_speed = float(config.filament_unloading_speed.get_at(idx)); + m_filpar[idx].unloading_speed_start = float(config.filament_unloading_speed_start.get_at(idx)); + m_filpar[idx].delay = float(config.filament_toolchange_delay.get_at(idx)); + m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx); + m_filpar[idx].cooling_initial_speed = float(config.filament_cooling_initial_speed.get_at(idx)); + m_filpar[idx].cooling_final_speed = float(config.filament_cooling_final_speed.get_at(idx)); + } + + m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point + float nozzle_diameter = float(config.nozzle_diameter.get_at(idx)); + m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM + + float max_vol_speed = float(config.filament_max_volumetric_speed.get_at(idx)); + if (max_vol_speed!= 0.f) + m_filpar[idx].max_e_speed = (max_vol_speed / filament_area()); + + m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter + + if (m_semm) { + std::istringstream stream{config.filament_ramming_parameters.get_at(idx)}; + float speed = 0.f; + stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator; + m_filpar[idx].ramming_line_width_multiplicator /= 100; + m_filpar[idx].ramming_step_multiplicator /= 100; + while (stream >> speed) + m_filpar[idx].ramming_speed.push_back(speed); + // ramming_speed now contains speeds to be used for every 0.25s piece of the ramming line. + // This allows to have the ramming flow variable. The 0.25s value is how it is saved in config + // and the same time step has to be used when the ramming is performed. + } else { + // We will use the same variables internally, but the correspondence to the configuration options will be different. + float vol = config.filament_multitool_ramming_volume.get_at(idx); + float flow = config.filament_multitool_ramming_flow.get_at(idx); + m_filpar[idx].multitool_ramming = config.filament_multitool_ramming.get_at(idx); + m_filpar[idx].ramming_line_width_multiplicator = 2.; + m_filpar[idx].ramming_step_multiplicator = 1.; + + // Now the ramming speed vector. In this case it contains just one value (flow). + // The time is calculated and saved separately. This is here so that the MM ramming + // is not limited by the 0.25s granularity - it is not possible to create a SEMM-style + // ramming_speed vector that would respect both the volume and flow (because of + // rounding issues with small volumes and high flow). + m_filpar[idx].ramming_speed.push_back(flow); + m_filpar[idx].multitool_ramming_time = vol/flow; + } + + m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later +} + + + +// Returns gcode to prime the nozzles at the front edge of the print bed. +std::vector WipeTower2::prime( + // print_z of the first layer. + float initial_layer_print_height, + // Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object. + const std::vector &tools, + // If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower. + // If false, the last priming are will be large enough to wipe the last extruder sufficiently. + bool /*last_wipe_inside_wipe_tower*/) +{ + this->set_layer(initial_layer_print_height, initial_layer_print_height, tools.size(), true, false); + m_current_tool = tools.front(); + + // The Prusa i3 MK2 has a working space of [0, -2.2] to [250, 210]. + // Due to the XYZ calibration, this working space may shrink slightly from all directions, + // therefore the homing position is shifted inside the bed by 0.2 in the firmware to [0.2, -2.0]. +// WipeTower::box_coordinates cleaning_box(xy(0.5f, - 1.5f), m_wipe_tower_width, wipe_area); + + float prime_section_width = std::min(0.9f * m_bed_width / tools.size(), 60.f); + WipeTower::box_coordinates cleaning_box(Vec2f(0.02f * m_bed_width, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f); + if (m_bed_shape == CircularBed) { + cleaning_box = WipeTower::box_coordinates(Vec2f(0.f, 0.f), prime_section_width, 100.f); + float total_width_half = tools.size() * prime_section_width / 2.f; + cleaning_box.translate(-total_width_half, -std::sqrt(std::max(0.f, std::pow(m_bed_width/2, 2.f) - std::pow(1.05f * total_width_half, 2.f)))); + } + else + cleaning_box.translate(m_bed_bottom_left); + + std::vector results; + + // Iterate over all priming toolchanges and push respective ToolChangeResults into results vector. + for (size_t idx_tool = 0; idx_tool < tools.size(); ++ idx_tool) { + size_t old_tool = m_current_tool; + + WipeTowerWriter2 writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + writer.set_extrusion_flow(m_extrusion_flow) + .set_z(m_z_pos) + .set_initial_tool(m_current_tool); + + // This is the first toolchange - initiate priming + if (idx_tool == 0) { + writer.append(";--------------------\n" + "; CP PRIMING START\n") + .append(";--------------------\n") + .speed_override_backup() + .speed_override(100) + .set_initial_position(Vec2f::Zero()) // Always move to the starting position + .travel(cleaning_box.ld, 7200); + if (m_set_extruder_trimpot) + writer.set_extruder_trimpot(750); // Increase the extruder driver current to allow fast ramming. + } + else + writer.set_initial_position(results.back().end_pos); + + + unsigned int tool = tools[idx_tool]; + m_left_to_right = true; + toolchange_Change(writer, tool, m_filpar[tool].material); // Select the tool, set a speed override for soluble and flex materials. + toolchange_Load(writer, cleaning_box); // Prime the tool. + if (idx_tool + 1 == tools.size()) { + // Last tool should not be unloaded, but it should be wiped enough to become of a pure color. + toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool]); + } else { + // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. + //writer.travel(writer.x(), writer.y() + m_perimeter_width, 7200); + toolchange_Wipe(writer, cleaning_box , 20.f); + WipeTower::box_coordinates box = cleaning_box; + box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width); + toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[tools[idx_tool + 1]].first_layer_temperature); + cleaning_box.translate(prime_section_width, 0.f); + writer.travel(cleaning_box.ld, 7200); + } + ++ m_num_tool_changes; + + + // Ask our writer about how much material was consumed: + if (m_current_tool < m_used_filament_length.size()) + m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); + + // This is the last priming toolchange - finish priming + if (idx_tool+1 == tools.size()) { + // Reset the extruder current to a normal value. + if (m_set_extruder_trimpot) + writer.set_extruder_trimpot(550); + writer.speed_override_restore() + .feedrate(m_travel_speed * 60.f) + .flush_planner_queue() + .reset_extruder() + .append("; CP PRIMING END\n" + ";------------------\n" + "\n\n"); + } + + results.emplace_back(construct_tcr(writer, true, old_tool, true)); + } + + m_old_temperature = -1; // If the priming is turned off in config, the temperature changing commands will not actually appear + // in the output gcode - we should not remember emitting them (we will output them twice in the worst case) + + return results; +} + +WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) +{ + size_t old_tool = m_current_tool; + + float wipe_area = 0.f; + float wipe_volume = 0.f; + + // Finds this toolchange info + if (tool != (unsigned int)(-1)) + { + for (const auto &b : m_layer_info->tool_changes) + if ( b.new_tool == tool ) { + wipe_volume = b.wipe_volume; + wipe_area = b.required_depth * m_layer_info->extra_spacing; + break; + } + } + else { + // Otherwise we are going to Unload only. And m_layer_info would be invalid. + } + + WipeTower::box_coordinates cleaning_box( + Vec2f(m_perimeter_width / 2.f, m_perimeter_width / 2.f), + m_wipe_tower_width - m_perimeter_width, + (tool != (unsigned int)(-1) ? wipe_area+m_depth_traversed-0.5f*m_perimeter_width + : m_wipe_tower_depth-m_perimeter_width)); + + WipeTowerWriter2 writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + writer.set_extrusion_flow(m_extrusion_flow) + .set_z(m_z_pos) + .set_initial_tool(m_current_tool) + .set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f)) + .append(";--------------------\n" + "; CP TOOLCHANGE START\n") + .comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based + + if (tool != (unsigned)(-1)) + writer.append(std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[tool].material + "\n").c_str()) + .append(";--------------------\n"); + + writer.speed_override_backup(); + writer.speed_override(100); + + Vec2f initial_position = cleaning_box.ld + Vec2f(0.f, m_depth_traversed); + writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); + + // Increase the extruder driver current to allow fast ramming. + if (m_set_extruder_trimpot) + writer.set_extruder_trimpot(750); + + // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. + if (tool != (unsigned int)-1){ // This is not the last change. + toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, + is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature); + toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials. + toolchange_Load(writer, cleaning_box); + writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road + toolchange_Wipe(writer, cleaning_box, wipe_volume); // Wipe the newly loaded filament until the end of the assigned wipe area. + ++ m_num_tool_changes; + } else + toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].temperature); + + m_depth_traversed += wipe_area; + + if (m_set_extruder_trimpot) + writer.set_extruder_trimpot(550); // Reset the extruder current to a normal value. + writer.speed_override_restore(); + writer.feedrate(m_travel_speed * 60.f) + .flush_planner_queue() + .reset_extruder() + .append("; CP TOOLCHANGE END\n" + ";------------------\n" + "\n\n"); + + // Ask our writer about how much material was consumed: + if (m_current_tool < m_used_filament_length.size()) + m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); + + return construct_tcr(writer, false, old_tool, false); +} + + +// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. +void WipeTower2::toolchange_Unload( + WipeTowerWriter2 &writer, + const WipeTower::box_coordinates &cleaning_box, + const std::string& current_material, + const int new_temperature) +{ + float xl = cleaning_box.ld.x() + 1.f * m_perimeter_width; + float xr = cleaning_box.rd.x() - 1.f * m_perimeter_width; + + const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness + const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm + + const Vec2f ramming_start_pos = Vec2f(xl, cleaning_box.ld.y() + m_depth_traversed + y_step/2.f); + + writer.append("; CP TOOLCHANGE UNLOAD\n") + .change_analyzer_line_width(line_width); + + unsigned i = 0; // iterates through ramming_speed + m_left_to_right = true; // current direction of ramming + float remaining = xr - xl ; // keeps track of distance to the next turnaround + float e_done = 0; // measures E move done from each segment + + const bool do_ramming = m_enable_filament_ramming && (m_semm || m_filpar[m_current_tool].multitool_ramming); + + if (do_ramming) { + writer.travel(ramming_start_pos); // move to starting position + writer.disable_linear_advance(); + } + else + writer.set_position(ramming_start_pos); + + // if the ending point of the ram would end up in mid air, align it with the end of the wipe tower: + if (do_ramming && (m_layer_info > m_plan.begin() && m_layer_info < m_plan.end() && (m_layer_info-1!=m_plan.begin() || !m_adhesion ))) { + + // this is y of the center of previous sparse infill border + float sparse_beginning_y = 0.f; + if (m_current_shape == SHAPE_REVERSED) + sparse_beginning_y += ((m_layer_info-1)->depth - (m_layer_info-1)->toolchanges_depth()) + - ((m_layer_info)->depth-(m_layer_info)->toolchanges_depth()) ; + else + sparse_beginning_y += (m_layer_info-1)->toolchanges_depth() + m_perimeter_width; + + float sum_of_depths = 0.f; + for (const auto& tch : m_layer_info->tool_changes) { // let's find this toolchange + if (tch.old_tool == m_current_tool) { + sum_of_depths += tch.ramming_depth; + float ramming_end_y = sum_of_depths; + ramming_end_y -= (y_step/m_extra_spacing-m_perimeter_width) / 2.f; // center of final ramming line + + if ( (m_current_shape == SHAPE_REVERSED && ramming_end_y < sparse_beginning_y - 0.5f*m_perimeter_width ) || + (m_current_shape == SHAPE_NORMAL && ramming_end_y > sparse_beginning_y + 0.5f*m_perimeter_width ) ) + { + writer.extrude(xl + tch.first_wipe_line-1.f*m_perimeter_width,writer.y()); + remaining -= tch.first_wipe_line-1.f*m_perimeter_width; + } + break; + } + sum_of_depths += tch.required_depth; + } + } + + + writer.append("; Ramming\n"); + // now the ramming itself: + while (do_ramming && i < m_filpar[m_current_tool].ramming_speed.size()) + { + // The time step is different for SEMM ramming and the MM ramming. See comments in set_extruder() for details. + const float time_step = m_semm ? 0.25f : m_filpar[m_current_tool].multitool_ramming_time; + + const float x = volume_to_length(m_filpar[m_current_tool].ramming_speed[i] * time_step, line_width, m_layer_height); + const float e = m_filpar[m_current_tool].ramming_speed[i] * time_step / filament_area(); // transform volume per sec to E move; + const float dist = std::min(x - e_done, remaining); // distance to travel for either the next time_step, or to the next turnaround + const float actual_time = dist/x * time_step; + writer.ram(writer.x(), writer.x() + (m_left_to_right ? 1.f : -1.f) * dist, 0.f, 0.f, e * (dist / x), dist / (actual_time / 60.f)); + remaining -= dist; + + if (remaining < WT_EPSILON) { // we reached a turning point + writer.travel(writer.x(), writer.y() + y_step, 7200); + m_left_to_right = !m_left_to_right; + remaining = xr - xl; + } + e_done += dist; // subtract what was actually done + if (e_done > x - WT_EPSILON) { // current segment finished + ++i; + e_done = 0; + } + } + Vec2f end_of_ramming(writer.x(),writer.y()); + writer.change_analyzer_line_width(m_perimeter_width); // so the next lines are not affected by ramming_line_width_multiplier + + writer.append("; Retract(unload)\n"); + // Retraction: + float old_x = writer.x(); + float turning_point = (!m_left_to_right ? xl : xr ); + if (m_semm && (m_cooling_tube_retraction != 0 || m_cooling_tube_length != 0)) { + float total_retraction_distance = m_cooling_tube_retraction + m_cooling_tube_length/2.f - 15.f; // the 15mm is reserved for the first part after ramming + writer.suppress_preview() + .retract(15.f, m_filpar[m_current_tool].unloading_speed_start * 60.f) // feedrate 5000mm/min = 83mm/s + .retract(0.70f * total_retraction_distance, 1.0f * m_filpar[m_current_tool].unloading_speed * 60.f) + .retract(0.20f * total_retraction_distance, 0.5f * m_filpar[m_current_tool].unloading_speed * 60.f) + .retract(0.10f * total_retraction_distance, 0.3f * m_filpar[m_current_tool].unloading_speed * 60.f) + .resume_preview(); + } + // Wipe tower should only change temperature with single extruder MM. Otherwise, all temperatures should + // be already set and there is no need to change anything. Also, the temperature could be changed + // for wrong extruder. + if (m_semm) { + if (new_temperature != 0 && (new_temperature != m_old_temperature || is_first_layer()) ) { // Set the extruder temperature, but don't wait. + // If the required temperature is the same as last time, don't emit the M104 again (if user adjusted the value, it would be reset) + // However, always change temperatures on the first layer (this is to avoid issues with priming lines turned off). + writer.set_extruder_temp(new_temperature, false); + m_old_temperature = new_temperature; + } + } + + writer.append("; Cooling\n"); + // Cooling: + const int& number_of_moves = m_filpar[m_current_tool].cooling_moves; + if (m_semm && number_of_moves > 0) { + const float& initial_speed = m_filpar[m_current_tool].cooling_initial_speed; + const float& final_speed = m_filpar[m_current_tool].cooling_final_speed; + + float speed_inc = (final_speed - initial_speed) / (2.f * number_of_moves - 1.f); + + writer.suppress_preview() + .travel(writer.x(), writer.y() + y_step); + old_x = writer.x(); + turning_point = xr-old_x > old_x-xl ? xr : xl; + for (int i=0; i cleaning_box.lu.y()-0.5f*m_perimeter_width) + break; // in case next line would not fit + + traversed_x -= writer.x(); + x_to_wipe -= std::abs(traversed_x); + if (x_to_wipe < WT_EPSILON) { + writer.travel(m_left_to_right ? xl + 1.5f*m_perimeter_width : xr - 1.5f*m_perimeter_width, writer.y(), 7200); + break; + } + // stepping to the next line: + writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5f*m_perimeter_width, writer.y() + dy); + m_left_to_right = !m_left_to_right; + } + + // We may be going back to the model - wipe the nozzle. If this is followed + // by finish_layer, this wipe path will be overwritten. + writer.add_wipe_point(writer.x(), writer.y()) + .add_wipe_point(writer.x(), writer.y() - dy) + .add_wipe_point(! m_left_to_right ? m_wipe_tower_width : 0.f, writer.y() - dy); + + if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool) + m_left_to_right = !m_left_to_right; + + writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow. +} + + + + +WipeTower::ToolChangeResult WipeTower2::finish_layer() +{ + assert(! this->layer_finished()); + m_current_layer_finished = true; + + size_t old_tool = m_current_tool; + + WipeTowerWriter2 writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + writer.set_extrusion_flow(m_extrusion_flow) + .set_z(m_z_pos) + .set_initial_tool(m_current_tool) + .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)); + + + // Slow down on the 1st layer. + bool first_layer = is_first_layer(); + float feedrate = first_layer ? m_first_layer_speed * 60.f : m_infill_speed * 60.f; + float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth(); + WipeTower::box_coordinates fill_box(Vec2f(m_perimeter_width, m_layer_info->depth-(current_depth-m_perimeter_width)), + m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width); + + + writer.set_initial_position((m_left_to_right ? fill_box.ru : fill_box.lu), // so there is never a diagonal travel + m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); + + bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON; + WipeTower::box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)), + m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); + + // inner perimeter of the sparse section, if there is space for it: + if (fill_box.ru.y() - fill_box.rd.y() > m_perimeter_width - WT_EPSILON) + writer.rectangle(fill_box.ld, fill_box.rd.x()-fill_box.ld.x(), fill_box.ru.y()-fill_box.rd.y(), feedrate); + + // we are in one of the corners, travel to ld along the perimeter: + if (writer.x() > fill_box.ld.x()+EPSILON) writer.travel(fill_box.ld.x(),writer.y()); + if (writer.y() > fill_box.ld.y()+EPSILON) writer.travel(writer.x(),fill_box.ld.y()); + + // Extrude infill to support the material to be printed above. + const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width); + float left = fill_box.lu.x() + 2*m_perimeter_width; + float right = fill_box.ru.x() - 2 * m_perimeter_width; + if (dy > m_perimeter_width) + { + writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f)) + .append(";--------------------\n" + "; CP EMPTY GRID START\n") + .comment_with_value(" layer #", m_num_layer_changes + 1); + + // Is there a soluble filament wiped/rammed at the next layer? + // If so, the infill should not be sparse. + bool solid_infill = m_layer_info+1 == m_plan.end() + ? false + : std::any_of((m_layer_info+1)->tool_changes.begin(), + (m_layer_info+1)->tool_changes.end(), + [this](const WipeTowerInfo::ToolChange& tch) { + return m_filpar[tch.new_tool].is_soluble + || m_filpar[tch.old_tool].is_soluble; + }); + solid_infill |= first_layer && m_adhesion; + + if (solid_infill) { + float sparse_factor = 1.5f; // 1=solid, 2=every other line, etc. + if (first_layer) { // the infill should touch perimeters + left -= m_perimeter_width; + right += m_perimeter_width; + sparse_factor = 1.f; + } + float y = fill_box.ld.y() + m_perimeter_width; + int n = dy / (m_perimeter_width * sparse_factor); + float spacing = (dy-m_perimeter_width)/(n-1); + int i=0; + for (i=0; i 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> 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) / 40.) + 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 filler(Fill::new_from_type(ipMonotonicLine)); + 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::max(); + for (int i=0; i() - center)); + for (size_t i=0; i() - center)); + } + writer.travel(pts[i].first); + } + } + if (++i == int(pts.size())) + i = 0; + } + writer.extrude(pts[start_i].first, feedrate); + return poly; + }; + + feedrate = first_layer ? m_first_layer_speed * 60.f : m_perimeter_speed * 60.f; + + // 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) + if (first_layer) { + size_t loops_num = (m_wipe_tower_brim_width + spacing/2.f) / spacing; + + for (size_t i = 0; i < loops_num; ++ i) { + poly = offset(poly, scale_(spacing)).front(); + int cp = poly.closest_point_index(Point::new_scale(writer.x(), writer.y())); + writer.travel(unscale(poly.points[cp]).cast()); + for (int i=cp+1; true; ++i ) { + if (i==int(poly.points.size())) + i = 0; + writer.extrude(unscale(poly.points[i]).cast()); + if (i == cp) + break; + } + } + + // 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 + m_wipe_tower_brim_width_real = loops_num * spacing; + } + + // Now prepare future wipe. + int i = poly.closest_point_index(Point::new_scale(writer.x(), writer.y())); + writer.add_wipe_point(writer.pos()); + writer.add_wipe_point(unscale(poly.points[i==0 ? int(poly.points.size())-1 : i-1]).cast()); + + // 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. + if (! m_no_sparse_layers || toolchanges_on_layer || first_layer) { + if (m_current_tool < m_used_filament_length.size()) + 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, true); +} + +// Static method to get the radius and x-scaling of the stabilizing cone base. +std::pair WipeTower2::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); +} + +// Static method to extract wipe_volumes[from][to] from the configuration. +std::vector> WipeTower2::extract_wipe_volumes(const PrintConfig& config) +{ + // Get wiping matrix to get number of extruders and convert vector to vector: + std::vector wiping_matrix(cast(config.flush_volumes_matrix.values)); + auto scale = config.flush_multiplier; + + // Orca todo: currently we only/always support SEMM. + // The values shall only be used when SEMM is enabled. The purging for other printers + // is determined by filament_minimal_purge_on_wipe_tower. + if (! config.purge_in_prime_tower.value) + std::fill(wiping_matrix.begin(), wiping_matrix.end(), 0.f); + + // Extract purging volumes for each extruder pair: + std::vector> wipe_volumes; + const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON); + for (unsigned int i = 0; i(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders)); + + // Also include filament_minimal_purge_on_wipe_tower. This is needed for the preview. + for (unsigned int i = 0; i(wipe_volumes[i][j] * scale, config.filament_minimal_purge_on_wipe_tower.get_at(j)); + + return wipe_volumes; +} + +// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box +void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, + unsigned int new_tool, float wipe_volume) +{ + assert(m_plan.empty() || m_plan.back().z <= z_par + WT_EPSILON); // refuses to add a layer below the last one + + if (m_plan.empty() || m_plan.back().z + WT_EPSILON < z_par) // if we moved to a new layer, we'll add it to m_plan first + m_plan.push_back(WipeTowerInfo(z_par, layer_height_par)); + + if (m_first_layer_idx == size_t(-1) && (! m_no_sparse_layers || old_tool != new_tool || m_plan.size() == 1)) + m_first_layer_idx = m_plan.size() - 1; + + if (old_tool == new_tool) // new layer without toolchanges - we are done + return; + + // this is an actual toolchange - let's calculate depth to reserve on the wipe tower + float depth = 0.f; + float width = m_wipe_tower_width - 3*m_perimeter_width; + float length_to_extrude = volume_to_length(0.25f * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f), + m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator, + layer_height_par); + depth = (int(length_to_extrude / width) + 1) * (m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator * m_filpar[old_tool].ramming_step_multiplicator); + float ramming_depth = depth; + length_to_extrude = width*((length_to_extrude / width)-int(length_to_extrude / width)) - width; + float first_wipe_line = -length_to_extrude; + length_to_extrude += volume_to_length(wipe_volume, m_perimeter_width, layer_height_par); + length_to_extrude = std::max(length_to_extrude,0.f); + + depth += (int(length_to_extrude / width) + 1) * m_perimeter_width; + depth *= m_extra_spacing; + + m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, depth, ramming_depth, first_wipe_line, wipe_volume)); +} + + + +void WipeTower2::plan_tower() +{ + // Calculate m_wipe_tower_depth (maximum depth for all the layers) and propagate depths downwards + m_wipe_tower_depth = 0.f; + for (auto& layer : m_plan) + 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) + { + float this_layer_depth = std::max(m_plan[layer_index].depth, m_plan[layer_index].toolchanges_depth()); + m_plan[layer_index].depth = this_layer_depth; + + if (this_layer_depth > m_wipe_tower_depth - m_perimeter_width) + m_wipe_tower_depth = this_layer_depth + m_perimeter_width; + + for (int i = layer_index - 1; i >= 0 ; i--) + { + if (m_plan[i].depth - this_layer_depth < 2*m_perimeter_width ) + m_plan[i].depth = this_layer_depth; + } + } +} + +void WipeTower2::save_on_last_wipe() +{ + for (m_layer_info=m_plan.begin();m_layer_infoz, m_layer_info->height, 0, m_layer_info->z == m_plan.front().z, m_layer_info->z == m_plan.back().z); + if (m_layer_info->tool_changes.size()==0) // we have no way to save anything on an empty layer + continue; + + // Which toolchange will finish_layer extrusions be subtracted from? + int idx = first_toolchange_to_nonsoluble(m_layer_info->tool_changes); + + for (int i=0; itool_changes.size()); ++i) { + auto& toolchange = m_layer_info->tool_changes[i]; + tool_change(toolchange.new_tool); + + if (i == idx) { + float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into + float length_to_save = finish_layer().total_extrusion_length_in_plane(); + float length_to_wipe = volume_to_length(toolchange.wipe_volume, + m_perimeter_width, m_layer_info->height) - toolchange.first_wipe_line - length_to_save; + + length_to_wipe = std::max(length_to_wipe,0.f); + float depth_to_wipe = m_perimeter_width * (std::floor(length_to_wipe/width) + ( length_to_wipe > 0.f ? 1.f : 0.f ) ) * m_extra_spacing; + + toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe; + } + } + } +} + + +// Return index of first toolchange that switches to non-soluble extruder +// ot -1 if there is no such toolchange. +int WipeTower2::first_toolchange_to_nonsoluble( + const std::vector& tool_changes) const +{ + for (size_t idx=0; idx> &result) +{ + if (m_plan.empty()) + return; + + plan_tower(); + for (int i=0;i<5;++i) { + save_on_last_wipe(); + plan_tower(); + } + + 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 + for (const auto& layer : m_plan) { + if (!layer.tool_changes.empty()) { + m_current_tool = layer.tool_changes.front().old_tool; + break; + } + } + + for (auto& used : m_used_filament_length) // reset used filament stats + used = 0.f; + + m_old_temperature = -1; // reset last temperature written in the gcode + + std::vector layer_result; + for (const WipeTower2::WipeTowerInfo& layer : m_plan) + { + 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; + + if (m_layer_info->depth < m_wipe_tower_depth - m_perimeter_width) + m_y_shift = (m_wipe_tower_depth-m_layer_info->depth-m_perimeter_width)/2.f; + + int idx = first_toolchange_to_nonsoluble(layer.tool_changes); + WipeTower::ToolChangeResult finish_layer_tcr; + + if (idx == -1) { + // if there is no toolchange switching to non-soluble, finish layer + // will be called at the very beginning. That's the last possibility + // where a nonsoluble tool can be. + finish_layer_tcr = finish_layer(); + } + + for (int i=0; i> WipeTower2::get_z_and_depth_pairs() const +{ + std::vector> out = {{0.f, m_wipe_tower_depth}}; + for (const WipeTowerInfo& wti : m_plan) { + assert(wti.depth < wti.depth + WT_EPSILON); + if (wti.depth < out.back().second - WT_EPSILON) + out.emplace_back(wti.z, wti.depth); + } + if (out.back().first < m_wipe_tower_height - WT_EPSILON) + out.emplace_back(m_wipe_tower_height, 0.f); + return out; +} + +} // namespace Slic3r diff --git a/src/libslic3r/GCode/WipeTower2.hpp b/src/libslic3r/GCode/WipeTower2.hpp new file mode 100644 index 0000000000..8fd5d5de31 --- /dev/null +++ b/src/libslic3r/GCode/WipeTower2.hpp @@ -0,0 +1,324 @@ +// Orca: This file is ported from latest PrusaSlicer + +// Original PrusaSlicer Copyright: +///|/ Copyright (c) Prusa Research 2017 - 2023 Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#ifndef WipeTower2_ +#define WipeTower2_ + +#include +#include +#include +#include +#include + +#include "libslic3r/Point.hpp" +#include "WipeTower.hpp" +namespace Slic3r +{ + +class WipeTowerWriter2; +class PrintRegionConfig; + +class WipeTower2 +{ +public: + static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; } + static std::pair get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg); + static std::vector> extract_wipe_volumes(const PrintConfig& config); + + + // Construct ToolChangeResult from current state of WipeTower2 and WipeTowerWriter2. + // WipeTowerWriter2 is moved from ! + WipeTower::ToolChangeResult construct_tcr(WipeTowerWriter2& writer, + bool priming, + size_t old_tool, + bool is_finish) const; + + // x -- x coordinates of wipe tower in mm ( left bottom corner ) + // y -- y coordinates of wipe tower in mm ( left bottom corner ) + // width -- width of wipe tower in mm ( default 60 mm - leave as it is ) + // wipe_area -- space available for one toolchange in mm + WipeTower2(const PrintConfig& config, + const PrintRegionConfig& default_region_config, + int plate_idx, Vec3d plate_origin, + const std::vector>& wiping_matrix, + size_t initial_tool); + + + // Set the extruder properties. + void set_extruder(size_t idx, const PrintConfig& config); + + // Appends into internal structure m_plan containing info about the future wipe tower + // to be used before building begins. The entries must be added ordered in z. + void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume = 0.f); + + // Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result" + void generate(std::vector> &result); + + float get_depth() const { return m_wipe_tower_depth; } + std::vector> get_z_and_depth_pairs() const; + float get_brim_width() const { return m_wipe_tower_brim_width_real; } + float get_wipe_tower_height() const { return m_wipe_tower_height; } + + + + + + // Switch to a next layer. + void set_layer( + // Print height of this layer. + float print_z, + // Layer height, used to calculate extrusion the rate. + float layer_height, + // Maximum number of tool changes on this layer or the layers below. + size_t max_tool_changes, + // Is this the first layer of the print? In that case print the brim first. (OBSOLETE) + bool /*is_first_layer*/, + // Is this the last layer of the waste tower? + bool is_last_layer) + { + m_z_pos = print_z; + m_layer_height = layer_height; + m_depth_traversed = 0.f; + m_current_layer_finished = false; + + + // Advance m_layer_info iterator, making sure we got it right + while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end()) + ++m_layer_info; + + m_current_shape = (! this->is_first_layer() && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL; + if (this->is_first_layer()) { + m_num_layer_changes = 0; + m_num_tool_changes = 0; + } else + ++ m_num_layer_changes; + + // Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height: + m_extrusion_flow = extrusion_flow(layer_height); + } + + // Return the wipe tower position. + const Vec2f& position() const { return m_wipe_tower_pos; } + // Return the wipe tower width. + float width() const { return m_wipe_tower_width; } + // The wipe tower is finished, there should be no more tool changes or wipe tower prints. + bool finished() const { return m_max_color_changes == 0; } + + // Returns gcode to prime the nozzles at the front edge of the print bed. + std::vector prime( + // print_z of the first layer. + float first_layer_height, + // Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object. + const std::vector &tools, + // If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower. + // If false, the last priming are will be large enough to wipe the last extruder sufficiently. + bool last_wipe_inside_wipe_tower); + + // Returns gcode for a toolchange and a final print head position. + // On the first layer, extrude a brim around the future wipe tower first. + WipeTower::ToolChangeResult tool_change(size_t new_tool); + + // Fill the unfilled space with a sparse infill. + // Call this method only if layer_finished() is false. + WipeTower::ToolChangeResult finish_layer(); + + // Is the current layer finished? + bool layer_finished() const { + return m_current_layer_finished; + } + + std::vector get_used_filament() const { return m_used_filament_length; } + int get_number_of_toolchanges() const { return m_num_tool_changes; } + + struct FilamentParameters { + std::string material = "PLA"; + bool is_soluble = false; + int temperature = 0; + int first_layer_temperature = 0; + float loading_speed = 0.f; + float loading_speed_start = 0.f; + float unloading_speed = 0.f; + float unloading_speed_start = 0.f; + float delay = 0.f ; + int cooling_moves = 0; + float cooling_initial_speed = 0.f; + float cooling_final_speed = 0.f; + float ramming_line_width_multiplicator = 1.f; + float ramming_step_multiplicator = 1.f; + float max_e_speed = std::numeric_limits::max(); + std::vector ramming_speed; + float nozzle_diameter; + float filament_area; + bool multitool_ramming; + float multitool_ramming_time = 0.f; + }; + +private: + enum wipe_shape // A fill-in direction + { + SHAPE_NORMAL = 1, + SHAPE_REVERSED = -1 + }; + + const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust + const float WT_EPSILON = 1e-3f; + float filament_area() const { + return m_filpar[0].filament_area; // all extruders are assumed to have the same filament diameter at this point + } + + + bool m_semm = true; // Are we using a single extruder multimaterial printer? + bool m_enable_filament_ramming = true; + 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_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_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_internal_rotation = 0.f; + float m_y_shift = 0.f; // y shift passed to writer + float m_z_pos = 0.f; // Current Z position. + float m_layer_height = 0.f; // Current layer height. + size_t m_max_color_changes = 0; // Maximum number of color changes per layer. + int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary) + float m_travel_speed = 0.f; + float m_infill_speed = 0.f; + float m_perimeter_speed = 0.f; + float m_first_layer_speed = 0.f; + size_t m_first_layer_idx = size_t(-1); + + // G-code generator parameters. + float m_cooling_tube_retraction = 0.f; + float m_cooling_tube_length = 0.f; + float m_parking_pos_retraction = 0.f; + float m_extra_loading_move = 0.f; + float m_bridging = 0.f; + bool m_no_sparse_layers = false; + bool m_set_extruder_trimpot = false; + bool m_adhesion = true; + GCodeFlavor m_gcode_flavor; + + // Bed properties + enum { + RectangularBed, + CircularBed, + CustomBed + } m_bed_shape; + float m_bed_width; // width of the bed bounding box + Vec2f m_bed_bottom_left; // bottom-left corner coordinates (for rectangular beds) + + float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill. + float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter. + + // Extruder specific parameters. + std::vector m_filpar; + + // State of the wipe tower generator. + unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics. + unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics. + ///unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes. + bool m_print_brim = true; + // A fill-in direction (positive Y, negative Y) alternates with each layer. + wipe_shape m_current_shape = SHAPE_NORMAL; + size_t m_current_tool = 0; + const std::vector> wipe_volumes; + + float m_depth_traversed = 0.f; // Current y position at the wipe tower. + bool m_current_layer_finished = false; + bool m_left_to_right = true; + float m_extra_spacing = 1.f; + + bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; } + + // Calculates extrusion flow needed to produce required line width for given layer height + float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow + { + if ( layer_height < 0 ) + return m_extrusion_flow; + return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / filament_area(); + } + + // Calculates length of extrusion line to extrude given volume + float volume_to_length(float volume, float line_width, float layer_height) const { + return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f)))); + } + + // Calculates depth for all layers and propagates them downwards + void plan_tower(); + + // Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental + void make_wipe_tower_square(); + + // Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe + void save_on_last_wipe(); + + + // to store information about tool changes for a given layer + struct WipeTowerInfo{ + struct ToolChange { + size_t old_tool; + size_t new_tool; + float required_depth; + float ramming_depth; + float first_wipe_line; + float wipe_volume; + ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f) + : old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv} {} + }; + float z; // z position of the layer + float height; // layer height + float depth; // depth of the layer based on all layers above + float extra_spacing; + float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; } + + std::vector tool_changes; + + WipeTowerInfo(float z_par, float layer_height_par) + : z{z_par}, height{layer_height_par}, depth{0}, extra_spacing{1.f} {} + }; + + std::vector m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...)) + std::vector::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: + std::vector m_used_filament_length; + + // Return index of first toolchange that switches to non-soluble extruder + // ot -1 if there is no such toolchange. + int first_toolchange_to_nonsoluble( + const std::vector& tool_changes) const; + + void toolchange_Unload( + WipeTowerWriter2 &writer, + const WipeTower::box_coordinates &cleaning_box, + const std::string& current_material, + const int new_temperature); + + void toolchange_Change( + WipeTowerWriter2 &writer, + const size_t new_tool, + const std::string& new_material); + + void toolchange_Load( + WipeTowerWriter2 &writer, + const WipeTower::box_coordinates &cleaning_box); + + void toolchange_Wipe( + WipeTowerWriter2 &writer, + const WipeTower::box_coordinates &cleaning_box, + float wipe_volume); +}; + +} // namespace Slic3r + +#endif // WipeTowerPrusaMM_hpp_ diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index f8ac1ab4cb..276eea4f2f 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -764,8 +764,10 @@ static std::vector s_Preset_print_options { "bridge_density", "precise_outer_wall", "overhang_speed_classic", "bridge_acceleration", "sparse_infill_acceleration", "internal_solid_infill_acceleration", "tree_support_adaptive_layer_height", "tree_support_auto_brim", "tree_support_brim_width", "gcode_comments", "gcode_label_objects", - "initial_layer_travel_speed", "exclude_object", "slow_down_layers", "infill_anchor", "infill_anchor_max", - "make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes" ,"initial_layer_min_bead_width" + "initial_layer_travel_speed", "exclude_object", "slow_down_layers", "infill_anchor", "infill_anchor_max","initial_layer_min_bead_width", + "make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes", + "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extruder", "wiping_volumes_extruders","wipe_tower_bridging", "single_extruder_multi_material_priming", + "wipe_tower_rotation_angle" }; @@ -790,7 +792,11 @@ static std::vector s_Preset_filament_options { "filament_wipe_distance", "additional_cooling_fan_speed", "bed_temperature_difference", "nozzle_temperature_range_low", "nozzle_temperature_range_high", //SoftFever - "enable_pressure_advance", "pressure_advance","chamber_temperature", "filament_shrink", "support_material_interface_fan_speed", "filament_notes" /*,"filament_seam_gap"*/ + "enable_pressure_advance", "pressure_advance","chamber_temperature", "filament_shrink", "support_material_interface_fan_speed", "filament_notes" /*,"filament_seam_gap"*/, + "filament_loading_speed", "filament_loading_speed_start", "filament_load_time", + "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", + "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", + "filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", }; static std::vector s_Preset_machine_limits_options { @@ -817,7 +823,9 @@ static std::vector s_Preset_printer_options { "print_host_webui", "printhost_cafile","printhost_port","printhost_authorization_type", "printhost_user", "printhost_password", "printhost_ssl_ignore_revoke", "thumbnails", - "use_firmware_retraction", "use_relative_e_distances", "printer_notes"}; + "use_firmware_retraction", "use_relative_e_distances", "printer_notes", + "cooling_tube_retraction", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "purge_in_prime_tower", "enable_filament_ramming"}; static std::vector s_Preset_sla_print_options { "layer_height", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 2691856de2..f59c9cd617 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -12,6 +12,7 @@ #include "Thread.hpp" #include "GCode.hpp" #include "GCode/WipeTower.hpp" +#include "GCode/WipeTower2.hpp" #include "Utils.hpp" #include "PrintConfig.hpp" #include "Model.hpp" @@ -172,7 +173,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "gcode_comments", "gcode_label_objects", "exclude_object", - "support_material_interface_fan_speed" + "support_material_interface_fan_speed", + "single_extruder_multi_material_priming" }; static std::unordered_set steps_ignore; @@ -216,10 +218,22 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "nozzle_temperature_initial_layer" || opt_key == "filament_minimal_purge_on_wipe_tower" || opt_key == "filament_max_volumetric_speed" + || opt_key == "filament_loading_speed" + || opt_key == "filament_loading_speed_start" + || opt_key == "filament_unloading_speed" + || opt_key == "filament_unloading_speed_start" + || opt_key == "filament_toolchange_delay" + || opt_key == "filament_cooling_moves" + || opt_key == "filament_cooling_initial_speed" + || opt_key == "filament_cooling_final_speed" + || opt_key == "filament_ramming_parameters" + || opt_key == "filament_multitool_ramming" + || opt_key == "filament_multitool_ramming_volume" + || opt_key == "filament_multitool_ramming_flow" + || opt_key == "filament_max_volumetric_speed" || opt_key == "gcode_flavor" || opt_key == "single_extruder_multi_material" || opt_key == "nozzle_temperature" - // BBS || opt_key == "cool_plate_temp" || opt_key == "eng_plate_temp" || opt_key == "hot_plate_temp" @@ -228,7 +242,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "prime_tower_width" || opt_key == "prime_tower_brim_width" || opt_key == "first_layer_print_sequence" - //|| opt_key == "wipe_tower_bridging" + || opt_key == "wipe_tower_bridging" || opt_key == "wipe_tower_no_sparse_layers" || opt_key == "flush_volumes_matrix" || opt_key == "prime_volume" @@ -239,7 +253,14 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "travel_speed_z" || opt_key == "initial_layer_speed" || opt_key == "initial_layer_travel_speed" - || opt_key == "slow_down_layers") { + || opt_key == "slow_down_layers" + || opt_key == "wipe_tower_cone_angle" + || opt_key == "wipe_tower_extra_spacing" + || opt_key == "wipe_tower_extruder" + || opt_key == "wiping_volumes_extruders" + || opt_key == "enable_filament_ramming" + || opt_key == "purge_in_prime_tower" + ) { //|| opt_key == "z_offset") { steps.emplace_back(psWipeTower); steps.emplace_back(psSkirtBrim); @@ -2157,20 +2178,29 @@ bool Print::has_wipe_tower() const return false; } -const WipeTowerData& Print::wipe_tower_data(size_t filaments_cnt) const +const WipeTowerData &Print::wipe_tower_data(size_t filaments_cnt) const { // If the wipe tower wasn't created yet, make sure the depth and brim_width members are set to default. - if (! is_step_done(psWipeTower) && filaments_cnt !=0) { - // BBS - double width = m_config.prime_tower_width; + if (!is_step_done(psWipeTower) && filaments_cnt != 0) { + double width = m_config.prime_tower_width; double layer_height = 0.2; // hard code layer height - double wipe_volume = m_config.prime_volume; - if (filaments_cnt == 1 && enable_timelapse_print()) { + double wipe_volume = m_config.prime_volume; + if (m_config.purge_in_prime_tower || (filaments_cnt == 1 && enable_timelapse_print())) { const_cast(this)->m_wipe_tower_data.depth = wipe_volume / (layer_height * width); } else { - const_cast(this)->m_wipe_tower_data.depth = wipe_volume * (filaments_cnt - 1) / (layer_height * width); + // Calculating depth should take into account currently set wiping volumes. + // For a long time, the initial preview would just use 900/width per toolchange (15mm on a 60mm wide tower) + // and it worked well enough. Let's try to do slightly better by accounting for the purging volumes. + std::vector> wipe_volumes = WipeTower2::extract_wipe_volumes(m_config); + std::vector max_wipe_volumes; + for (const std::vector &v : wipe_volumes) + max_wipe_volumes.emplace_back(*std::max_element(v.begin(), v.end())); + float maximum = std::accumulate(max_wipe_volumes.begin(), max_wipe_volumes.end(), 0.f); + maximum = maximum * filaments_cnt / max_wipe_volumes.size(); + + const_cast(this)->m_wipe_tower_data.depth = maximum / (layer_height * width); } - const_cast(this)->m_wipe_tower_data.brim_width = m_config.prime_tower_brim_width; + const_cast(this)->m_wipe_tower_data.brim_width = m_config.prime_tower_brim_width; } return m_wipe_tower_data; @@ -2240,97 +2270,190 @@ void Print::_make_wipe_tower() } this->throw_if_canceled(); - // Initialize the wipe tower. - // BBS: in BBL machine, wipe tower is only use to prime extruder. So just use a global wipe volume. - WipeTower wipe_tower(m_config, m_plate_index, m_origin, m_config.prime_volume, m_wipe_tower_data.tool_ordering.first_extruder(), - m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z); + if (!m_config.purge_in_prime_tower) { + // in BBL machine, wipe tower is only use to prime extruder. So just use a global wipe volume. + WipeTower wipe_tower(m_config, m_plate_index, m_origin, m_config.prime_volume, m_wipe_tower_data.tool_ordering.first_extruder(), + m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z); - //wipe_tower.set_retract(); - //wipe_tower.set_zhop(); + // wipe_tower.set_retract(); + // wipe_tower.set_zhop(); - // Set the extruder & material properties at the wipe tower object. - for (size_t i = 0; i < number_of_extruders; ++ i) - wipe_tower.set_extruder(i, m_config); + // Set the extruder & material properties at the wipe tower object. + for (size_t i = 0; i < number_of_extruders; ++i) + wipe_tower.set_extruder(i, m_config); - // BBS: remove priming logic - //m_wipe_tower_data.priming = Slic3r::make_unique>( - // wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); + // BBS: remove priming logic + // m_wipe_tower_data.priming = Slic3r::make_unique>( + // wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); - // Lets go through the wipe tower layers and determine pairs of extruder changes for each - // to pass to wipe_tower (so that it can use it for planning the layout of the tower) - { - // BBS: priming logic is removed, so get the initial extruder by first_extruder() - unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.first_extruder(); - for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers - if (!layer_tools.has_wipe_tower) continue; - bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); - wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id); + // Lets go through the wipe tower layers and determine pairs of extruder changes for each + // to pass to wipe_tower (so that it can use it for planning the layout of the tower) + { + // BBS: priming logic is removed, so get the initial extruder by first_extruder() + unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.first_extruder(); + for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers + if (!layer_tools.has_wipe_tower) + continue; + bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); + wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, current_extruder_id, + current_extruder_id); - for (const auto extruder_id : layer_tools.extruders) { - // BBS: priming logic is removed, so no need to do toolchange for first extruder - if (/*(first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || */extruder_id != current_extruder_id) { - float volume_to_purge = wipe_volumes[current_extruder_id][extruder_id]; - volume_to_purge *= m_config.flush_multiplier; + for (const auto extruder_id : layer_tools.extruders) { + // BBS: priming logic is removed, so no need to do toolchange for first extruder + if (/*(first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || */ extruder_id != + current_extruder_id) { + float volume_to_purge = wipe_volumes[current_extruder_id][extruder_id]; + volume_to_purge *= m_config.flush_multiplier; - // Not all of that can be used for infill purging: - //volume_to_purge -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + // Not all of that can be used for infill purging: + // volume_to_purge -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); - // try to assign some infills/objects for the wiping: - volume_to_purge = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, volume_to_purge); + // try to assign some infills/objects for the wiping: + volume_to_purge = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, + volume_to_purge); - // add back the minimal amount toforce on the wipe tower: - //volume_to_purge += (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + // add back the minimal amount toforce on the wipe tower: + // volume_to_purge += (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); - // request a toolchange at the wipe tower with at least volume_to_wipe purging amount - wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, - current_extruder_id, extruder_id, m_config.prime_volume, volume_to_purge); - current_extruder_id = extruder_id; + // request a toolchange at the wipe tower with at least volume_to_wipe purging amount + wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, + current_extruder_id, extruder_id, m_config.prime_volume, volume_to_purge); + current_extruder_id = extruder_id; + } } - } - layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this); + layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this); - // if enable timelapse, slice all layer - if (enable_timelapse_print()) { - if (layer_tools.wipe_tower_partitions == 0) - wipe_tower.set_last_layer_extruder_fill(false); - continue; - } + // if enable timelapse, slice all layer + if (enable_timelapse_print()) { + if (layer_tools.wipe_tower_partitions == 0) + wipe_tower.set_last_layer_extruder_fill(false); + continue; + } - if (&layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0) - break; + if (&layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0) + break; + } } - } - // Generate the wipe tower layers. - m_wipe_tower_data.tool_changes.reserve(m_wipe_tower_data.tool_ordering.layer_tools().size()); - wipe_tower.generate(m_wipe_tower_data.tool_changes); - m_wipe_tower_data.depth = wipe_tower.get_depth(); - m_wipe_tower_data.brim_width = wipe_tower.get_brim_width(); + // Generate the wipe tower layers. + m_wipe_tower_data.tool_changes.reserve(m_wipe_tower_data.tool_ordering.layer_tools().size()); + wipe_tower.generate(m_wipe_tower_data.tool_changes); + m_wipe_tower_data.depth = wipe_tower.get_depth(); + m_wipe_tower_data.brim_width = wipe_tower.get_brim_width(); - // Unload the current filament over the purge tower. - coordf_t layer_height = m_objects.front()->config().layer_height.value; - if (m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions > 0) { - // The wipe tower goes up to the last layer of the print. - if (wipe_tower.layer_finished()) { - // The wipe tower is printed to the top of the print and it has no space left for the final extruder purge. - // Lift Z to the next layer. - wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z + layer_height), float(layer_height), 0, false, true); + // Unload the current filament over the purge tower. + coordf_t layer_height = m_objects.front()->config().layer_height.value; + if (m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions > 0) { + // The wipe tower goes up to the last layer of the print. + if (wipe_tower.layer_finished()) { + // The wipe tower is printed to the top of the print and it has no space left for the final extruder purge. + // Lift Z to the next layer. + wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z + layer_height), float(layer_height), 0, false, + true); + } else { + // There is yet enough space at this layer of the wipe tower for the final purge. + } } else { - // There is yet enough space at this layer of the wipe tower for the final purge. + // The wipe tower does not reach the last print layer, perform the pruge at the last print layer. + assert(m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions == 0); + wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z), float(layer_height), 0, false, true); } - } else { - // The wipe tower does not reach the last print layer, perform the pruge at the last print layer. - assert(m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions == 0); - wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z), float(layer_height), 0, false, true); - } - m_wipe_tower_data.final_purge = Slic3r::make_unique( - wipe_tower.tool_change((unsigned int)(-1))); + m_wipe_tower_data.final_purge = Slic3r::make_unique(wipe_tower.tool_change((unsigned int) (-1))); - m_wipe_tower_data.used_filament = wipe_tower.get_used_filament(); - m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges(); - const Vec3d origin = this->get_plate_origin(); - m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position(), wipe_tower.width(), wipe_tower.get_height(), wipe_tower.get_layer_height(), m_wipe_tower_data.depth, - m_wipe_tower_data.brim_width, {scale_(origin.x()), scale_(origin.y())}); + m_wipe_tower_data.used_filament = wipe_tower.get_used_filament(); + m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges(); + const Vec3d origin = this->get_plate_origin(); + m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position(), wipe_tower.width(), wipe_tower.get_height(), + wipe_tower.get_layer_height(), m_wipe_tower_data.depth, m_wipe_tower_data.brim_width, + {scale_(origin.x()), scale_(origin.y())}); + } else { + // Initialize the wipe tower. + WipeTower2 wipe_tower(m_config, m_default_region_config, m_plate_index, m_origin, wipe_volumes, + m_wipe_tower_data.tool_ordering.first_extruder()); + + // wipe_tower.set_retract(); + // wipe_tower.set_zhop(); + + // Set the extruder & material properties at the wipe tower object. + for (size_t i = 0; i < number_of_extruders; ++i) + wipe_tower.set_extruder(i, m_config); + + // m_wipe_tower_data.priming = Slic3r::make_unique>( + // wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); + + // Lets go through the wipe tower layers and determine pairs of extruder changes for each + // to pass to wipe_tower (so that it can use it for planning the layout of the tower) + { + unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.first_extruder(); + for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers + if (!layer_tools.has_wipe_tower) + continue; + bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); + wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, current_extruder_id, + current_extruder_id, false); + for (const auto extruder_id : layer_tools.extruders) { + if (/*(first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || */ extruder_id != + current_extruder_id) { + float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange + volume_to_wipe *= m_config.flush_multiplier; + // Not all of that can be used for infill purging: + volume_to_wipe -= (float) m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + + // try to assign some infills/objects for the wiping: + volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, + volume_to_wipe); + + // add back the minimal amount toforce on the wipe tower: + volume_to_wipe += (float) m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); + + // request a toolchange at the wipe tower with at least volume_to_wipe purging amount + wipe_tower.plan_toolchange((float) layer_tools.print_z, (float) layer_tools.wipe_tower_layer_height, + current_extruder_id, extruder_id, volume_to_wipe); + current_extruder_id = extruder_id; + } + } + layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this); + if (&layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0) + break; + } + } + + // Generate the wipe tower layers. + m_wipe_tower_data.tool_changes.reserve(m_wipe_tower_data.tool_ordering.layer_tools().size()); + wipe_tower.generate(m_wipe_tower_data.tool_changes); + m_wipe_tower_data.depth = wipe_tower.get_depth(); + m_wipe_tower_data.z_and_depth_pairs = wipe_tower.get_z_and_depth_pairs(); + 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. + coordf_t layer_height = m_objects.front()->config().layer_height.value; + if (m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions > 0) { + // The wipe tower goes up to the last layer of the print. + if (wipe_tower.layer_finished()) { + // The wipe tower is printed to the top of the print and it has no space left for the final extruder purge. + // Lift Z to the next layer. + wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z + layer_height), float(layer_height), 0, false, + true); + } else { + // There is yet enough space at this layer of the wipe tower for the final purge. + } + } else { + // The wipe tower does not reach the last print layer, perform the pruge at the last print layer. + assert(m_wipe_tower_data.tool_ordering.back().wipe_tower_partitions == 0); + wipe_tower.set_layer(float(m_wipe_tower_data.tool_ordering.back().print_z), float(layer_height), 0, false, true); + } + m_wipe_tower_data.final_purge = Slic3r::make_unique(wipe_tower.tool_change((unsigned int) (-1))); + + m_wipe_tower_data.used_filament = wipe_tower.get_used_filament(); + m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges(); + const Vec3d origin = Vec3d::Zero(); + m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position(), wipe_tower.width(), wipe_tower.get_wipe_tower_height(), + config().initial_layer_print_height, m_wipe_tower_data.depth, + m_wipe_tower_data.z_and_depth_pairs, m_wipe_tower_data.brim_width, + config().wipe_tower_rotation_angle, config().wipe_tower_cone_angle, + {scale_(origin.x()), scale_(origin.y())}); + } } // Generate a recommended G-code output file name based on the format template, default extension, and template parameters diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 83ccfbaa6d..f688e4ec3b 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -11,6 +11,7 @@ #include "TriangleMeshSlicer.hpp" #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" +#include "GCode/WipeTower2.hpp" #include "GCode/ThumbnailData.hpp" #include "GCode/GCodeProcessor.hpp" #include "MultiMaterialSegmentation.hpp" @@ -545,7 +546,10 @@ struct FakeWipeTower float height; float layer_height; float depth; + std::vector> z_and_depth_pairs; float brim_width; + float rotation_angle; + float cone_angle; Vec2d plate_origin; void set_fake_extrusion_data(Vec2f p, float w, float h, float lh, float d, float bd, Vec2d o) @@ -558,8 +562,21 @@ struct FakeWipeTower brim_width = bd; plate_origin = o; } - + void set_fake_extrusion_data(const Vec2f& p, float w, float h, float lh, float d, const std::vector>& zad, float bd, float ra, float ca, const Vec2d& o) + { + pos = p; + width = w; + height = h; + layer_height = lh; + depth = d; + z_and_depth_pairs = zad; + brim_width = bd; + rotation_angle = ra; + cone_angle = ca; + plate_origin = o; + } void set_pos(Vec2f p) { pos = p; } + void set_pos_and_rotation(const Vec2f& p, float rotation) { pos = p; rotation_angle = rotation; } std::vector getFakeExtrusionPathsFromWipeTower() const { @@ -587,6 +604,82 @@ struct FakeWipeTower } return paths; } + + std::vector getFakeExtrusionPathsFromWipeTower2() const + { + float h = height; + float lh = layer_height; + int d = scale_(depth); + int w = scale_(width); + int bd = scale_(brim_width); + Point minCorner = { -bd, -bd }; + Point maxCorner = { minCorner.x() + w + bd, minCorner.y() + d + bd }; + + const auto [cone_base_R, cone_scale_x] = WipeTower2::get_wipe_tower_cone_base(width, height, depth, cone_angle); + + std::vector paths; + for (float hh = 0.f; hh < h; hh += lh) { + + if (hh != 0.f) { + // The wipe tower may be getting smaller. Find the depth for this layer. + size_t i = 0; + for (i=0; i= z_and_depth_pairs[i].first && hh < z_and_depth_pairs[i+1].first) + break; + d = scale_(z_and_depth_pairs[i].second); + minCorner = {0.f, -d/2 + scale_(z_and_depth_pairs.front().second/2.f)}; + maxCorner = { minCorner.x() + w, minCorner.y() + d }; + } + + + ExtrusionPath path(ExtrusionRole::erWipeTower, 0.0, 0.0, lh); + path.polyline = { minCorner, {maxCorner.x(), minCorner.y()}, maxCorner, {minCorner.x(), maxCorner.y()}, minCorner }; + paths.push_back({ path }); + + // We added the border, now add several parallel lines so we can detect an object that is fully inside the tower. + // For now, simply use fixed spacing of 3mm. + for (coord_t y=minCorner.y()+scale_(3.); y 0.) { + path.polyline.clear(); + double r = cone_base_R * (1 - hh/height); + for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.) + path.polyline.points.emplace_back(Point::new_scale(width/2. + r * std::cos(alpha)/cone_scale_x, depth/2. + r * std::sin(alpha))); + paths.back().emplace_back(path); + if (hh == 0.f) { // Cone brim. + for (float bw=brim_width; bw>0.f; bw-=3.f) { + path.polyline.clear(); + for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.) // see load_wipe_tower_preview, where the same is a bit clearer + path.polyline.points.emplace_back(Point::new_scale( + width/2. + cone_base_R * std::cos(alpha)/cone_scale_x * (1. + cone_scale_x*bw/cone_base_R), + depth/2. + cone_base_R * std::sin(alpha) * (1. + bw/cone_base_R)) + ); + paths.back().emplace_back(path); + } + } + } + + // Only the first layer has brim. + if (hh == 0.f) { + minCorner = minCorner + Point(bd, bd); + maxCorner = maxCorner - Point(bd, bd); + } + } + + // Rotate and translate the tower into the final position. + for (ExtrusionPaths& ps : paths) { + for (ExtrusionPath& p : ps) { + p.polyline.rotate(Geometry::deg2rad(rotation_angle)); + p.polyline.translate(scale_(pos.x()), scale_(pos.y())); + } + } + + return paths; + } }; struct WipeTowerData @@ -604,7 +697,9 @@ struct WipeTowerData // Depth of the wipe tower to pass to GLCanvas3D for exact bounding box: float depth; + std::vector> z_and_depth_pairs; float brim_width; + float height; void clear() { priming.reset(nullptr); @@ -617,7 +712,7 @@ struct WipeTowerData } private: - // Only allow the WipeTowerData to be instantiated internally by Print, + // Only allow the WipeTowerData to be instantiated internally by Print, // as this WipeTowerData shares reference to Print::m_tool_ordering. friend class Print; WipeTowerData(ToolOrdering &tool_ordering) : tool_ordering(tool_ordering) { clear(); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index aa757fffaf..a4b9603fc5 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1369,17 +1369,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats { 2. }); - def = this->add("filament_minimal_purge_on_wipe_tower", coFloats); - def->label = L("Minimal purge on wipe tower"); - def->tooltip = L("After a tool change, the exact position of the newly loaded filament inside " - "the nozzle may not be known, and the filament pressure is likely not yet stable. " - "Before purging the print head into an infill or a sacrificial object, Slic3r will always prime " - "this amount of material into the wipe tower to produce successive infill or sacrificial object extrusions reliably."); - def->sidetext = L("mm³"); - def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats { 15. }); - def = this->add("machine_load_filament_time", coFloat); def->label = L("Filament load time"); def->tooltip = L("Time to load new filament when switch filament. For statistics only"); @@ -1415,6 +1404,132 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionPercents{ 100 }); +def = this->add("filament_loading_speed", coFloats); + def->label = L("Loading speed"); + def->tooltip = L("Speed used for loading the filament on the wipe tower."); + def->sidetext = L("mm/s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 28. }); + + def = this->add("filament_loading_speed_start", coFloats); + def->label = L("Loading speed at the start"); + def->tooltip = L("Speed used at the very beginning of loading phase."); + def->sidetext = L("mm/s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 3. }); + + def = this->add("filament_unloading_speed", coFloats); + def->label = L("Unloading speed"); + def->tooltip = L("Speed used for unloading the filament on the wipe tower (does not affect " + " initial part of unloading just after ramming)."); + def->sidetext = L("mm/s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 90. }); + + def = this->add("filament_unloading_speed_start", coFloats); + def->label = L("Unloading speed at the start"); + def->tooltip = L("Speed used for unloading the tip of the filament immediately after ramming."); + def->sidetext = L("mm/s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 100. }); + + def = this->add("filament_toolchange_delay", coFloats); + def->label = L("Delay after unloading"); + def->tooltip = L("Time to wait after the filament is unloaded. " + "May help to get reliable toolchanges with flexible materials " + "that may need more time to shrink to original dimensions."); + def->sidetext = L("s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 0. }); + + def = this->add("filament_cooling_moves", coInts); + def->label = L("Number of cooling moves"); + def->tooltip = L("Filament is cooled by being moved back and forth in the " + "cooling tubes. Specify desired number of these moves."); + def->max = 0; + def->max = 20; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionInts { 4 }); + + def = this->add("filament_cooling_initial_speed", coFloats); + def->label = L("Speed of the first cooling move"); + def->tooltip = L("Cooling moves are gradually accelerating beginning at this speed."); + def->sidetext = L("mm/s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 2.2 }); + + def = this->add("filament_minimal_purge_on_wipe_tower", coFloats); + def->label = L("Minimal purge on wipe tower"); + def->tooltip = L("After a tool change, the exact position of the newly loaded filament inside " + "the nozzle may not be known, and the filament pressure is likely not yet stable. " + "Before purging the print head into an infill or a sacrificial object, Slic3r will always prime " + "this amount of material into the wipe tower to produce successive infill or sacrificial object extrusions reliably."); + def->sidetext = L("mm³"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 15. }); + + def = this->add("filament_cooling_final_speed", coFloats); + def->label = L("Speed of the last cooling move"); + def->tooltip = L("Cooling moves are gradually accelerating towards this speed."); + def->sidetext = L("mm/s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 3.4 }); + + def = this->add("filament_load_time", coFloats); + def->label = L("Filament load time"); + def->tooltip = L("Time for the printer firmware (or the Multi Material Unit 2.0) to load a new filament during a tool change (when executing the T code). This time is added to the total print time by the G-code time estimator."); + def->sidetext = L("s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 0. }); + + def = this->add("filament_ramming_parameters", coStrings); + def->label = L("Ramming parameters"); + def->tooltip = L("This string is edited by RammingDialog and contains ramming specific parameters."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionStrings { "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0|" + " 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" }); + + def = this->add("filament_unload_time", coFloats); + def->label = L("Filament unload time"); + def->tooltip = L("Time for the printer firmware (or the Multi Material Unit 2.0) to unload a filament during a tool change (when executing the T code). This time is added to the total print time by the G-code time estimator."); + def->sidetext = L("s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 0. }); + + def = this->add("filament_multitool_ramming", coBools); + def->label = L("Enable ramming for multitool setups"); + def->tooltip = L("Perform ramming when using multitool printer (i.e. when the 'Single Extruder Multimaterial' in Printer Settings is unchecked). " + "When checked, a small amount of filament is rapidly extruded on the wipe tower just before the toolchange. " + "This option is only used when the wipe tower is enabled."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBools { false }); + + def = this->add("filament_multitool_ramming_volume", coFloats); + def->label = L("Multitool ramming volume"); + def->tooltip = L("The volume to be rammed before the toolchange."); + def->sidetext = L("mm³"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 10. }); + + def = this->add("filament_multitool_ramming_flow", coFloats); + def->label = L("Multitool ramming flow"); + def->tooltip = L("Flow used for ramming the filament before the toolchange."); + def->sidetext = L("mm³/s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 10. }); + def = this->add("filament_density", coFloats); def->label = L("Density"); def->tooltip = L("Filament density. For statistics only"); @@ -2460,6 +2575,48 @@ void PrintConfigDef::init_fff_params() def->readonly = false; def->set_default_value(new ConfigOptionFloat { 0.0 }); + def = this->add("cooling_tube_retraction", coFloat); + def->label = L("Cooling tube position"); + def->tooltip = L("Distance of the center-point of the cooling tube from the extruder tip."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(91.5)); + + def = this->add("cooling_tube_length", coFloat); + def->label = L("Cooling tube length"); + def->tooltip = L("Length of the cooling tube to limit space for cooling moves inside it."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(5.)); + + def = this->add("high_current_on_filament_swap", coBool); + def->label = L("High extruder current on filament swap"); + def->tooltip = L("It may be beneficial to increase the extruder motor current during the filament exchange" + " sequence to allow for rapid ramming feed rates and to overcome resistance when loading" + " a filament with an ugly shaped tip."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(0)); + + def = this->add("parking_pos_retraction", coFloat); + def->label = L("Filament parking position"); + def->tooltip = L("Distance of the extruder tip from the position where the filament is parked " + "when unloaded. This should match the value in printer firmware."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(92.)); + + def = this->add("extra_loading_move", coFloat); + def->label = L("Extra loading distance"); + def->tooltip = L("When set to zero, the distance the filament is moved from parking position during load " + "is exactly the same as it was moved back during unload. When positive, it is loaded further, " + " if negative, the loading move is shorter than unloading."); + def->sidetext = L("mm"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(-2.)); + def = this->add("start_end_points", coPoints); def->label = L("Start end points"); def->tooltip = L("The start and end points which is from cutter area to garbage can."); @@ -3026,19 +3183,39 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionStrings { " " }); def = this->add("single_extruder_multi_material", coBool); - //def->label = L("Single Extruder Multi Material"); - //def->tooltip = L("Use single nozzle to print multi filament"); - def->mode = comDevelop; - def->set_default_value(new ConfigOptionBool(false)); + def->label = L("Single Extruder Multi Material"); + def->tooltip = L("Use single nozzle to print multi filament"); + def->mode = comAdvanced; + def->readonly = true; + def->set_default_value(new ConfigOptionBool(true)); + + def = this->add("purge_in_prime_tower", coBool); + def->label = L("Purge in prime tower"); + def->tooltip = L("Purge remaining filament into prime tower"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(true)); + + def = this->add("enable_filament_ramming", coBool); + def->label = L("Enable filament ramming"); + def->tooltip = L("Enable filament ramming"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(true)); + def = this->add("wipe_tower_no_sparse_layers", coBool); - //def->label = L("No sparse layers (EXPERIMENTAL)"); - //def->tooltip = L("If enabled, the wipe tower will not be printed on layers with no toolchanges. " - // "On layers with a toolchange, extruder will travel downward to print the wipe tower. " - // "User is responsible for ensuring there is no collision with the print."); - def->mode = comDevelop; + def->label = L("No sparse layers (EXPERIMENTAL)"); + def->tooltip = L("If enabled, the wipe tower will not be printed on layers with no toolchanges. " + "On layers with a toolchange, extruder will travel downward to print the wipe tower. " + "User is responsible for ensuring there is no collision with the print."); + def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("single_extruder_multi_material_priming", coBool); + def->label = L("Prime all printing extruders"); + def->tooltip = L("If enabled, all printing extruders will be primed at the front edge of the print bed at the start of the print."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(true)); + def = this->add("slice_closing_radius", coFloat); def->label = L("Slice gap closing radius"); def->category = L("Quality"); @@ -3679,7 +3856,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Flush multiplier"); def->tooltip = L("The actual flushing volumes is equal to the flush multiplier multiplied by the flushing volumes in the table."); def->sidetext = ""; - def->set_default_value(new ConfigOptionFloat(1.0)); + def->set_default_value(new ConfigOptionFloat(0.3)); // BBS def = this->add("prime_volume", coFloat); @@ -3712,13 +3889,13 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("mm"); def->min = 2.0; def->mode = comSimple; - def->set_default_value(new ConfigOptionFloat(35.)); + def->set_default_value(new ConfigOptionFloat(60.)); def = this->add("wipe_tower_rotation_angle", coFloat); - //def->label = L("Wipe tower rotation angle"); - //def->tooltip = L("Wipe tower rotation angle with respect to x-axis."); - //def->sidetext = L("°"); - def->mode = comDevelop; + def->label = L("Wipe tower rotation angle"); + def->tooltip = L("Wipe tower rotation angle with respect to x-axis."); + def->sidetext = L("°"); + def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.)); def = this->add("prime_tower_brim_width", coFloat); @@ -3729,6 +3906,41 @@ void PrintConfigDef::init_fff_params() def->min = 0.; def->set_default_value(new ConfigOptionFloat(3.)); + 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 = comAdvanced; + def->min = 100.; + def->max = 300.; + def->set_default_value(new ConfigOptionPercent(100.)); + + def = this->add("wipe_tower_extruder", coInt); + def->label = L("Wipe tower extruder"); + def->category = L("Extruders"); + def->tooltip = L("The extruder to use when printing perimeter of the wipe tower. " + "Set to 0 to use the one that is available (non-soluble would be preferred)."); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionInt(0)); + + def = this->add("wiping_volumes_extruders", coFloats); + def->label = L("Purging volumes - load/unload volumes"); + def->tooltip = L("This vector saves required volumes to change from/to each tool used on the " + "wipe tower. These values are used to simplify creation of the full purging " + "volumes below."); + def->set_default_value(new ConfigOptionFloats { 70., 70., 70., 70., 70., 70., 70., 70., 70., 70. }); + def = this->add("flush_into_infill", coBool); def->category = L("Flush options"); def->label = L("Flush into objects' infill"); @@ -3754,13 +3966,12 @@ void PrintConfigDef::init_fff_params() "It will not take effect, unless the prime tower is enabled."); def->set_default_value(new ConfigOptionBool(false)); - //BBS - //def = this->add("wipe_tower_bridging", coFloat); - //def->label = L("Maximal bridging distance"); - //def->tooltip = L("Maximal distance between supports on sparse infill sections."); - //def->sidetext = L("mm"); - //def->mode = comAdvanced; - //def->set_default_value(new ConfigOptionFloat(10.)); + def = this->add("wipe_tower_bridging", coFloat); + def->label = L("Maximal bridging distance"); + def->tooltip = L("Maximal distance between supports on sparse infill sections."); + def->sidetext = L("mm"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(10.)); def = this->add("xy_hole_compensation", coFloat); def->label = L("X-Y hole compensation"); @@ -4704,7 +4915,9 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va } } else if (opt_key == "overhang_fan_threshold" && value == "5%") { value = "10%"; - } + } else if(opt_key == "single_extruder_multi_material") { + value = "1"; + } // Ignore the following obsolete configuration keys: static std::set ignore = { diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 3bdfb8844d..03c1f75c30 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -870,9 +870,6 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInts, temperature_vitrification)) //BBS ((ConfigOptionFloats, filament_max_volumetric_speed)) ((ConfigOptionInts, required_nozzle_HRC)) - ((ConfigOptionFloat, machine_load_filament_time)) - ((ConfigOptionFloat, machine_unload_filament_time)) - ((ConfigOptionFloats, filament_minimal_purge_on_wipe_tower)) // BBS ((ConfigOptionBool, scan_first_layer)) // ((ConfigOptionBool, spaghetti_detector)) @@ -900,6 +897,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionString, machine_start_gcode)) ((ConfigOptionStrings, filament_start_gcode)) ((ConfigOptionBool, single_extruder_multi_material)) + ((ConfigOptionBool, single_extruder_multi_material_priming)) ((ConfigOptionBool, wipe_tower_no_sparse_layers)) ((ConfigOptionString, change_filament_gcode)) ((ConfigOptionFloat, travel_speed)) @@ -919,6 +917,33 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloatOrPercent, initial_layer_travel_speed)) ((ConfigOptionBool, bbl_calib_mark_logo)) + // Orca: mmu + ((ConfigOptionFloat, cooling_tube_retraction)) + ((ConfigOptionFloat, cooling_tube_length)) + ((ConfigOptionBool, high_current_on_filament_swap)) + ((ConfigOptionFloat, parking_pos_retraction)) + ((ConfigOptionFloat, extra_loading_move)) + ((ConfigOptionFloat, machine_load_filament_time)) + ((ConfigOptionFloat, machine_unload_filament_time)) + ((ConfigOptionFloats, filament_loading_speed)) + ((ConfigOptionFloats, filament_loading_speed_start)) + ((ConfigOptionFloats, filament_load_time)) + ((ConfigOptionFloats, filament_unloading_speed)) + ((ConfigOptionFloats, filament_unloading_speed_start)) + ((ConfigOptionFloats, filament_toolchange_delay)) + // Orca todo: consolidate with machine_load_filament_time + ((ConfigOptionFloats, filament_unload_time)) + ((ConfigOptionInts, filament_cooling_moves)) + ((ConfigOptionFloats, filament_cooling_initial_speed)) + ((ConfigOptionFloats, filament_minimal_purge_on_wipe_tower)) + ((ConfigOptionFloats, filament_cooling_final_speed)) + ((ConfigOptionStrings, filament_ramming_parameters)) + ((ConfigOptionBools, filament_multitool_ramming)) + ((ConfigOptionFloats, filament_multitool_ramming_volume)) + ((ConfigOptionFloats, filament_multitool_ramming_flow)) + ((ConfigOptionBool, purge_in_prime_tower)) + ((ConfigOptionBool, enable_filament_ramming)) + ) // This object is mapped to Perl as Slic3r::Config::Print. @@ -1021,9 +1046,16 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloat, wipe_tower_per_color_wipe)) ((ConfigOptionFloat, wipe_tower_rotation_angle)) ((ConfigOptionFloat, prime_tower_brim_width)) - //((ConfigOptionFloat, wipe_tower_bridging)) + ((ConfigOptionFloat, wipe_tower_bridging)) ((ConfigOptionFloats, flush_volumes_matrix)) ((ConfigOptionFloats, flush_volumes_vector)) + + // Orca: mmu support + ((ConfigOptionFloat, wipe_tower_cone_angle)) + ((ConfigOptionPercent, wipe_tower_extra_spacing)) + ((ConfigOptionInt, wipe_tower_extruder)) + ((ConfigOptionFloats, wiping_volumes_extruders)) + // BBS: wipe tower is only used for priming ((ConfigOptionFloat, prime_volume)) ((ConfigOptionFloat, flush_multiplier)) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 82bd5ac3a3..61dc8c9491 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -278,7 +278,8 @@ set(SLIC3R_GUI_SOURCES GUI/wxExtensions.cpp GUI/wxExtensions.hpp GUI/WipeTowerDialog.cpp - GUI/WipeTowerDialog.hpp + GUI/RammingChart.cpp + GUI/RammingChart.hpp GUI/RemovableDriveManager.cpp GUI/RemovableDriveManager.hpp GUI/SendSystemInfoDialog.cpp diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index d3e74d7f60..28f5189a72 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -645,10 +645,23 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool have_ooze_prevention = config->opt_bool("ooze_prevention"); toggle_field("standby_temperature_delta", have_ooze_prevention); + // Orca todo: enable/disable wipe tower parameters + // for (auto el : + // {"wipe_tower_x", "wipe_tower_y", , "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_cone_angle", + // "wipe_tower_extra_spacing", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming"}) + // toggle_field(el, have_wipe_tower); + bool have_prime_tower = config->opt_bool("enable_prime_tower"); - for (auto el : { "prime_tower_width", "prime_volume", "prime_tower_brim_width"}) + for (auto el : { "prime_tower_width", "prime_tower_brim_width"}) toggle_line(el, have_prime_tower); + bool purge_in_primetower = preset_bundle->printers.get_edited_preset().config.opt_bool("purge_in_prime_tower"); + + for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_bridging", "wipe_tower_no_sparse_layers"}) + toggle_line(el, have_prime_tower && purge_in_primetower); + + toggle_line("prime_volume",have_prime_tower && !purge_in_primetower); + for (auto el : {"flush_into_infill", "flush_into_support", "flush_into_objects"}) toggle_field(el, have_prime_tower); @@ -692,7 +705,6 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line("exclude_object", gcflavor == gcfKlipper); toggle_line("min_width_top_surface",config->opt_bool("only_one_wall_top")); - } void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 24199e855e..40d9f52f5f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2637,12 +2637,13 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re float w = dynamic_cast(m_config->option("prime_tower_width"))->value; float a = dynamic_cast(proj_cfg.option("wipe_tower_rotation_angle"))->value; // BBS - float v = dynamic_cast(m_config->option("prime_volume"))->value; + // float v = dynamic_cast(m_config->option("prime_volume"))->value; Vec3d plate_origin = ppl.get_plate(plate_id)->get_origin(); const Print* print = m_process->fff_print(); - float brim_width = print->wipe_tower_data(filaments_count).brim_width; - Vec3d wipe_tower_size = ppl.get_plate(plate_id)->estimate_wipe_tower_size(w, v); + const auto& wipe_tower_data = print->wipe_tower_data(filaments_count); + float brim_width = wipe_tower_data.brim_width; + Vec3d wipe_tower_size = ppl.get_plate(plate_id)->estimate_wipe_tower_size(w, wipe_tower_data.depth); const float margin = 15.f; BoundingBoxf3 plate_bbox = wxGetApp().plater()->get_partplate_list().get_plate(plate_id)->get_bounding_box(); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 2db9dc4621..cb056161a9 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -1549,7 +1549,7 @@ std::vector PartPlate::get_used_extruders() return used_extruders; } -Vec3d PartPlate::estimate_wipe_tower_size(const double w, const double wipe_volume) const +Vec3d PartPlate::estimate_wipe_tower_size(const double w, const double d) const { Vec3d wipe_tower_size; std::vector plate_extruders = get_extruders(true); @@ -1579,7 +1579,7 @@ Vec3d PartPlate::estimate_wipe_tower_size(const double w, const double wipe_volu auto timelapse_type = dconfig.option>("timelapse_type"); bool timelapse_enabled = timelapse_type ? (timelapse_type->value == TimelapseType::tlSmooth) : false; - double depth = wipe_volume * (plate_extruders.size() - 1) / (layer_height * w); + double depth = d; if (timelapse_enabled || depth > EPSILON) { float min_wipe_tower_depth = 0.f; auto iter = WipeTower::min_depth_per_height.begin(); diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index 1facd33685..b1bc521718 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -285,7 +285,7 @@ public: ModelInstance* get_instance(int obj_id, int instance_id); Vec3d get_origin() { return m_origin; } - Vec3d estimate_wipe_tower_size(const double w, const double wipe_volume) const; + Vec3d estimate_wipe_tower_size(const double w, const double d) const; std::vector get_extruders(bool conside_custom_gcode = false) const; std::vector get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const; std::vector get_extruders_without_support(bool conside_custom_gcode = false) const; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 068049769a..c9f324fd35 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2328,7 +2328,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) "layer_height", "initial_layer_print_height", "min_layer_height", "max_layer_height", "brim_width", "wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers", "enable_support", "support_filament", "support_interface_filament", - "support_top_z_distance", "support_bottom_z_distance", "raft_layers" + "support_top_z_distance", "support_bottom_z_distance", "raft_layers", + "wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extruder", })) , sidebar(new Sidebar(q)) , notification_manager(std::make_unique(q)) @@ -11302,7 +11303,7 @@ void Plater::on_config_change(const DynamicPrintConfig &config) else if (boost::starts_with(opt_key, "enable_prime_tower") || boost::starts_with(opt_key, "prime_tower") || boost::starts_with(opt_key, "wipe_tower") || - // opt_key == "filament_minimal_purge_on_wipe_tower" // ? #ys_FIXME + opt_key == "filament_minimal_purge_on_wipe_tower" || opt_key == "single_extruder_multi_material" || // BBS opt_key == "prime_volume") { diff --git a/src/slic3r/GUI/RammingChart.cpp b/src/slic3r/GUI/RammingChart.cpp new file mode 100644 index 0000000000..244d83a9b8 --- /dev/null +++ b/src/slic3r/GUI/RammingChart.cpp @@ -0,0 +1,292 @@ +#include +#include + +#include "RammingChart.hpp" +#include "GUI.hpp" +#include "GUI_App.hpp" +#include "I18N.hpp" + +wxDEFINE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent); + + +void Chart::draw() { + wxAutoBufferedPaintDC dc(this); // unbuffered DC caused flickering on win + + dc.SetBrush(GetBackgroundColour()); + dc.SetPen(GetBackgroundColour()); + dc.DrawRectangle(GetClientRect()); // otherwise the background would end up black on windows + +#ifdef _WIN32 + dc.SetPen(wxPen(GetForegroundColour())); + dc.SetBrush(wxBrush(Slic3r::GUI::wxGetApp().get_highlight_default_clr())); +#else + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxWHITE_BRUSH); +#endif + dc.DrawRectangle(m_rect); + + if (visible_area.m_width < 0.499) { + dc.DrawText(_(L("NO RAMMING AT ALL")),wxPoint(m_rect.GetLeft()+m_rect.GetWidth()/2-legend_side,m_rect.GetBottom()-m_rect.GetHeight()/2)); + return; + } + + + if (!m_line_to_draw.empty()) { + for (unsigned int i=0;i2) { + m_buttons.erase(m_buttons.begin()+button_index); + recalculate_line(); + } +} + + + +void Chart::mouse_clicked(wxMouseEvent& event) { + wxPoint point = event.GetPosition(); + int button_index = which_button_is_clicked(point); + if ( button_index != -1) { + m_dragged = &m_buttons[button_index]; + m_previous_mouse = point; + } +} + + + +void Chart::mouse_moved(wxMouseEvent& event) { + if (!event.Dragging() || !m_dragged) return; + wxPoint pos = event.GetPosition(); + wxRect rect = m_rect; + rect.Deflate(side/2.); + if (!(rect.Contains(pos))) { // the mouse left chart area + mouse_left_window(event); + return; + } + int delta_x = pos.x - m_previous_mouse.x; + int delta_y = pos.y - m_previous_mouse.y; + m_dragged->move(fixed_x?0:double(delta_x)/m_rect.GetWidth() * visible_area.m_width,-double(delta_y)/m_rect.GetHeight() * visible_area.m_height); + m_previous_mouse = pos; + recalculate_line(); +} + + + +void Chart::mouse_double_clicked(wxMouseEvent& event) { + if (!manual_points_manipulation) + return; + wxPoint point = event.GetPosition(); + if (!m_rect.Contains(point)) // the click is outside the chart + return; + m_buttons.push_back(screen_to_math(point)); + std::sort(m_buttons.begin(),m_buttons.end()); + recalculate_line(); + return; +} + + + + +void Chart::recalculate_line() { + m_line_to_draw.clear(); + m_total_volume = 0.f; + + std::vector points; + for (auto& but : m_buttons) { + points.push_back(wxPoint(math_to_screen(but.get_pos()))); + if (points.size()>1 && points.back().x==points[points.size()-2].x) points.pop_back(); + if (points.size()>1 && points.back().x > m_rect.GetRight()) { + points.pop_back(); + break; + } + } + + // The calculation wouldn't work in case the ramming is to be turned off completely. + if (points.size()>1) { + std::sort(points.begin(),points.end(),[](wxPoint& a,wxPoint& b) { return a.x < b.x; }); + + // Cubic spline interpolation: see https://en.wikiversity.org/wiki/Cubic_Spline_Interpolation#Methods + const bool boundary_first_derivative = true; // true - first derivative is 0 at the leftmost and rightmost point + // false - second ---- || ------- + const int N = points.size()-1; // last point can be accessed as N, we have N+1 total points + std::vector diag(N+1); + std::vector mu(N+1); + std::vector lambda(N+1); + std::vector h(N+1); + std::vector rhs(N+1); + + // let's fill in inner equations + for (int i=1;i<=N;++i) h[i] = points[i].x-points[i-1].x; + std::fill(diag.begin(),diag.end(),2.f); + for (int i=1;i<=N-1;++i) { + mu[i] = h[i]/(h[i]+h[i+1]); + lambda[i] = 1.f - mu[i]; + rhs[i] = 6 * ( float(points[i+1].y-points[i].y )/(h[i+1]*(points[i+1].x-points[i-1].x)) - + float(points[i].y -points[i-1].y)/(h[i] *(points[i+1].x-points[i-1].x)) ); + } + + // now fill in the first and last equations, according to boundary conditions: + if (boundary_first_derivative) { + const float endpoints_derivative = 0; + lambda[0] = 1; + mu[N] = 1; + rhs[0] = (6.f/h[1]) * (float(points[0].y-points[1].y)/(points[0].x-points[1].x) - endpoints_derivative); + rhs[N] = (6.f/h[N]) * (endpoints_derivative - float(points[N-1].y-points[N].y)/(points[N-1].x-points[N].x)); + } + else { + lambda[0] = 0; + mu[N] = 0; + rhs[0] = 0; + rhs[N] = 0; + } + + // the trilinear system is ready to be solved: + for (int i=1;i<=N;++i) { + float multiple = mu[i]/diag[i-1]; // let's subtract proper multiple of above equation + diag[i]-= multiple * lambda[i-1]; + rhs[i] -= multiple * rhs[i-1]; + } + // now the back substitution (vector mu contains invalid values from now on): + rhs[N] = rhs[N]/diag[N]; + for (int i=N-1;i>=0;--i) + rhs[i] = (rhs[i]-lambda[i]*rhs[i+1])/diag[i]; + + unsigned int i=1; + float y=0.f; + for (int x=m_rect.GetLeft(); x<=m_rect.GetRight() ; ++x) { + if (splines) { + if (i x) + y = points[0].y; + else + if (points[N].x < x) + y = points[N].y; + else + y = (rhs[i-1]*pow(points[i].x-x,3)+rhs[i]*pow(x-points[i-1].x,3)) / (6*h[i]) + + (points[i-1].y-rhs[i-1]*h[i]*h[i]/6.f) * (points[i].x-x)/h[i] + + (points[i].y -rhs[i] *h[i]*h[i]/6.f) * (x-points[i-1].x)/h[i]; + m_line_to_draw.push_back(y); + } + else { + float x_math = screen_to_math(wxPoint(x,0)).m_x; + if (i+2<=points.size() && m_buttons[i+1].get_pos().m_x-0.125 < x_math) + ++i; + m_line_to_draw.push_back(math_to_screen(wxPoint2DDouble(x_math,m_buttons[i].get_pos().m_y)).y); + } + + m_line_to_draw.back() = std::max(m_line_to_draw.back(), m_rect.GetTop()-1); + m_line_to_draw.back() = std::min(m_line_to_draw.back(), m_rect.GetBottom()-1); + m_total_volume += (m_rect.GetBottom() - m_line_to_draw.back()) * (visible_area.m_width / m_rect.GetWidth()) * (visible_area.m_height / m_rect.GetHeight()); + } + } + + wxPostEvent(this->GetParent(), wxCommandEvent(EVT_WIPE_TOWER_CHART_CHANGED)); + Refresh(); +} + + + +std::vector Chart::get_ramming_speed(float sampling) const { + std::vector speeds_out; + + const int number_of_samples = std::round( visible_area.m_width / sampling); + if (number_of_samples>0) { + const int dx = (m_line_to_draw.size()-1) / number_of_samples; + for (int j=0;j> Chart::get_buttons() const { + std::vector> buttons_out; + for (const auto& button : m_buttons) + buttons_out.push_back(std::make_pair(float(button.get_pos().m_x),float(button.get_pos().m_y))); + return buttons_out; +} + + + + +BEGIN_EVENT_TABLE(Chart, wxWindow) +EVT_MOTION(Chart::mouse_moved) +EVT_LEFT_DOWN(Chart::mouse_clicked) +EVT_LEFT_UP(Chart::mouse_released) +EVT_LEFT_DCLICK(Chart::mouse_double_clicked) +EVT_RIGHT_DOWN(Chart::mouse_right_button_clicked) +EVT_LEAVE_WINDOW(Chart::mouse_left_window) +EVT_PAINT(Chart::paint_event) +END_EVENT_TABLE() diff --git a/src/slic3r/GUI/RammingChart.hpp b/src/slic3r/GUI/RammingChart.hpp new file mode 100644 index 0000000000..f62546b1d5 --- /dev/null +++ b/src/slic3r/GUI/RammingChart.hpp @@ -0,0 +1,120 @@ +#ifndef RAMMING_CHART_H_ +#define RAMMING_CHART_H_ + +#include +#include +#ifndef WX_PRECOMP + #include +#endif + +wxDECLARE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent); + + +class Chart : public wxWindow { + +public: + Chart(wxWindow* parent, wxRect rect,const std::vector>& initial_buttons,int ramming_speed_size, float sampling, int scale_unit=10) : + wxWindow(parent,wxID_ANY,rect.GetTopLeft(),rect.GetSize()), + scale_unit(scale_unit), legend_side(5*scale_unit) + { + SetBackgroundStyle(wxBG_STYLE_PAINT); + m_rect = wxRect(wxPoint(legend_side,0),rect.GetSize()-wxSize(legend_side,legend_side)); + visible_area = wxRect2DDouble(0.0, 0.0, sampling*ramming_speed_size, 20.); + m_buttons.clear(); + if (initial_buttons.size()>0) + for (const auto& pair : initial_buttons) + m_buttons.push_back(wxPoint2DDouble(pair.first,pair.second)); + recalculate_line(); + } + void set_xy_range(float x,float y) { + x = int(x/0.5) * 0.5; + if (x>=0) visible_area.SetRight(x); + if (y>=0) visible_area.SetBottom(y); + recalculate_line(); + } + float get_volume() const { return m_total_volume; } + float get_time() const { return visible_area.m_width; } + + std::vector get_ramming_speed(float sampling) const; //returns sampled ramming speed + std::vector> get_buttons() const; // returns buttons position + + void draw(); + + void mouse_clicked(wxMouseEvent& event); + void mouse_right_button_clicked(wxMouseEvent& event); + void mouse_moved(wxMouseEvent& event); + void mouse_double_clicked(wxMouseEvent& event); + void mouse_left_window(wxMouseEvent&) { m_dragged = nullptr; } + void mouse_released(wxMouseEvent&) { m_dragged = nullptr; } + void paint_event(wxPaintEvent&) { draw(); } + DECLARE_EVENT_TABLE() + + + + +private: + static const bool fixed_x = true; + static const bool splines = true; + static const bool manual_points_manipulation = false; + static const int side = 10; // side of draggable button + + const int scale_unit; + int legend_side; + + class ButtonToDrag { + public: + bool operator<(const ButtonToDrag& a) const { return m_pos.m_x < a.m_pos.m_x; } + ButtonToDrag(wxPoint2DDouble pos) : m_pos{pos} {}; + wxPoint2DDouble get_pos() const { return m_pos; } + void move(double x,double y) { m_pos.m_x+=x; m_pos.m_y+=y; } + private: + wxPoint2DDouble m_pos; // position in math coordinates + }; + + + + wxPoint math_to_screen(const wxPoint2DDouble& math) const { + wxPoint screen; + screen.x = (math.m_x-visible_area.m_x) * (m_rect.GetWidth() / visible_area.m_width ); + screen.y = (math.m_y-visible_area.m_y) * (m_rect.GetHeight() / visible_area.m_height ); + screen.y *= -1; + screen += m_rect.GetLeftBottom(); + return screen; + } + wxPoint2DDouble screen_to_math(const wxPoint& screen) const { + wxPoint2DDouble math = screen; + math -= m_rect.GetLeftBottom(); + math.m_y *= -1; + math.m_x *= visible_area.m_width / m_rect.GetWidth(); // scales to [0;1]x[0,1] + math.m_y *= visible_area.m_height / m_rect.GetHeight(); + return (math+visible_area.GetLeftTop()); + } + + int which_button_is_clicked(const wxPoint& point) const { + if (!m_rect.Contains(point)) + return -1; + for (unsigned int i=0;i m_buttons; + std::vector m_line_to_draw; + wxRect2DDouble visible_area; + ButtonToDrag* m_dragged = nullptr; + float m_total_volume = 0.f; + +}; + + +#endif // RAMMING_CHART_H_ \ No newline at end of file diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 8de6ae14f8..d183e4528d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -7,6 +7,7 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp" +#include "WipeTowerDialog.hpp" #include "Search.hpp" #include "OG_CustomCtrl.hpp" @@ -1590,15 +1591,15 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category) wxPostEvent(m_page_view, evt); } } - //else if (category == "Single extruder MM setup") { - // // When we show and hide "Single extruder MM setup" page, - // // related options are still in the search list - // // So, let's hightlighte a "single_extruder_multi_material" option, - // // as a "way" to show hidden page again - // field = get_field("single_extruder_multi_material"); - // if (field) - // set_focus(field->getWindow()); - //} + else if (category == "Single extruder MM setup") { + // When we show and hide "Single extruder MM setup" page, + // related options are still in the search list + // So, let's hightlighte a "single_extruder_multi_material" option, + // as a "way" to show hidden page again + field = get_field("single_extruder_multi_material"); + if (field) + set_focus(field->getWindow()); + } m_highlighter.init(get_custom_ctrl_with_blinking_ptr(opt_key)); } @@ -2072,6 +2073,13 @@ void TabPrint::build() optgroup->append_single_option_line("prime_tower_width"); optgroup->append_single_option_line("prime_volume"); optgroup->append_single_option_line("prime_tower_brim_width"); + optgroup->append_single_option_line("wipe_tower_rotation_angle"); + optgroup->append_single_option_line("wipe_tower_bridging"); + optgroup->append_single_option_line("wipe_tower_cone_angle"); + optgroup->append_single_option_line("wipe_tower_extra_spacing"); + optgroup->append_single_option_line("wipe_tower_no_sparse_layers"); + // optgroup->append_single_option_line("single_extruder_multi_material_priming"); + optgroup = page->new_optgroup(L("Flush options"), L"param_flush"); optgroup->append_single_option_line("flush_into_infill", "reduce-wasting-during-filament-change#wipe-into-infill"); @@ -2814,12 +2822,6 @@ void TabFilament::build() //BBS add_filament_overrides_page(); -#if 0 - //page = add_options_page(L("Advanced"), "advanced"); - // optgroup = page->new_optgroup(L("Wipe tower parameters")); - // optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower"); -#endif - const int gcode_field_height = 15; // 150 const int notes_field_height = 25; // 250 @@ -2844,7 +2846,49 @@ void TabFilament::build() option.opt.height = gcode_field_height;// 150; optgroup->append_single_option_line(option); - page = add_options_page(L("Notes"), "note"); + page = add_options_page(L("Multimaterial"), "advanced"); + optgroup = page->new_optgroup(L("Wipe tower parameters")); + optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower"); + + optgroup = page->new_optgroup(L("Toolchange parameters with single extruder MM printers")); + optgroup->append_single_option_line("filament_loading_speed_start"); + optgroup->append_single_option_line("filament_loading_speed"); + optgroup->append_single_option_line("filament_unloading_speed_start"); + optgroup->append_single_option_line("filament_unloading_speed"); + optgroup->append_single_option_line("filament_load_time"); + optgroup->append_single_option_line("filament_unload_time"); + optgroup->append_single_option_line("filament_toolchange_delay"); + optgroup->append_single_option_line("filament_cooling_moves"); + optgroup->append_single_option_line("filament_cooling_initial_speed"); + optgroup->append_single_option_line("filament_cooling_final_speed"); + + create_line_with_widget(optgroup.get(), "filament_ramming_parameters", "", [this](wxWindow* parent) { + auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + wxGetApp().UpdateDarkUI(ramming_dialog_btn); + ramming_dialog_btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + ramming_dialog_btn->SetSize(ramming_dialog_btn->GetBestSize()); + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(ramming_dialog_btn); + + ramming_dialog_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { + RammingDialog dlg(this,(m_config->option("filament_ramming_parameters"))->get_at(0)); + if (dlg.ShowModal() == wxID_OK) { + load_key_value("filament_ramming_parameters", dlg.get_parameters()); + update_changed_ui(); + } + }); + return sizer; + }); + + // Orca: multi tool is not supported yet. +#ifdef ORCA_MULTI_TOOL + optgroup = page->new_optgroup(L("Toolchange parameters with multi extruder MM printers")); + optgroup->append_single_option_line("filament_multitool_ramming"); + optgroup->append_single_option_line("filament_multitool_ramming_volume"); + optgroup->append_single_option_line("filament_multitool_ramming_flow"); +#endif + + page = add_options_page(L("Notes"), "note"); optgroup = page->new_optgroup(L("Notes"),"note", 0); optgroup->label_width = 0; option = optgroup->get_option("filament_notes"); @@ -2917,7 +2961,7 @@ void TabFilament::toggle_options() wxGetApp().preset_bundle->is_bbl_vendor(); } - if (m_active_page->title() == "Cooling") { + if (m_active_page->title() == L("Cooling")) { bool cooling = m_config->opt_bool("slow_down_for_layer_cooling", 0); toggle_option("slow_down_min_speed", cooling); @@ -2929,7 +2973,7 @@ void TabFilament::toggle_options() "additional_cooling_fan_speed", m_preset_bundle->printers.get_edited_preset().config.option("auxiliary_fan")->value); } - if (m_active_page->title() == "Filament") + if (m_active_page->title() == L("Filament")) { bool pa = m_config->opt_bool("enable_pressure_advance", 0); toggle_option("pressure_advance", pa); @@ -2939,8 +2983,17 @@ void TabFilament::toggle_options() toggle_line("textured_plate_temp_initial_layer", is_BBL_printer); toggle_option("chamber_temperature", !is_BBL_printer); } - if (m_active_page->title() == "Setting Overrides") + if (m_active_page->title() == L("Setting Overrides")) update_filament_overrides_page(); + + if (m_active_page->title() == L("Multimaterial")) { + // Orca: hide specific settings for BBL printers + for (auto el : + {"filament_minimal_purge_on_wipe_tower", "filament_loading_speed_start", "filament_loading_speed", + "filament_unloading_speed_start", "filament_unloading_speed", "filament_load_time", "filament_unload_time", + "filament_toolchange_delay", "filament_cooling_moves", "filament_cooling_initial_speed", "filament_cooling_final_speed"}) + toggle_option(el, !is_BBL_printer); + } } void TabFilament::update() @@ -3041,12 +3094,12 @@ void TabPrinter::build_fff() // optgroup->append_single_option_line("printable_area"); optgroup->append_single_option_line("printable_height"); optgroup->append_single_option_line("nozzle_volume"); - // BBS + #if 0 //optgroup->append_single_option_line("z_offset"); +#endif - //optgroup = page->new_optgroup(L("Capabilities")); - //ConfigOptionDef def; + // ConfigOptionDef def; // def.type = coInt, // def.set_default_value(new ConfigOptionInt(1)); // def.label = L("Extruders"); @@ -3055,87 +3108,8 @@ void TabPrinter::build_fff() // def.max = 256; // //BBS // def.mode = comDevelop; - //Option option(def, "extruders_count"); - //optgroup->append_single_option_line(option); - //optgroup->append_single_option_line("single_extruder_multi_material"); - - //optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value) { - // // optgroup->get_value() return int for def.type == coInt, - // // Thus, there should be boost::any_cast ! - // // Otherwise, boost::any_cast causes an "unhandled unknown exception" - // size_t extruders_count = size_t(boost::any_cast(optgroup->get_value("extruders_count"))); - // wxTheApp->CallAfter([this, opt_key, value, extruders_count]() { - // if (opt_key == "extruders_count" || opt_key == "single_extruder_multi_material") { - // extruders_count_changed(extruders_count); - // init_options_list(); // m_options_list should be updated before UI updating - // update_dirty(); - // if (opt_key == "single_extruder_multi_material") { // the single_extruder_multimaterial was added to force pages - // on_value_change(opt_key, value); // rebuild - let's make sure the on_value_change is not skipped - - // if (boost::any_cast(value) && m_extruders_count > 1) { - // SuppressBackgroundProcessingUpdate sbpu; - // std::vector nozzle_diameters = static_cast(m_config->option("nozzle_diameter"))->values; - // const double frst_diam = nozzle_diameters[0]; - - // for (auto cur_diam : nozzle_diameters) { - // // if value is differs from first nozzle diameter value - // if (fabs(cur_diam - frst_diam) > EPSILON) { - // const wxString msg_text = _(L("Single Extruder Multi Material is selected, \n" - // "and all extruders must have the same diameter.\n" - // "Do you want to change the diameter for all extruders to first extruder nozzle diameter value?")); - // //wxMessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); - // MessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); - - // DynamicPrintConfig new_conf = *m_config; - // if (dialog.ShowModal() == wxID_YES) { - // for (size_t i = 1; i < nozzle_diameters.size(); i++) - // nozzle_diameters[i] = frst_diam; - - // new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters)); - // } - // else - // new_conf.set_key_value("single_extruder_multi_material", new ConfigOptionBool(false)); - - // load_config(new_conf); - // break; - // } - // } - // } - // } - // } - // else { - // update_dirty(); - // on_value_change(opt_key, value); - // } - // }); - //}; - - //optgroup = page->new_optgroup(L("Firmware")); - - //optgroup->append_single_option_line("silent_mode"); - - //optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value) { - // wxTheApp->CallAfter([this, opt_key, value]() { - // if (opt_key == "silent_mode") { - // bool val = boost::any_cast(value); - // if (m_use_silent_mode != val) { - // m_rebuild_kinematics_page = true; - // m_use_silent_mode = val; - // } - // } - // if (opt_key == "gcode_flavor") { - // bool supports_travel_acceleration = (boost::any_cast(value) == int(gcfMarlinFirmware)); - // if (supports_travel_acceleration != m_supports_travel_acceleration) { - // m_rebuild_kinematics_page = true; - // m_supports_travel_acceleration = supports_travel_acceleration; - // } - // } - // build_unregular_pages(); - // update_dirty(); - // on_value_change(opt_key, value); - // }); - //}; -#endif + // Option option(def, "extruders_count"); + // optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); optgroup->append_single_option_line("gcode_flavor"); @@ -3452,35 +3426,31 @@ void TabPrinter::build_unregular_pages(bool from_initial_build/* = false*/) n_before_extruders++; size_t n_after_single_extruder_MM = 2; // Count of pages after single_extruder_multi_material page - //if (m_extruders_count_old == m_extruders_count || - // (m_has_single_extruder_MM_page && m_extruders_count == 1)) - //{ - // // if we have a single extruder MM setup, add a page with configuration options: - // for (size_t i = 0; i < m_pages.size(); ++i) // first make sure it's not there already - // if (m_pages[i]->title().find(L("Single extruder MM setup")) != std::string::npos) { - // m_pages.erase(m_pages.begin() + i); - // break; - // } - // m_has_single_extruder_MM_page = false; - //} + if (from_initial_build) { + // create a page, but pretend it's an extruder page, so we can add it to m_pages ourselves + auto page = add_options_page(L("Multimaterial"), "printer", true); + auto optgroup = page->new_optgroup(L("Single extruder multimaterial setup")); + optgroup->append_single_option_line("single_extruder_multi_material"); + optgroup->m_on_change = [this, optgroup](const t_config_option_key &opt_key, const boost::any &value) { + wxTheApp->CallAfter([this, opt_key, value]() { + if (opt_key == "single_extruder_multi_material") { + build_unregular_pages(); + } + }); + }; + optgroup = page->new_optgroup(L("Wipe tower")); + optgroup->append_single_option_line("purge_in_prime_tower"); + optgroup->append_single_option_line("enable_filament_ramming"); - //BBS: please add our single extruder multimaterial parameters here. Currently - //comment this part because we have no such config in this page. -#if 0 - //if (from_initial_build || - // (m_extruders_count > 1 && m_config->opt_bool("single_extruder_multi_material") && !m_has_single_extruder_MM_page)) { - // // create a page, but pretend it's an extruder page, so we can add it to m_pages ourselves - // auto page = add_options_page(L("Single extruder MM setup"), "printer", true); - // auto optgroup = page->new_optgroup(L("Single extruder multimaterial parameters")); - // - // if (from_initial_build) - // page->clear(); - // else { - // m_pages.insert(m_pages.end() - n_after_single_extruder_MM, page); - // m_has_single_extruder_MM_page = true; - // } - //} -#endif + + optgroup = page->new_optgroup(L("Single extruder multimaterial parameters")); + optgroup->append_single_option_line("cooling_tube_retraction"); + optgroup->append_single_option_line("cooling_tube_length"); + optgroup->append_single_option_line("parking_pos_retraction"); + optgroup->append_single_option_line("extra_loading_move"); + optgroup->append_single_option_line("high_current_on_filament_swap"); + m_pages.insert(m_pages.end() - n_after_single_extruder_MM, page); + } // BBS. Just create one extruder page because BBL machine has only on physical extruder. // Build missed extruder pages @@ -3640,6 +3610,7 @@ void TabPrinter::on_preset_loaded() // update the GUI field according to the number of nozzle diameters supplied extruders_count_changed(extruders_count); #endif + build_unregular_pages(); } void TabPrinter::update_pages() @@ -3722,8 +3693,7 @@ void TabPrinter::toggle_options() //if (m_active_page->title() == "Custom G-code") { // toggle_option("change_filament_gcode", have_multiple_extruders); //} - if (m_active_page->title() == "Basic information") { - toggle_option("single_extruder_multi_material", have_multiple_extruders); + if (m_active_page->title() == L("Basic information")) { // SoftFever: hide BBL specific settings for (auto el : @@ -3735,9 +3705,18 @@ void TabPrinter::toggle_options() toggle_line(el, !is_BBL_printer); } + if (m_active_page->title() == L("Multimaterial")) { + // toggle_option("single_extruder_multi_material", have_multiple_extruders); + + // SoftFever: hide specific settings for BBL printer + for (auto el : + {"purge_in_prime_tower", "enable_filament_ramming", "cooling_tube_retraction", "cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "high_current_on_filament_swap", }) + toggle_option(el, !is_BBL_printer); + + } wxString extruder_number; long val = 1; - if ( m_active_page->title().IsSameAs("Extruder") || + if ( m_active_page->title().IsSameAs(L("Extruder")) || (m_active_page->title().StartsWith("Extruder ", &extruder_number) && extruder_number.ToLong(&val) && val > 0 && (size_t)val <= m_extruders_count)) { @@ -3804,7 +3783,7 @@ void TabPrinter::toggle_options() toggle_option("retract_restart_extra_toolchange", have_multiple_extruders && toolchange_retraction, i); } - if (m_active_page->title() == "Motion ability") { + if (m_active_page->title() == L("Motion ability")) { auto gcf = m_config->option>("gcode_flavor")->value; assert(gcf == gcfMarlinLegacy || gcf == gcfMarlinFirmware || gcf == gcfKlipper); bool silent_mode = m_config->opt_bool("silent_mode"); diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 551eabd829..586573f181 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -547,7 +547,6 @@ public: class TabPrinter : public Tab { private: - bool m_has_single_extruder_MM_page = false; bool m_use_silent_mode = false; void append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key); bool m_rebuild_kinematics_page = false; diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index aa50d06b29..b407c56920 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -35,11 +35,163 @@ static const wxColour g_text_color = wxColour(107, 107, 107, 255); #define MAX_FLUSH_VALUE 999 #define MIN_WIPING_DIALOG_WIDTH FromDIP(400) + static void update_ui(wxWindow* window) { Slic3r::GUI::wxGetApp().UpdateDarkUI(window); } +RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) +: wxDialog(parent, wxID_ANY, _(L("Ramming customization")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/) +{ + update_ui(this); + m_panel_ramming = new RammingPanel(this,parameters); + + // Not found another way of getting the background colours of RammingDialog, RammingPanel and Chart correct than setting + // them all explicitely. Reading the parent colour yielded colour that didn't really match it, no wxSYS_COLOUR_... matched + // colour used for the dialog. Same issue (and "solution") here : https://forums.wxwidgets.org/viewtopic.php?f=1&t=39608 + // Whoever can fix this, feel free to do so. +#ifndef _WIN32 + this-> SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK)); + m_panel_ramming->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK)); +#endif + m_panel_ramming->Show(true); + this->Show(); + + auto main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(m_panel_ramming, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5); + main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBOTTOM, 10); + SetSizer(main_sizer); + main_sizer->SetSizeHints(this); + + update_ui(static_cast(this->FindWindowById(wxID_OK, this))); + update_ui(static_cast(this->FindWindowById(wxID_CANCEL, this))); + + this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); }); + + this->Bind(wxEVT_BUTTON,[this](wxCommandEvent&) { + m_output_data = m_panel_ramming->get_parameters(); + EndModal(wxID_OK); + },wxID_OK); + this->Show(); +// wxMessageDialog dlg(this, _(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to " + Slic3r::GUI::MessageDialog dlg(this, _(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to " + "properly shape the end of the unloaded filament so it does not prevent insertion of the new filament and can itself " + "be reinserted later. This phase is important and different materials can require different extrusion speeds to get " + "the good shape. For this reason, the extrusion rates during ramming are adjustable.\n\nThis is an expert-level " + "setting, incorrect adjustment will likely lead to jams, extruder wheel grinding into filament etc.")), _(L("Warning")), wxOK | wxICON_EXCLAMATION);// .ShowModal(); + dlg.ShowModal(); +} + + +#ifdef _WIN32 +#define style wxSP_ARROW_KEYS | wxBORDER_SIMPLE +#else +#define style wxSP_ARROW_KEYS +#endif + + + +RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) +: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxPoint(50,50), wxSize(800,350),wxBORDER_RAISED*/) +{ + update_ui(this); + auto sizer_chart = new wxBoxSizer(wxVERTICAL); + auto sizer_param = new wxBoxSizer(wxVERTICAL); + + std::stringstream stream{ parameters }; + stream >> m_ramming_line_width_multiplicator >> m_ramming_step_multiplicator; + int ramming_speed_size = 0; + float dummy = 0.f; + while (stream >> dummy) + ++ramming_speed_size; + stream.clear(); + stream.get(); + + std::vector> buttons; + float x = 0.f; + float y = 0.f; + while (stream >> x >> y) + buttons.push_back(std::make_pair(x, y)); + + m_chart = new Chart(this, wxRect(scale(1),scale(1),scale(48),scale(36)), buttons, ramming_speed_size, 0.25f, scale(1)); +#ifdef _WIN32 + update_ui(m_chart); +#else + m_chart->SetBackgroundColour(parent->GetBackgroundColour()); // see comment in RammingDialog constructor +#endif + sizer_chart->Add(m_chart, 0, wxALL, 5); + + m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,0.,5.0,3.,0.5); + m_widget_volume = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,0,10000,0); + m_widget_ramming_line_width_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); + m_widget_ramming_step_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); + +#ifdef _WIN32 + update_ui(m_widget_time->GetText()); + update_ui(m_widget_volume); + update_ui(m_widget_ramming_line_width_multiplicator); + update_ui(m_widget_ramming_step_multiplicator); +#endif + + auto gsizer_param = new wxFlexGridSizer(2, 5, 15); + gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total ramming time")) + " (" + _(L("s")) + "):")), 0, wxALIGN_CENTER_VERTICAL); + gsizer_param->Add(m_widget_time); + gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total rammed volume")) + " (" + _(L("mm")) + wxString("³):", wxConvUTF8))), 0, wxALIGN_CENTER_VERTICAL); + gsizer_param->Add(m_widget_volume); + gsizer_param->AddSpacer(20); + gsizer_param->AddSpacer(20); + gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Ramming line width")) + " (%):")), 0, wxALIGN_CENTER_VERTICAL); + gsizer_param->Add(m_widget_ramming_line_width_multiplicator); + gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Ramming line spacing")) + " (%):")), 0, wxALIGN_CENTER_VERTICAL); + gsizer_param->Add(m_widget_ramming_step_multiplicator); + + sizer_param->Add(gsizer_param, 0, wxTOP, scale(10)); + + m_widget_time->SetValue(m_chart->get_time()); + m_widget_time->SetDigits(2); + m_widget_volume->SetValue(m_chart->get_volume()); + m_widget_volume->Disable(); + m_widget_ramming_line_width_multiplicator->SetValue(m_ramming_line_width_multiplicator); + m_widget_ramming_step_multiplicator->SetValue(m_ramming_step_multiplicator); + + m_widget_ramming_step_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); }); + m_widget_ramming_line_width_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); }); + + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(sizer_chart, 0, wxALL, 5); + sizer->Add(sizer_param, 0, wxALL, 10); + + sizer->SetSizeHints(this); + SetSizer(sizer); + + m_widget_time->Bind(wxEVT_TEXT,[this](wxCommandEvent&) {m_chart->set_xy_range(m_widget_time->GetValue(),-1);}); + m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value + m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value + Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} ); + Refresh(true); // erase background +} + +void RammingPanel::line_parameters_changed() { + m_ramming_line_width_multiplicator = m_widget_ramming_line_width_multiplicator->GetValue(); + m_ramming_step_multiplicator = m_widget_ramming_step_multiplicator->GetValue(); +} + +std::string RammingPanel::get_parameters() +{ + std::vector speeds = m_chart->get_ramming_speed(0.25f); + std::vector> buttons = m_chart->get_buttons(); + std::stringstream stream; + stream << m_ramming_line_width_multiplicator << " " << m_ramming_step_multiplicator; + for (const float& speed_value : speeds) + stream << " " << speed_value; + stream << "|"; + for (const auto& button : buttons) + stream << " " << button.first << " " << button.second; + return stream.str(); +} + + #ifdef _WIN32 #define style wxSP_ARROW_KEYS | wxBORDER_SIMPLE #else @@ -233,7 +385,7 @@ void WipingPanel::create_panels(wxWindow* parent, const int num) { sizer->AddSpacer(ROW_BEG_PADDING); sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, ROW_VERT_PADDING); - for (unsigned int j = 0; j < num; ++j) { + for (int j = 0; j < num; ++j) { edit_boxes[j][i]->Reparent(panel); edit_boxes[j][i]->SetBackgroundColour(panel->GetBackgroundColour()); sizer->AddSpacer(EDIT_BOXES_GAP); diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index 91f7612ec0..4d038d378d 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -9,8 +9,38 @@ #include #include +#include "RammingChart.hpp" class Button; + +class RammingPanel : public wxPanel { +public: + RammingPanel(wxWindow* parent); + RammingPanel(wxWindow* parent,const std::string& data); + std::string get_parameters(); + +private: + Chart* m_chart = nullptr; + wxSpinCtrl* m_widget_volume = nullptr; + wxSpinCtrl* m_widget_ramming_line_width_multiplicator = nullptr; + wxSpinCtrl* m_widget_ramming_step_multiplicator = nullptr; + wxSpinCtrlDouble* m_widget_time = nullptr; + int m_ramming_step_multiplicator; + int m_ramming_line_width_multiplicator; + + void line_parameters_changed(); +}; + + +class RammingDialog : public wxDialog { +public: + RammingDialog(wxWindow* parent,const std::string& parameters); + std::string get_parameters() { return m_output_data; } +private: + RammingPanel* m_panel_ramming = nullptr; + std::string m_output_data; +}; + class WipingPanel : public wxPanel { public: // BBS