Merge branch 'main' into enh-spoolman-support

This commit is contained in:
Ocraftyone 2025-12-23 16:57:57 -05:00 committed by GitHub
commit 9c484f2372
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
74 changed files with 790 additions and 245 deletions

View file

@ -10,5 +10,8 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "45",
"initial_layer_speed": "25",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25",
"gap_infill_speed": "45",
"small_perimeter_speed": "45",
"outer_wall_speed": "45"
}

View file

@ -10,5 +10,8 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "45",
"initial_layer_speed": "25",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25",
"gap_infill_speed": "45",
"small_perimeter_speed": "45",
"outer_wall_speed": "45"
}

View file

@ -13,5 +13,8 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "100",
"initial_layer_speed": "45",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.4"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.4",
"small_perimeter_speed": "145",
"inner_wall_speed": "145",
"outer_wall_speed": "145"
}

View file

@ -4,9 +4,9 @@
"inherits": "0.10mm STRUCTURAL @MK4S 0.5",
"from": "system",
"instantiation": "true",
"inner_wall_speed": "80",
"small_perimeter_speed": "45",
"outer_wall_speed": "45",
"inner_wall_speed": "70",
"small_perimeter_speed": "50",
"outer_wall_speed": "50",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -10,5 +10,8 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "45",
"initial_layer_speed": "25",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25",
"small_perimeter_speed": "150",
"outer_wall_speed": "150",
"inner_wall_speed": "150"
}

View file

@ -10,5 +10,8 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "45",
"initial_layer_speed": "25",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25",
"gap_infill_speed": "45",
"small_perimeter_speed": "45",
"outer_wall_speed": "45"
}

View file

@ -12,5 +12,8 @@
"initial_layer_infill_speed": "60",
"initial_layer_speed": "45",
"top_surface_acceleration": "1500",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3",
"small_perimeter_speed": "45",
"inner_wall_speed": "70",
"outer_wall_speed": "45"
}

View file

@ -10,5 +10,8 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "45",
"initial_layer_speed": "25",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25",
"small_perimeter_speed": "150",
"inner_wall_speed": "150",
"outer_wall_speed": "150"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.15mm SPEED @MK4S 0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
@ -16,5 +16,6 @@
"internal_solid_infill_acceleration": "6000",
"inner_wall_acceleration": "6000",
"outer_wall_acceleration": "3000",
"top_surface_acceleration": "2000"
"top_surface_acceleration": "2000",
"support_threshold_angle": "35"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.15mm SPEED @MK4S HF0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_1_4_speed": "50",
"overhang_3_4_speed": "60%",
"sparse_infill_speed": "300",
"travel_speed": "350",
@ -18,5 +18,6 @@
"internal_solid_infill_acceleration": "6000",
"inner_wall_acceleration": "6000",
"outer_wall_acceleration": "3000",
"top_surface_acceleration": "2000"
"top_surface_acceleration": "2000",
"support_threshold_angle": "35"
}

View file

@ -10,5 +10,8 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "45",
"initial_layer_speed": "25",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.25",
"gap_infill_speed": "45",
"small_perimeter_speed": "45",
"outer_wall_speed": "45"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.15mm STRUCTURAL @MK4S 0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"overhang_3_4_speed": "45",
"sparse_infill_speed": "120",
"travel_speed": "350",
"travel_acceleration": "7000",

View file

@ -4,7 +4,7 @@
"inherits": "0.15mm STRUCTURAL @MK4S 0.5",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"overhang_3_4_speed": "45",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,9 +4,9 @@
"inherits": "0.15mm STRUCTURAL @MK4S 0.6",
"from": "system",
"instantiation": "true",
"inner_wall_speed": "80",
"overhang_2_4_speed": "30",
"overhang_3_4_speed": "70%",
"inner_wall_speed": "70",
"overhang_3_4_speed": "30",
"overhang_4_4_speed": "70%",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
@ -18,5 +18,6 @@
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.6",
"inner_wall_acceleration": "2500",
"outer_wall_acceleration": "1500",
"top_surface_acceleration": "2000"
"top_surface_acceleration": "2000",
"gap_infill_speed": "70"
}

View file

@ -13,5 +13,8 @@
"initial_layer_infill_speed": "60",
"initial_layer_speed": "45",
"top_surface_acceleration": "1500",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3",
"small_perimeter_speed": "160",
"inner_wall_speed": "160",
"outer_wall_speed": "160"
}

View file

@ -12,5 +12,8 @@
"initial_layer_infill_speed": "60",
"initial_layer_speed": "45",
"top_surface_acceleration": "1500",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3",
"small_perimeter_speed": "50",
"inner_wall_speed": "70",
"outer_wall_speed": "50"
}

View file

@ -4,12 +4,15 @@
"inherits": "0.20mm SOLUBLE FULL @MK4S 0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.4 and printer_notes!~/.*HF_NOZZLE.*/",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "100",
"initial_layer_speed": "45"
"initial_layer_speed": "45",
"small_perimeter_speed": "50",
"inner_wall_speed": "70",
"outer_wall_speed": "50"
}

View file

@ -4,12 +4,15 @@
"inherits": "0.20mm SOLUBLE INTERFACE @MK4S 0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.4 and printer_notes!~/.*HF_NOZZLE.*/",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "100",
"initial_layer_speed": "45"
"initial_layer_speed": "45",
"small_perimeter_speed": "50",
"inner_wall_speed": "70",
"outer_wall_speed": "50"
}

View file

@ -13,5 +13,8 @@
"initial_layer_infill_speed": "60",
"initial_layer_speed": "45",
"top_surface_acceleration": "1500",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3",
"small_perimeter_speed": "160",
"inner_wall_speed": "160",
"outer_wall_speed": "160"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.20mm SPEED @MK4S 0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
@ -16,5 +16,6 @@
"internal_solid_infill_acceleration": "6000",
"inner_wall_acceleration": "6000",
"outer_wall_acceleration": "3000",
"top_surface_acceleration": "2000"
"top_surface_acceleration": "2000",
"support_threshold_angle": "35"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.20mm SPEED @MK4S 0.5",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,8 +4,8 @@
"inherits": "0.20mm SPEED @MK4S 0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "30",
"overhang_3_4_speed": "70%",
"overhang_3_4_speed": "30",
"overhang_4_4_speed": "70%",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
@ -17,5 +17,8 @@
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.6 and printer_notes!~/.*HF_NOZZLE.*/",
"inner_wall_acceleration": "6000",
"outer_wall_acceleration": "3000",
"top_surface_acceleration": "2000"
"top_surface_acceleration": "2000",
"small_perimeter_speed": "130",
"inner_wall_speed": "130",
"outer_wall_speed": "130"
}

View file

@ -4,8 +4,8 @@
"inherits": "0.20mm SPEED @MK4S HF0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "60%",
"overhang_3_4_speed": "50",
"overhang_4_4_speed": "70%",
"sparse_infill_speed": "300",
"travel_speed": "350",
"travel_acceleration": "7000",
@ -18,5 +18,6 @@
"internal_solid_infill_acceleration": "6000",
"inner_wall_acceleration": "6000",
"outer_wall_acceleration": "3000",
"top_surface_acceleration": "2000"
"top_surface_acceleration": "2000",
"support_threshold_angle": "35"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.20mm SPEED @MK4S HF0.5",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,8 +4,8 @@
"inherits": "0.20mm SPEED @MK4S HF0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "30",
"overhang_3_4_speed": "70%",
"overhang_3_4_speed": "30",
"overhang_4_4_speed": "70%",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -12,5 +12,8 @@
"initial_layer_infill_speed": "60",
"initial_layer_speed": "45",
"top_surface_acceleration": "1500",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.3",
"small_perimeter_speed": "50",
"inner_wall_speed": "70",
"outer_wall_speed": "50"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.20mm STRUCTURAL @MK4S 0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"overhang_3_4_speed": "45",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,7 +4,7 @@
"inherits": "0.20mm STRUCTURAL @MK4S 0.5",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"overhang_3_4_speed": "45",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,7 +4,7 @@
"inherits": "0.20mm STRUCTURAL @MK4S 0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "30",
"overhang_3_4_speed": "30",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,7 +4,7 @@
"inherits": "0.25mm SPEED @MK4S 0.5",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,8 +4,8 @@
"inherits": "0.25mm SPEED @MK4S 0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "30",
"overhang_3_4_speed": "70%",
"overhang_3_4_speed": "30",
"overhang_4_4_speed": "70%",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
@ -17,5 +17,8 @@
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.6 and printer_notes!~/.*HF_NOZZLE.*/",
"inner_wall_acceleration": "6000",
"outer_wall_acceleration": "3000",
"top_surface_acceleration": "2000"
"top_surface_acceleration": "2000",
"small_perimeter_speed": "75",
"inner_wall_speed": "95",
"outer_wall_speed": "75"
}

View file

@ -4,8 +4,8 @@
"inherits": "0.25mm SPEED @MK4S HF0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "60%",
"overhang_3_4_speed": "50",
"overhang_4_4_speed": "70%",
"sparse_infill_speed": "300",
"travel_speed": "350",
"travel_acceleration": "7000",
@ -13,10 +13,11 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "100",
"initial_layer_speed": "45",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*HF_NOZZLE.*/",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.4 and printer_notes=~/.*HF_NOZZLE.*/",
"sparse_infill_acceleration": "7000",
"internal_solid_infill_acceleration": "6000",
"inner_wall_acceleration": "6000",
"outer_wall_acceleration": "3000",
"top_surface_acceleration": "2000"
"top_surface_acceleration": "2000",
"support_threshold_angle": "35"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.25mm SPEED @MK4S HF0.5",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,8 +4,8 @@
"inherits": "0.25mm SPEED @MK4S HF0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "30",
"overhang_3_4_speed": "70%",
"overhang_3_4_speed": "30",
"overhang_4_4_speed": "70%",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,7 +4,7 @@
"inherits": "0.25mm STRUCTURAL @MK4S 0.5",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"overhang_3_4_speed": "45",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,7 +4,7 @@
"inherits": "0.25mm STRUCTURAL @MK4S 0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "30",
"overhang_3_4_speed": "30",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,7 +4,7 @@
"inherits": "0.25mm STRUCTURAL @MK4S HF0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"overhang_3_4_speed": "45",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,7 +4,7 @@
"inherits": "0.28mm DRAFT @MK4S HF0.4",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"support_threshold_angle": "35",
"outer_wall_acceleration": "3000",
"inner_wall_acceleration": "6000",

View file

@ -4,8 +4,8 @@
"inherits": "0.30mm DETAIL @MK4S 0.8",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "35",
"top_surface_speed": "2000",
"overhang_3_4_speed": "35",
"top_surface_acceleration": "2000",
"inner_wall_acceleration": "2500",
"internal_solid_infill_acceleration": "5000",
"sparse_infill_acceleration": "7000",
@ -15,5 +15,6 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "55",
"initial_layer_speed": "45",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.8 and printer_notes!~/.*HF_NOZZLE.*/"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.8 and printer_notes!~/.*HF_NOZZLE.*/",
"gap_infill_speed": "45"
}

View file

@ -4,8 +4,8 @@
"inherits": "0.30mm SPEED @MK4S HF0.8",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"top_surface_speed": "2000",
"overhang_3_4_speed": "45",
"top_surface_acceleration": "2000",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,8 +4,8 @@
"inherits": "0.30mm STRUCTURAL @MK4S HF0.8",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "40",
"top_surface_speed": "2000",
"overhang_3_4_speed": "40",
"top_surface_acceleration": "2000",
"support_speed": "100",
"support_interface_speed": "55%",
"travel_speed": "350",
@ -18,6 +18,5 @@
"sparse_infill_acceleration": "6000",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.8 and printer_notes=~/.*HF_NOZZLE.*/",
"inner_wall_acceleration": "2500",
"outer_wall_acceleration": "1500",
"top_surface_acceleration": "2000"
"outer_wall_acceleration": "1500"
}

View file

@ -4,8 +4,8 @@
"inherits": "0.32mm SPEED @MK4S 0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "30",
"overhang_3_4_speed": "70%",
"overhang_3_4_speed": "30",
"overhang_4_4_speed": "70%",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,7 +4,7 @@
"inherits": "0.32mm SPEED @MK4S HF0.5",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "50",
"support_interface_speed": "50%",
"travel_speed": "350",
"travel_acceleration": "7000",

View file

@ -4,9 +4,9 @@
"inherits": "0.32mm SPEED @MK4S HF0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "35",
"overhang_3_4_speed": "70%",
"top_surface_speed": "2000",
"overhang_3_4_speed": "35",
"overhang_4_4_speed": "70%",
"top_surface_acceleration": "2000",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
@ -17,6 +17,5 @@
"sparse_infill_acceleration": "7000",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*HF_NOZZLE.*/",
"inner_wall_acceleration": "6000",
"outer_wall_acceleration": "3000",
"top_surface_acceleration": "2000"
"outer_wall_acceleration": "3000"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.32mm STRUCTURAL @MK4S 0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "30",
"overhang_3_4_speed": "30",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,7 +4,7 @@
"inherits": "0.32mm STRUCTURAL @MK4S HF0.5",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"overhang_3_4_speed": "45",
"support_speed": "120",
"support_interface_speed": "50%",
"travel_speed": "350",

View file

@ -4,7 +4,7 @@
"inherits": "0.32mm STRUCTURAL @MK4S HF0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "35",
"overhang_3_4_speed": "35",
"support_speed": "110",
"support_interface_speed": "50%",
"travel_speed": "350",

View file

@ -4,8 +4,8 @@
"inherits": "0.40mm QUALITY @MK4S 0.8",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "35",
"top_surface_speed": "2000",
"overhang_3_4_speed": "35",
"top_surface_acceleration": "2000",
"inner_wall_acceleration": "2500",
"internal_solid_infill_acceleration": "5000",
"sparse_infill_acceleration": "7000",

View file

@ -4,9 +4,9 @@
"inherits": "0.40mm SPEED @MK4S HF0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "35",
"overhang_3_4_speed": "70%",
"top_surface_speed": "2000",
"overhang_3_4_speed": "35",
"overhang_4_4_speed": "70%",
"top_surface_acceleration": "2000",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
@ -17,6 +17,5 @@
"sparse_infill_acceleration": "7000",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.6 and printer_notes=~/.*HF_NOZZLE.*/",
"inner_wall_acceleration": "6000",
"outer_wall_acceleration": "3000",
"top_surface_acceleration": "2000"
"outer_wall_acceleration": "3000"
}

View file

@ -4,8 +4,8 @@
"inherits": "0.40mm SPEED @MK4S HF0.8",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"top_surface_speed": "2000",
"overhang_3_4_speed": "45",
"top_surface_acceleration": "2000",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
@ -14,5 +14,7 @@
"initial_layer_speed": "45",
"internal_solid_infill_acceleration": "5000",
"sparse_infill_acceleration": "7000",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.8 and printer_notes=~/.*HF_NOZZLE.*/"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.8 and printer_notes=~/.*HF_NOZZLE.*/",
"small_perimeter_speed": "85",
"outer_wall_speed": "85"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.40mm STRUCTURAL @MK4S HF0.6",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "35",
"overhang_3_4_speed": "35",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -4,8 +4,8 @@
"inherits": "0.40mm STRUCTURAL @MK4S HF0.8",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "40",
"top_surface_speed": "2000",
"overhang_3_4_speed": "40",
"top_surface_acceleration": "2000",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",
@ -16,6 +16,5 @@
"sparse_infill_acceleration": "6000",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.8 and printer_notes=~/.*HF_NOZZLE.*/",
"inner_wall_acceleration": "2500",
"outer_wall_acceleration": "1500",
"top_surface_acceleration": "2000"
"outer_wall_acceleration": "1500"
}

View file

@ -4,7 +4,7 @@
"inherits": "0.55mm DRAFT @MK4S 0.8",
"from": "system",
"instantiation": "true",
"top_surface_speed": "2000",
"top_surface_acceleration": "2000",
"inner_wall_acceleration": "2500",
"internal_solid_infill_acceleration": "5000",
"sparse_infill_acceleration": "7000",
@ -14,5 +14,6 @@
"support_interface_top_layers": "3",
"initial_layer_infill_speed": "55",
"initial_layer_speed": "45",
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.8 and printer_notes!~/.*HF_NOZZLE.*/"
"compatible_printers_condition": "printer_notes=~/.*PRINTER_MODEL_COREONE.*/ and nozzle_diameter[0]==0.8 and printer_notes!~/.*HF_NOZZLE.*/",
"inner_wall_speed": "45"
}

View file

@ -4,8 +4,8 @@
"inherits": "0.55mm SPEED @MK4S HF0.8",
"from": "system",
"instantiation": "true",
"overhang_2_4_speed": "45",
"top_surface_speed": "2000",
"overhang_3_4_speed": "45",
"top_surface_acceleration": "2000",
"travel_speed": "350",
"travel_acceleration": "7000",
"default_acceleration": "3000",

View file

@ -9,4 +9,4 @@ ROOT_DIR="$(dirname "$0")/.."
cd "${ROOT_DIR}" || exit 1
ctest --test-dir build/tests --output-junit "$(pwd)/ctest_results.xml" --output-on-failure -j
ctest --test-dir build/tests -L "Http|PlaceholderParser" --output-junit "$(pwd)/ctest_results.xml" --output-on-failure -j

View file

@ -35,6 +35,11 @@ Clipper2Lib::Paths64 Slic3rPoints_to_Paths64(const Container& in)
return out;
}
Clipper2Lib::Paths64 Slic3rPolylines_to_Paths64(const Polylines& in)
{
return Slic3rPoints_to_Paths64(in);
}
Points Path64ToPoints(const Clipper2Lib::Path64& path64)
{
Points points;

View file

@ -4,9 +4,12 @@
#include "ExPolygon.hpp"
#include "Polygon.hpp"
#include "Polyline.hpp"
#include "clipper2/clipper.h"
namespace Slic3r {
Clipper2Lib::Paths64 Slic3rPolylines_to_Paths64(const Slic3r::Polylines& in);
Slic3r::Polylines Paths64_to_polylines(const Clipper2Lib::Paths64& in);
Slic3r::Polylines intersection_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip);
Slic3r::Polylines diff_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip);
ExPolygons union_ex_2(const Polygons &expolygons);

View file

@ -200,6 +200,10 @@ void Fill3DHoneycomb::_fill_surface_single(
if (std::abs(infill_angle) >= EPSILON) expolygon.rotate(-infill_angle);
BoundingBox bb = expolygon.contour.bounding_box();
// Expand the bounding box to avoid artifacts at the edges
coord_t expand = 5 * (scale_(this->spacing));
bb.offset(expand);
// Note: with equally-scaled X/Y/Z, the pattern will create a vertically-stretched
// truncated octahedron; so Z is pre-adjusted first by scaling by sqrt(2)
coordf_t zScale = sqrt(2);

View file

@ -1371,42 +1371,47 @@ void Filler::_fill_surface_single(
all_polylines.reserve(lines.size());
std::transform(lines.begin(), lines.end(), std::back_inserter(all_polylines), [](const Line& l) { return Polyline{ l.a, l.b }; });
// Apply multiline offset if needed
multiline_fill(all_polylines, params, spacing);
// Apply multiline offset if needed
multiline_fill(all_polylines, params, spacing);
// Crop all polylines
all_polylines = intersection_pl(std::move(all_polylines), expolygon);
#endif
}
// After intersection_pl some polylines with only one line are split into more lines
for (Polyline &polyline : all_polylines) {
//FIXME assert that all the points are collinear and in between the start and end point.
if (polyline.points.size() > 2)
polyline.points.erase(polyline.points.begin() + 1, polyline.points.end() - 1);
}
// assert(has_no_collinear_lines(all_polylines));
if (params.multiline == 1) {
// After intersection_pl some polylines with only one line are split into more lines
for (Polyline& polyline : all_polylines) {
// FIXME assert that all the points are collinear and in between the start and end point.
if (polyline.points.size() > 2)
polyline.points.erase(polyline.points.begin() + 1, polyline.points.end() - 1);
}
// assert(has_no_collinear_lines(all_polylines));
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
{
static int iRun = 0;
export_infill_lines_to_svg(expolygon, all_polylines, debug_out_path("FillAdaptive-initial-%d.svg", iRun++));
}
{
static int iRun = 0;
export_infill_lines_to_svg(expolygon, all_polylines, debug_out_path("FillAdaptive-initial-%d.svg", iRun++));
}
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
const auto hook_length = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length)));
const auto hook_length_max = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length_max)));
const auto hook_length = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length)));
const auto hook_length_max = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length_max)));
Polylines all_polylines_with_hooks = all_polylines.size() > 1 ? connect_lines_using_hooks(std::move(all_polylines), expolygon, this->spacing, hook_length, hook_length_max) : std::move(all_polylines);
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
{
static int iRun = 0;
export_infill_lines_to_svg(expolygon, all_polylines_with_hooks, debug_out_path("FillAdaptive-hooks-%d.svg", iRun++));
}
{
static int iRun = 0;
export_infill_lines_to_svg(expolygon, all_polylines_with_hooks, debug_out_path("FillAdaptive-hooks-%d.svg", iRun++));
}
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
chain_or_connect_infill(std::move(all_polylines_with_hooks), expolygon, polylines_out, this->spacing, params);
chain_or_connect_infill(std::move(all_polylines_with_hooks), expolygon, polylines_out, this->spacing, params);
} else {
// if multiline is > 1 infill is ready to connect
chain_or_connect_infill(std::move(all_polylines), expolygon, polylines_out, this->spacing, params);
}
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
{

View file

@ -3,6 +3,7 @@
#include <cmath>
#include "../ClipperUtils.hpp"
#include "../Clipper2Utils.hpp"
#include "../EdgeGrid.hpp"
#include "../Geometry.hpp"
#include "../Geometry/Circle.hpp"
@ -2699,60 +2700,77 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const Polygons &boun
connect_base_support(std::move(infill_ordered), polygons_src, bbox, polylines_out, spacing, params);
}
//Fill Multiline
// Fill Multiline -Clipper2 version
void multiline_fill(Polylines& polylines, const FillParams& params, float spacing)
{
if (params.multiline > 1) {
const int n_lines = params.multiline;
const int n_polylines = static_cast<int>(polylines.size());
Polylines all_polylines;
all_polylines.reserve(n_lines * n_polylines);
if (params.multiline <= 1)
return;
const float center = (n_lines - 1) / 2.0f;
const int n_lines = params.multiline;
const int n_polylines = static_cast<int>(polylines.size());
Polylines all_polylines;
all_polylines.reserve(n_lines * n_polylines);
for (int line = 0; line < n_lines; ++line) {
float offset = scale_((static_cast<float>(line) - center) * spacing);
// Remove invalid polylines
polylines.erase(std::remove_if(polylines.begin(), polylines.end(),
[](const Polyline& p) { return p.size() < 2; }),
polylines.end());
for (const Polyline& pl : polylines) {
const size_t n = pl.points.size();
if (n < 2) {
all_polylines.emplace_back(pl);
continue;
}
if (polylines.empty())
return;
// Convert source polylines to Clipper2 paths
Clipper2Lib::Paths64 subject_paths = Slic3rPolylines_to_Paths64(polylines);
Points new_points;
new_points.reserve(n);
for (size_t i = 0; i < n; ++i) {
Vec2f tangent;
// For the first and last point, if the polyline is a
// closed loop, get the tangent from the points on either
// side of the join, otherwise just use the first or last
// line.
if (i == 0) {
if (pl.points[0] == pl.points[n-1]) {
tangent = (pl.points[1] - pl.points[n-2]).template cast<float>().normalized();
} else {
tangent = (pl.points[1] - pl.points[0]).template cast<float>().normalized();
}
} else if (i == n - 1) {
if (pl.points[0] == pl.points[n-1]) {
tangent = (pl.points[1] - pl.points[n-2]).template cast<float>().normalized();
} else {
tangent = (pl.points[n-1] - pl.points[n-2]).template cast<float>().normalized();
}
} else
tangent = (pl.points[i+1] - pl.points[i-1]).template cast<float>().normalized();
Vec2f normal(-tangent.y(), tangent.x());
const double miter_limit = 2.0;
const int rings = n_lines / 2;
Point p = pl.points[i] + (normal * offset).template cast<coord_t>();
new_points.push_back(p);
}
// Compute offsets (in units of spacing)
std::vector<double> offsets;
offsets.reserve(n_lines);
all_polylines.emplace_back(std::move(new_points));
}
}
polylines = std::move(all_polylines);
if (n_lines % 2 != 0) {
// Odd: center line at offset = 0
offsets.push_back(0.0);
for (int i = 1; i <= rings; ++i)
offsets.push_back(i * spacing);
} else {
// Even: no center, start at 0.5 * spacing
double start = 0.5 * spacing;
for (int i = 0; i < rings; ++i)
offsets.push_back(start + i * spacing);
}
// Process each offset
Clipper2Lib::ClipperOffset offsetter(miter_limit);
offsetter.AddPaths(subject_paths, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Round);
for (double t : offsets) {
if (t == 0.0) {
// Center line (only applies when n_lines is odd)
all_polylines.insert(all_polylines.end(), polylines.begin(), polylines.end());
continue;
}
// ClipperOffset with current offset distance (union is not needed here)
Clipper2Lib::Paths64 offset_paths;
offsetter.Execute(scale_(t), offset_paths);
if (offset_paths.empty())
continue;
// Convert back to polylines
Polylines new_polylines = Paths64_to_polylines(offset_paths);
for (Polyline& pl : new_polylines) {
if (pl.points.size() < 3)
continue;
if (pl.points.front() != pl.points.back())
pl.points.push_back(pl.points.front());
all_polylines.emplace_back(std::move(pl));
}
}
polylines = std::move(all_polylines);
}
} // namespace Slic3r

View file

@ -19,7 +19,7 @@ void FillConcentric::_fill_surface_single(
// no rotation is supported for this infill pattern
BoundingBox bounding_box = expolygon.contour.bounding_box();
coord_t min_spacing = scale_(this->spacing);
coord_t min_spacing = scale_(this->spacing) * params.multiline;
coord_t distance = coord_t(min_spacing / params.density);
if (params.density > 0.9999f && !params.dont_adjust) {
@ -27,8 +27,12 @@ void FillConcentric::_fill_surface_single(
this->spacing = unscale<double>(distance);
}
Polygons loops = to_polygons(expolygon);
ExPolygons last { std::move(expolygon) };
// Contract surface polygon by half line width to avoid excesive overlap with perimeter
ExPolygons contracted = offset_ex(expolygon, -float(scale_(0.5 * (params.multiline - 1) * this->spacing )));
Polygons loops = to_polygons(contracted);
ExPolygons last { std::move(contracted) };
while (! last.empty()) {
last = offset2_ex(last, -(distance + min_spacing/2), +min_spacing/2);
append(loops, to_polygons(last));
@ -46,6 +50,9 @@ void FillConcentric::_fill_surface_single(
last_pos = polylines_out.back().last_point();
}
// Apply multiline offset if needed
multiline_fill(polylines_out, params, spacing);
// clip the paths to prevent the extruder from getting exactly on the first point of the loop
// Keep valid paths only.
size_t j = iPathFirst;

View file

@ -74,7 +74,7 @@ void FillHoneycomb::_fill_surface_single(
}
}
// Apply multiline offset if needed
multiline_fill(all_polylines, params, 1.1 * spacing);
multiline_fill(all_polylines, params, spacing);
all_polylines = intersection_pl(std::move(all_polylines), expolygon);
chain_or_connect_infill(std::move(all_polylines), expolygon, polylines_out, this->spacing, params);

View file

@ -81,6 +81,9 @@ void FillPlanePath::_fill_surface_single(
BoundingBox snug_bounding_box = get_extents(expolygon).inflated(SCALED_EPSILON);
// Expand the bounding box to avoid artifacts at the edges
snug_bounding_box.offset(scale_(this->spacing)*params.multiline);
// Rotated bounding box of the area to fill in with the pattern.
BoundingBox bounding_box = align ?
// Sparse infill needs to be aligned across layers. Align infill across layers using the object's bounding box.
@ -97,7 +100,7 @@ void FillPlanePath::_fill_surface_single(
Polyline polyline;
{
auto distance_between_lines = scaled<double>(this->spacing) / params.density;
auto distance_between_lines = scaled<double>(this->spacing) * params.multiline / params.density;
auto min_x = coord_t(ceil(coordf_t(bounding_box.min.x()) / distance_between_lines));
auto min_y = coord_t(ceil(coordf_t(bounding_box.min.y()) / distance_between_lines));
auto max_x = coord_t(ceil(coordf_t(bounding_box.max.x()) / distance_between_lines));
@ -117,8 +120,13 @@ void FillPlanePath::_fill_surface_single(
}
}
Polylines polylines = {polyline};
// Apply multiline offset if needed
multiline_fill(polylines, params, spacing);
if (polyline.size() >= 2) {
Polylines polylines = intersection_pl(polyline, expolygon);
polylines = intersection_pl(std::move(polylines), expolygon);
if (!polylines.empty()) {
Polylines chained;
if (params.dont_connect() || params.density > 0.5) {

View file

@ -3000,7 +3000,7 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface *surface, FillPar
params.density /= double(sweep_params.size());
assert(params.density > 0.0001f && params.density <= 1.f);
ExPolygonWithOffset poly_with_offset_base(surface->expolygon, 0, float(scale_(this->overlap - 0.5 * this->spacing)));
ExPolygonWithOffset poly_with_offset_base(surface->expolygon, 0, float(scale_(this->overlap + 0.5 * params.multiline * this->spacing)));//increase offset to crop infill lines when using multiline infill
if (poly_with_offset_base.n_contours == 0)
// Not a single infill line fits.
return true;
@ -3012,19 +3012,24 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface *surface, FillPar
for (const SweepParams &sweep : sweep_params) {
// Rotate polygons so that we can work with vertical lines here
float angle = rotate_vector.first + sweep.angle_base;
//Fill Multiline
for (int i = 0; i < params.multiline; ++i) {
coord_t group_offset = i * line_spacing;
coord_t internal_offset = (i - (params.multiline - 1) / 2.0f) * line_width;
coord_t total_offset = group_offset + internal_offset;
coord_t pattern_shift = scale_(sweep.pattern_shift + unscale_(total_offset));
make_fill_lines(ExPolygonWithOffset(poly_with_offset_base, -angle), rotate_vector.second.rotated(-angle), angle,
line_width + coord_t(SCALED_EPSILON), line_spacing, pattern_shift, fill_lines);
}
make_fill_lines(ExPolygonWithOffset(poly_with_offset_base, -angle), rotate_vector.second.rotated(-angle), angle,
line_width + coord_t(SCALED_EPSILON), line_spacing, coord_t(scale_(sweep.pattern_shift)), fill_lines);
}
// Apply multiline offset if needed
multiline_fill(fill_lines, params, spacing);
// Contract surface polygon by half line width to avoid excesive overlap with perimeter
ExPolygons contracted = offset_ex(surface->expolygon, -float(scale_(0.5 * this->spacing)));
// if contraction results in empty polygon, use original surface
const ExPolygon &intersection_surface = contracted.empty() ? surface->expolygon : contracted.front();
if ((params.pattern == ipLateralLattice || params.pattern == ipLateralHoneycomb ) && params.multiline >1 )
// Intersect polylines with perimeter
fill_lines = intersection_pl(std::move(fill_lines), intersection_surface);
if ((params.pattern == ipLateralLattice || params.pattern == ipLateralHoneycomb ) && params.multiline >1 )
remove_overlapped(fill_lines, line_width);
if (!fill_lines.empty()) {
@ -3033,7 +3038,260 @@ if ((params.pattern == ipLateralLattice || params.pattern == ipLateralHoneycomb
fill_lines = chain_polylines(std::move(fill_lines));
append(polylines_out, std::move(fill_lines));
} else
connect_infill(std::move(fill_lines), poly_with_offset_base.polygons_outer, get_extents(surface->expolygon.contour), polylines_out, this->spacing, params);
connect_infill(std::move(fill_lines), intersection_surface, polylines_out, this->spacing, params);
}
return true;
}
bool FillRectilinear::fill_surface_trapezoidal(
const Surface* surface,
FillParams params,
const std::initializer_list<SweepParams>& sweep_params,
Polylines& polylines_out,
int Pattern_type) // 0=grid, 1=triangular
{
assert(params.multiline > 1);
Polylines polylines;
// Common parameters
const coord_t d1 = coord_t(scale_(this->spacing)) * params.multiline; // Infill total wall thickness
// Pattern-specific parameters
coord_t period;
double base_angle;
std::pair<double, Point> rotate_vector = this->_infill_direction(surface);
if (Pattern_type == 0) {
// Grid pattern parameters
period = coord_t((2.0 * d1 / params.density) * std::sqrt(2.0));
base_angle = rotate_vector.first + M_PI_4; // 45
} else {
// Triangular pattern parameters
period = coord_t(( 2.0 * d1 / params.density) * std::sqrt(3.0));
base_angle = rotate_vector.first + M_PI_2; //90
}
// Obtain the expolygon and rotate to align with pattern base angle
ExPolygon expolygon = surface->expolygon;
if (std::abs(base_angle) >= EPSILON) {
expolygon.rotate(-base_angle, rotate_vector.second);
}
// Use extended object bounding box for consistent pattern across layers
BoundingBox bb = this->extended_object_bounding_box();
switch (Pattern_type) {
case 0: // Grid / Trapezoidal
{
// Generate a non-crossing trapezoidal pattern to avoid overextrusion at intersections when `multiline > 1`.
// P1--P2
// / \
// P0/ \P3__P4
//
// P1x-P2x=P3x-P4x=d1
// P0y-P1y=P2y-P3y=d2
const coord_t d2 = coord_t(0.5 * period - d1);
// Align bounding box to the grid
bb.merge(align_to_grid(bb.min, Point(period, period)));
const coord_t xmin = bb.min.x();
const coord_t xmax = bb.max.x();
const coord_t ymin = bb.min.y();
const coord_t ymax = bb.max.y();
// Create the two base row patterns once
Polyline base_row_normal;
base_row_normal.points.reserve(((xmax - xmin) / period + 1) * 5); // 5 points per trapezoid
Polyline base_row_flipped;
base_row_flipped.points.reserve(((xmax - xmin) / period + 1) * 5); // 5 points per trapezoid
// Build complete rows from xmin to xmax
for (coord_t x = xmin; x < xmax; x += period) {
// Normal row
base_row_normal.points.emplace_back(Point(x, d1 / 2)); // P0
base_row_normal.points.emplace_back(Point(x + d1, d1 / 2)); // P1
base_row_normal.points.emplace_back(Point(x + d1 + d2, d1 / 2 + d2)); // P2
base_row_normal.points.emplace_back(Point(x + 2 * d1 + d2, d1 / 2 + d2)); // P3
base_row_normal.points.emplace_back(Point(x + 2 * d1 + 2 * d2, d1 / 2)); // P4
}
// Flipped row (mirrored vertically)
base_row_flipped.points = base_row_normal.points;
for (auto& p : base_row_flipped.points) {
p.y() = period / 2 - p.y();
}
// Pre-allocate polylines
const size_t estimated_rows = ((ymax - ymin) / (period / 2) + 1);
polylines.reserve(estimated_rows);
bool flip_vertical = false;
// Now just copy and translate vertically
for (coord_t y = ymin; y < ymax; y += period / 2) {
Polyline pl_row = flip_vertical ? base_row_flipped : base_row_normal;
// Translate all points vertically
for (Point& p : pl_row.points) {
p.y() += y;
}
polylines.emplace_back(std::move(pl_row));
flip_vertical = !flip_vertical;
}
// transpose points for odd layers
if (layer_id % 2 == 1) {
for (Polyline& pl : polylines) {
for (Point& p : pl.points) {
std::swap(p.x(), p.y());
p.x() += d1 / 2;
p.y() -= d1 / 2;
}
}
}
break;
}
case 1: // Triangular
{
// Generate a non-crossing trapezoidal pattern with a base line below.
// P1-P2
// / \
// P0/ \P3_P4
// ----------------
// P1x-P2x=P3x-P4x=d2
// P0y-P1y=P2y-P3y=h-2d1
//
// Triangular pattern density adjustment:
const coord_t d2_tri = coord_t(2.0 / std::sqrt(3.0) * d1);
const coord_t h = coord_t(0.5 * std::sqrt(3.0) * period); // height of triangle
// Align bounding box to the grid
bb.merge(align_to_grid(bb.center(), Point(period,h)));
const int layer_mod = layer_id % 3;
const double angle = layer_mod * 2.0 * M_PI / 3.0;
const Point rotation_center = bb.center();
const coord_t half_w = bb.size().x() / 2;
const coord_t half_h = bb.size().y() / 2;
// Compute how many full periods fit in each direction
const coord_t num_periods_x = coord_t(std::ceil(half_w / double(period)));
coord_t num_periods_y =coord_t(std::ceil(half_h / double(h)));
// Ensure an even number of rows so the pattern stays centered
if ((num_periods_y % 2) != 0)
++num_periods_y;
// Compute aligned limits (symmetric around the origin)
const coord_t x_min_aligned = -num_periods_x * period;
const coord_t x_max_aligned = num_periods_x * period;
const coord_t y_min_aligned = -num_periods_y * h;
const coord_t y_max_aligned = num_periods_y * h;
// Pre-allocate estimated number of polylines
const size_t estimated_rows = (y_max_aligned - y_min_aligned) / h + 2;
const size_t estimated_polylines = (estimated_rows + 1) * 2; // base line + trapezoid line per row
polylines.reserve(estimated_polylines);
// Create the two base row templates once
Polyline base_line_template;
base_line_template.points.reserve(2); // 2 points for base line
Polyline trapezoid_row_normal;
trapezoid_row_normal.points.reserve(((x_max_aligned - x_min_aligned) / period + 1) * 5); // 5 points per trapezoid
Polyline trapezoid_row_shifted;
trapezoid_row_shifted.points.reserve(((x_max_aligned - x_min_aligned) / period + 1) * 5); // 5 points per trapezoid
// Build base line template (from x_min_aligned to x_max_aligned)
base_line_template.points.emplace_back(Point(x_min_aligned, 0));
base_line_template.points.emplace_back(Point(x_max_aligned, 0));
// Build complete trapezoid rows once
// Normal row (no shift)
for (coord_t x = x_min_aligned; x < x_max_aligned; x += period) {
trapezoid_row_normal.points.emplace_back(Point(x + d2_tri / 2, d1)); // P0
trapezoid_row_normal.points.emplace_back(Point(x + period / 2 - d2_tri / 2, h - d1)); // P1
trapezoid_row_normal.points.emplace_back(Point(x + period / 2 + d2_tri / 2, h - d1)); // P2
trapezoid_row_normal.points.emplace_back(Point(x + period - d2_tri / 2, d1)); // P3
trapezoid_row_normal.points.emplace_back(Point(x + period, d1)); // P4
}
// Shifted row (mirrored vertically)
trapezoid_row_shifted.points = trapezoid_row_normal.points;
for (auto& p : trapezoid_row_shifted.points)
p.y() = h - p.y();
bool shift_row = false;
// Generate pattern by copying and translating templates vertically
for (coord_t y = y_min_aligned; y < y_max_aligned; y += h) {
// Base line - copy and translate
Polyline base_line = base_line_template;
for (Point& p : base_line.points) {
p.y() += y;
}
polylines.emplace_back(std::move(base_line));
// Trapezoid line - copy and translate the appropriate template
Polyline trapezoid_line = shift_row ? trapezoid_row_shifted : trapezoid_row_normal;
for (Point& p : trapezoid_line.points) {
p.y() += y;
}
if (!trapezoid_line.points.empty()) {
polylines.emplace_back(std::move(trapezoid_line));
}
shift_row = !shift_row;
}
// Rotate around origin (0,0)
if (layer_mod)
for (auto& pl : polylines)
pl.rotate(angle, Point(0,0));
break;
}
default:
// Handle unknown pattern type
break;
}
// Apply multiline fill
multiline_fill(polylines, params, spacing);
// Contract surface polygon by half line width to avoid excesive overlap with perimeter
ExPolygons contracted = offset_ex(expolygon, -float(scale_(0.5 * this->spacing)));
// if contraction results in empty polygon, use original surface
const ExPolygon &intersection_surface = contracted.empty() ? expolygon : contracted.front();
// Intersect polylines with offset expolygon
polylines = intersection_pl(std::move(polylines), intersection_surface);
// Remove very short segments that may cause connection issues
const double minlength = scale_(0.8 * this->spacing);
if (minlength > 0 && !polylines.empty()) {
polylines.erase(std::remove_if(polylines.begin(), polylines.end(),
[minlength](const Polyline& pl) { return pl.length() < minlength; }),
polylines.end());
}
// Connect infill lines using offset expolygon
int infill_start_idx = polylines_out.size();
if (!polylines.empty()) {
Slic3r::Fill::chain_or_connect_infill(std::move(polylines), intersection_surface, polylines_out, this->spacing, params);
// Rotate back the infill lines to original orientation
if (std::abs(base_angle) >= EPSILON) {
for (auto it = polylines_out.begin() + infill_start_idx; it != polylines_out.end(); ++it) {
it->rotate(base_angle, rotate_vector.second);
}
}
}
return true;
@ -3077,15 +3335,27 @@ Polylines FillMonotonicLine::fill_surface(const Surface* surface, const FillPara
Polylines FillGrid::fill_surface(const Surface *surface, const FillParams &params)
{
Polylines polylines_out;
if (! this->fill_surface_by_multilines(
surface, params,
{ { 0.f, 0.f }, { float(M_PI / 2.), 0.f } },
polylines_out))
BOOST_LOG_TRIVIAL(error) << "FillGrid::fill_surface() failed to fill a region.";
if (this->layer_id % 2 == 1)
for (int i = 0; i < polylines_out.size(); i++)
std::reverse(polylines_out[i].begin(), polylines_out[i].end());
if (params.multiline > 1) {
// Experimental trapezoidal grid
if (!this->fill_surface_trapezoidal(
surface, params,
{ { 0.f, 0.f }, { float(M_PI / 2.), 0.f } },
polylines_out,0))
BOOST_LOG_TRIVIAL(error) << "FillGrid::fill_surface_trapezoidal() failed.";
} else {
if (!this->fill_surface_by_multilines(
surface, params,
{ { 0.f, 0.f }, { float(M_PI / 2.), 0.f } },
polylines_out))
BOOST_LOG_TRIVIAL(error) << "FillGrid::fill_surface() failed to fill a region.";
if (this->layer_id % 2 == 1)
for (int i = 0; i < polylines_out.size(); i++)
std::reverse(polylines_out[i].begin(), polylines_out[i].end());
}
return polylines_out;
}
@ -3108,12 +3378,23 @@ Polylines FillLateralLattice::fill_surface(const Surface *surface, const FillPar
Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams &params){
Polylines polylines_out;
if (params.multiline > 1) {
// Experimental trapezoidal grid
if (!this->fill_surface_trapezoidal(
surface, params,
{ { 0.f, 0.f }, { float(M_PI / 2.), 0.f } },
polylines_out,1))
BOOST_LOG_TRIVIAL(error) << "FillGrid::fill_surface_trapezoidal() failed.";
} else {
if (! this->fill_surface_by_multilines(
surface, params,
{ { 0.f, 0.f }, { float(M_PI / 3.), 0.f }, { float(2. * M_PI / 3.), 0. } },
polylines_out))
BOOST_LOG_TRIVIAL(error) << "FillTriangles::fill_surface() failed to fill a region.";
}
return polylines_out;
}
Polylines FillStars::fill_surface(const Surface *surface, const FillParams &params)
@ -3144,8 +3425,8 @@ Polylines FillQuarterCubic::fill_surface(const Surface* surface, const FillParam
using namespace boost::math::float_constants;
Polylines polylines_out;
coord_t line_width = coord_t(scale_(this->spacing));
coord_t period = coord_t(scale_(this->spacing) / params.density) * 4;
coord_t line_width = coord_t(scale_(this->spacing)) * params.multiline;
coord_t period = coord_t(scale_(this->spacing) *params.multiline / params.density) * 4;
// First half tetrahedral fill
double pattern_z_shift = 0.0;

View file

@ -29,6 +29,7 @@ protected:
float pattern_shift;
};
bool fill_surface_by_multilines(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out);
bool fill_surface_trapezoidal(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out,int Pattern_type);
// The extended bounding box of the whole object that covers any rotation of every layer.
BoundingBox extended_object_bounding_box() const;

View file

@ -6196,10 +6196,16 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
);
}
// if still in avoidance mode and under “max”, clamp to “min”
if (m_resonance_avoidance
&& speed <= m_config.max_resonance_avoidance_speed.value) {
speed = std::min(speed, m_config.min_resonance_avoidance_speed.value);
// if still in avoidance mode and under "max", adjust speed:
// - speeds in lower half of range: clamp down to "min"
// - speeds in upper half of range: boost up to "max"
if (m_resonance_avoidance && speed < m_config.max_resonance_avoidance_speed.value) {
if (speed < m_config.min_resonance_avoidance_speed.value +
((m_config.max_resonance_avoidance_speed.value - m_config.min_resonance_avoidance_speed.value) / 2)) {
speed = std::min(speed, m_config.min_resonance_avoidance_speed.value);
} else {
speed = m_config.max_resonance_avoidance_speed.value;
}
}
// reset flag for next segment

View file

@ -1045,8 +1045,8 @@ namespace client
case coFloatOrPercent:
{
std::string opt_key(opt.it_range.begin(), opt.it_range.end());
if (boost::ends_with(opt_key, "extrusion_width")) {
// Extrusion width supports defaults and a complex graph of dependencies.
if (boost::ends_with(opt_key, "line_width")) {
// Line width supports defaults and a complex graph of dependencies.
output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast<unsigned int>(ctx->current_extruder_id)));
} else if (! static_cast<const ConfigOptionFloatOrPercent*>(opt.opt)->percent) {
// Not a percent, just return the value.
@ -1060,8 +1060,8 @@ namespace client
const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over);
if (opt_parent == nullptr)
ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range);
if (boost::ends_with(opt_def->ratio_over, "extrusion_width")) {
// Extrusion width supports defaults and a complex graph of dependencies.
if (boost::ends_with(opt_def->ratio_over, "line_width")) {
// Line width supports defaults and a complex graph of dependencies.
assert(opt_parent->type() == coFloatOrPercent);
v *= Flow::extrusion_width(opt_def->ratio_over, static_cast<const ConfigOptionFloatOrPercent*>(opt_parent), *ctx, static_cast<unsigned int>(ctx->current_extruder_id));
break;
@ -2197,9 +2197,8 @@ namespace client
initializer_list(_r1)[px::bind(&MyContext::vector_variable_new_from_initializer_list, _r1, _a, _b, _1)]
// Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index.
// Only process such variable references, which return a naked vector variable.
// Orca todo: following code cause strange build errors with MSVC C++17
// | eps(px::bind(&MyContext::could_be_vector_variable_reference, _b)) >>
// variable_reference(_r1)[px::val(qi::_pass) = px::bind(&MyContext::vector_variable_new_from_copy, _r1, _a, _b, _1)]
| eps(px::bind(&MyContext::could_be_vector_variable_reference, _b)) >>
variable_reference(_r1)[qi::_pass = px::bind(&MyContext::vector_variable_new_from_copy, _r1, _a, _b, _1)]
// Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above.
| conditional_expression(_r1)
[px::bind(&MyContext::scalar_variable_new_from_scalar_expression, _r1, _a, _b, _1)]

View file

@ -2752,6 +2752,8 @@ Preset *PresetBundle::get_similar_printer_preset(std::string printer_model, std:
{
if (printer_model.empty())
printer_model = printers.get_selected_preset().config.opt_string("printer_model");
if (printer_model.empty()) // ORCA ensure a compatible model exist. fixes switches to blank preset if preset has no inherited value
return nullptr;
auto printer_variant_old = printers.get_selected_preset().config.opt_string("printer_variant");
std::map<std::string, Preset*> printer_presets;
for (auto &preset : printers.m_presets) {
@ -2762,7 +2764,8 @@ Preset *PresetBundle::get_similar_printer_preset(std::string printer_model, std:
}
if (printer_presets.empty())
return nullptr;
auto prefer_printer = printers.get_selected_preset().name;
auto prefer_printer = printers.get_selected_preset().alias; //.name ORCA use alias instead "name" for calling system presets. otherwise nozzle combo will not change printer presets if they custom named
if (!printer_variant.empty())
boost::replace_all(prefer_printer, printer_variant_old, printer_variant);
else if (auto n = prefer_printer.find(printer_variant_old); n != std::string::npos)

View file

@ -2750,7 +2750,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Fill Multiline");
def->tooltip = L("Using multiple lines for the infill pattern, if supported by infill pattern.");
def->min = 1;
def->max = 5; // Maximum number of lines for infill pattern
def->max = 10; // Maximum number of lines for infill pattern
def->set_default_value(new ConfigOptionInt(1));
def = this->add("sparse_infill_pattern", coEnum);

View file

@ -604,8 +604,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
// Infill patterns that support multiline infill.
InfillPattern pattern = config->opt_enum<InfillPattern>("sparse_infill_pattern");
bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipTpmsFK || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ipLateralLattice || pattern == ipLateralHoneycomb ||
pattern == ipCubic || pattern == ipStars || pattern == ipAlignedRectilinear || pattern == ipLightning || pattern == ip3DHoneycomb || pattern == ipAdaptiveCubic || pattern == ipSupportCubic;
bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipTpmsFK || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ipLateralLattice || pattern == ipLateralHoneycomb || pattern == ipConcentric ||
pattern == ipCubic || pattern == ipStars || pattern == ipAlignedRectilinear || pattern == ipLightning || pattern == ip3DHoneycomb || pattern == ipAdaptiveCubic || pattern == ipSupportCubic|| pattern == ipTriangles || pattern == ipQuarterCubic|| pattern == ipArchimedeanChords || pattern == ipHilbertCurve || pattern == ipOctagramSpiral;
// If there is infill, enable/disable fill_multiline according to whether the pattern supports multiline infill.
if (have_infill) {
@ -774,10 +774,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
// Orca: Force solid support interface when using support ironing
toggle_field("support_interface_spacing", have_support_material && have_support_interface && !has_support_ironing);
bool have_skirt_height = have_skirt &&
(config->opt_int("skirt_height") > 1 || config->opt_enum<DraftShield>("draft_shield") != dsEnabled);
toggle_line("support_speed", have_support_material || have_skirt_height);
toggle_line("support_interface_speed", have_support_material && have_support_interface);
// see issue #10915
// bool have_skirt_height = have_skirt &&
// (config->opt_int("skirt_height") > 1 || config->opt_enum<DraftShield>("draft_shield") != dsEnabled);
// toggle_line("support_speed", have_support_material || have_skirt_height);
// toggle_line("support_interface_speed", have_support_material && have_support_interface);
// BBS
//toggle_field("support_material_synchronize_layers", have_support_soluble);

View file

@ -29,6 +29,14 @@ ImageDPIFrame::ImageDPIFrame()
#ifdef __APPLE__
SetWindowStyleFlag(GetWindowStyleFlag() | wxSTAY_ON_TOP);
#endif
// ORCA add border
Bind(wxEVT_PAINT, [this](wxPaintEvent& evt) {
wxPaintDC dc(this);
dc.SetPen(StateColor::darkModeColorFor(wxColour("#DBDBDB")));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 0);
});
m_sizer_main = new wxBoxSizer(wxVERTICAL);

View file

@ -221,9 +221,14 @@ wxDEFINE_EVENT(EVT_NOTICE_FULL_SCREEN_CHANGED, IntEvent);
static string get_diameter_string(float diameter)
{
std::ostringstream stream;
stream << std::fixed << std::setprecision(1) << diameter;
return stream.str();
std::ostringstream stream; // ORCA ensure 0.25 returned as 0.25. previous code returned as 0.2 because of std::setprecision(1)
stream << std::fixed << std::setprecision(2) << diameter; // Use 2 decimals to capture 0.25 / 0.15 reliably
std::string s = stream.str();
if (s.find('.') != std::string::npos) { // Remove trailing zeros, but keep at least one decimal if needed
s.erase(s.find_last_not_of('0') + 1);
if (s.back() == '.') s += '0'; // Ensure "1." → "1.0"
}
return s;
}
bool Plater::has_illegal_filename_characters(const wxString& wxs_name)
@ -1234,7 +1239,8 @@ bool Sidebar::priv::switch_diameter(bool single)
}
auto preset = wxGetApp().preset_bundle->get_similar_printer_preset({}, diameter.ToStdString());
if (preset == nullptr) {
MessageDialog dlg(this->plater, "", "");
// ORCA add a text. this appears when user tries to change nozzle value but config doesnt have a inherited or compatible preset
MessageDialog dlg(this->plater, _L("Configuration incompatible"), _L("Warning"), wxICON_WARNING | wxOK);
dlg.ShowModal();
return false;
}
@ -2564,9 +2570,18 @@ void Sidebar::update_presets(Preset::Type preset_type)
p->layout_printer(preset_bundle.use_bbl_network(), isBBL && is_dual_extruder);
auto diameters = wxGetApp().preset_bundle->printers.diameters_of_selected_printer();
auto diameter = printer_preset.config.opt_string("printer_variant");
auto update_extruder_diameter = [&diameters, &diameter](ExtruderGroup & extruder) {
auto update_extruder_diameter = [&diameters, &diameter, &nozzle_diameter](int extruder_index,ExtruderGroup & extruder) {
extruder.combo_diameter->Clear();
int select = -1;
// ORCA if user defined a custom nozzle in printer config select it instead inherited one. this will show correct nozzle diameter in combobox if its exist in nozzle diameters list
auto nozzle_dia = get_diameter_string(nozzle_diameter->values[extruder_index]);
if(nozzle_dia != diameter && std::find(diameters.begin(), diameters.end(), nozzle_dia) != diameters.end())
diameter = nozzle_dia;
// ORCA try to add nozzle diameter from config if list is empty. fixes blank nozzle combo box when preset has no alias
if(diameters[0].empty() && !nozzle_dia.empty()){
diameters[0] = nozzle_dia;
diameter = nozzle_dia;
}
for (size_t i = 0; i < diameters.size(); ++i) {
if (diameters[i] == diameter)
select = extruder.combo_diameter->GetCount();
@ -2580,14 +2595,14 @@ void Sidebar::update_presets(Preset::Type preset_type)
AMSCountPopupWindow::UpdateAMSCount(0, p->left_extruder);
AMSCountPopupWindow::UpdateAMSCount(1, p->right_extruder);
//if (!p->is_switching_diameter) {
update_extruder_diameter(*p->left_extruder);
update_extruder_diameter(*p->right_extruder);
update_extruder_diameter(0, *p->left_extruder);
update_extruder_diameter(1, *p->right_extruder);
//}
p->image_printer_bed->SetBitmap(create_scaled_bitmap(image_path, this, PRINTER_THUMBNAIL_SIZE.GetHeight()));
} else {
AMSCountPopupWindow::UpdateAMSCount(0, p->single_extruder);
//if (!p->is_switching_diameter)
update_extruder_diameter(*p->single_extruder);
update_extruder_diameter(0, *p->single_extruder);
// ORCA sync unified nozzle combo box
p->combo_nozzle_dia->Clear();

View file

@ -4280,6 +4280,9 @@ void TabFilament::reload_config()
this->compatible_widget_reload(m_compatible_printers);
this->compatible_widget_reload(m_compatible_prints);
Tab::reload_config();
// Recompute derived override UI from the newly loaded config
update_filament_overrides_page(&m_preset_bundle->printers.get_edited_preset().config);
}
//void TabFilament::update_volumetric_flow_preset_hints()

View file

@ -14,40 +14,22 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
{ "nozzle_diameter", "0.6;0.6;0.6;0.6" },
{ "nozzle_temperature", "357;359;363;378" }
});
// To let the PlaceholderParser throw when referencing initial_layer_line_width if it is set to percent, as the PlaceholderParser does not know
// To test the "min_width_top_surface" over "inner_wall_line_width".
config.option<ConfigOptionFloatOrPercent>("inner_wall_line_width")->value = 150.;
config.option<ConfigOptionFloatOrPercent>("inner_wall_line_width")->percent = true;
// To let the PlaceholderParser throw when referencing scarf_joint_speed if it is set to percent, as the PlaceholderParser does not know
// a percent to what.
config.option<ConfigOptionFloatOrPercent>("initial_layer_line_width")->value = 50.;
config.option<ConfigOptionFloatOrPercent>("initial_layer_line_width")->percent = true;
config.option<ConfigOptionFloatOrPercent>("scarf_joint_speed")->value = 50.;
config.option<ConfigOptionFloatOrPercent>("scarf_joint_speed")->percent = true;
parser.apply_config(config);
parser.set("foo", 0);
parser.set("bar", 2);
parser.set("num_extruders", 4);
SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[nozzle_temperature_[foo]]") == "357"); }
SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[nozzle_temperature[foo]]") == "357"); }
SECTION("array reference") { REQUIRE(parser.process("{nozzle_temperature[foo]}") == "357"); }
SECTION("whitespaces and newlines are maintained") { REQUIRE(parser.process("test [ nozzle_temperature_ [foo] ] \n hu") == "test 357 \n hu"); }
// Test the "coFloatOrPercent" and "xxx_width" substitutions.
// FIXME: Don't know what exactly this referred to in Prusaslicer or
// whether it should apply to Orca or not.
// {outer_wall_line_width} returns as its default value, 0.
// SECTION("outer_wall_line_width") { REQUIRE(std::stod(parser.process("{outer_wall_line_width}")) == Catch::Approx(0.67500001192092896)); }
SECTION("support_object_xy_distance") { REQUIRE(std::stod(parser.process("{support_object_xy_distance}")) == Catch::Approx(0.35)); }
// initial_layer_line_width ratio over nozzle_diameter.
// FIXME: either something else which correctly calculates a ratio should be here,
// or something else should be found for for the REQUIRE_THROWS
// SECTION("initial_layer_line_width") { REQUIRE(std::stod(parser.process("{initial_layer_line_width}")) == Catch::Approx(0.9)); }
// small_perimeter_speed ratio over outer_wall_speed
SECTION("small_perimeter_speed") { REQUIRE(std::stod(parser.process("{small_perimeter_speed}")) == Catch::Approx(30.)); }
// infill_wall_overlap over inner_wall_line_width
// FIXME: Shouldn't this return the calculated value and not the percentage 15?
// SECTION("infill_wall_overlap") { REQUIRE(std::stod(parser.process("{infill_wall_overlap}")) == Catch::Approx(0.16875)); }
// If initial_layer_line_width is set to percent, then it is applied over respective extrusion types by overriding their respective speeds.
// The PlaceholderParser has no way to know which extrusion type the caller has in mind, therefore it throws.
SECTION("initial_layer_line_width throws failed to resolve the ratio_over dependencies") { REQUIRE_THROWS(parser.process("{initial_layer_line_width}")); }
SECTION("whitespaces and newlines are maintained") { REQUIRE(parser.process("test [ nozzle_temperature [foo] ] \n hu") == "test 357 \n hu"); }
// Test the math expressions.
SECTION("math: 2*3") { REQUIRE(parser.process("{2*3}") == "6"); }
@ -84,6 +66,20 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
SECTION("math: interpolate_table(13, (0, 0), (20, 20), (30, 20))") { REQUIRE(std::stod(parser.process("{interpolate_table(13, (0, 0), (20, 20), (30, 20))}")) == Catch::Approx(13.)); }
SECTION("math: interpolate_table(25, (0, 0), (20, 20), (30, 20))") { REQUIRE(std::stod(parser.process("{interpolate_table(25, (0, 0), (20, 20), (30, 20))}")) == Catch::Approx(20.)); }
// Test the "coFloatOrPercent" and "xxx_line_width" substitutions.
// min_width_top_surface ratio_over inner_wall_line_width.
SECTION("line_width") { REQUIRE(std::stod(parser.process("{line_width}")) == Catch::Approx(0.67500001192092896)); }
SECTION("min_width_top_surface") { REQUIRE(std::stod(parser.process("{min_width_top_surface}")) == Catch::Approx(2.7)); }
// Orca: this one is not coFloatOrPercent
//SECTION("support_object_xy_distance") { REQUIRE(std::stod(parser.process("{support_object_xy_distance}")) == Catch::Approx(0.3375)); }
// small_perimeter_speed over outer_wall_speed
SECTION("small_perimeter_speed") { REQUIRE(std::stod(parser.process("{small_perimeter_speed}")) == Catch::Approx(30.)); }
// infill_anchor over sparse_infill_line_width
SECTION("infill_anchor") { REQUIRE(std::stod(parser.process("{infill_anchor}")) == Catch::Approx(2.7)); }
// If scarf_joint_speed is set to percent, then it is applied over respective extrusion types by overriding their respective speeds.
// The PlaceholderParser has no way to know which extrusion type the caller has in mind, therefore it throws.
SECTION("scarf_joint_speed") { REQUIRE_THROWS(parser.process("{scarf_joint_speed}")); }
// Test the boolean expression parser.
auto boolean_expression = [&parser](const std::string& templ) { return parser.evaluate_boolean_expression(templ, parser.config()); };
@ -116,3 +112,131 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
SECTION("complex expression2") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)")); }
SECTION("complex expression3") { REQUIRE(! boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)")); }
}
SCENARIO("Placeholder parser variables", "[PlaceholderParser]") {
PlaceholderParser parser;
auto config = DynamicPrintConfig::full_print_config();
config.set_deserialize_strict({
{ "filament_notes", "testnotes" },
{ "enable_pressure_advance", "1" },
{ "nozzle_diameter", "0.6;0.6;0.6;0.6" },
{ "nozzle_temperature", "357;359;363;378" }
});
PlaceholderParser::ContextData context_with_global_dict;
context_with_global_dict.global_config = std::make_unique<DynamicConfig>();
SECTION("create an int local variable") { REQUIRE(parser.process("{local myint = 33+2}{myint}", 0, nullptr, nullptr, nullptr) == "35"); }
SECTION("create a string local variable") { REQUIRE(parser.process("{local mystr = \"mine\" + \"only\" + \"mine\"}{mystr}", 0, nullptr, nullptr, nullptr) == "mineonlymine"); }
SECTION("create a bool local variable") { REQUIRE(parser.process("{local mybool = 1 + 1 == 2}{mybool}", 0, nullptr, nullptr, nullptr) == "true"); }
SECTION("create an int global variable") { REQUIRE(parser.process("{global myint = 33+2}{myint}", 0, nullptr, nullptr, &context_with_global_dict) == "35"); }
SECTION("create a string global variable") { REQUIRE(parser.process("{global mystr = \"mine\" + \"only\" + \"mine\"}{mystr}", 0, nullptr, nullptr, &context_with_global_dict) == "mineonlymine"); }
SECTION("create a bool global variable") { REQUIRE(parser.process("{global mybool = 1 + 1 == 2}{mybool}", 0, nullptr, nullptr, &context_with_global_dict) == "true"); }
SECTION("create an int local variable and overwrite it") { REQUIRE(parser.process("{local myint = 33+2}{myint = 12}{myint}", 0, nullptr, nullptr, nullptr) == "12"); }
SECTION("create a string local variable and overwrite it") { REQUIRE(parser.process("{local mystr = \"mine\" + \"only\" + \"mine\"}{mystr = \"yours\"}{mystr}", 0, nullptr, nullptr, nullptr) == "yours"); }
SECTION("create a bool local variable and overwrite it") { REQUIRE(parser.process("{local mybool = 1 + 1 == 2}{mybool = false}{mybool}", 0, nullptr, nullptr, nullptr) == "false"); }
SECTION("create an int global variable and overwrite it") { REQUIRE(parser.process("{global myint = 33+2}{myint = 12}{myint}", 0, nullptr, nullptr, &context_with_global_dict) == "12"); }
SECTION("create a string global variable and overwrite it") { REQUIRE(parser.process("{global mystr = \"mine\" + \"only\" + \"mine\"}{mystr = \"yours\"}{mystr}", 0, nullptr, nullptr, &context_with_global_dict) == "yours"); }
SECTION("create a bool global variable and overwrite it") { REQUIRE(parser.process("{global mybool = 1 + 1 == 2}{mybool = false}{mybool}", 0, nullptr, nullptr, &context_with_global_dict) == "false"); }
SECTION("create an int local variable and redefine it") { REQUIRE(parser.process("{local myint = 33+2}{local myint = 12}{myint}", 0, nullptr, nullptr, nullptr) == "12"); }
SECTION("create a string local variable and redefine it") { REQUIRE(parser.process("{local mystr = \"mine\" + \"only\" + \"mine\"}{local mystr = \"yours\"}{mystr}", 0, nullptr, nullptr, nullptr) == "yours"); }
SECTION("create a bool local variable and redefine it") { REQUIRE(parser.process("{local mybool = 1 + 1 == 2}{local mybool = false}{mybool}", 0, nullptr, nullptr, nullptr) == "false"); }
SECTION("create an int global variable and redefine it") { REQUIRE(parser.process("{global myint = 33+2}{global myint = 12}{myint}", 0, nullptr, nullptr, &context_with_global_dict) == "12"); }
SECTION("create a string global variable and redefine it") { REQUIRE(parser.process("{global mystr = \"mine\" + \"only\" + \"mine\"}{global mystr = \"yours\"}{mystr}", 0, nullptr, nullptr, &context_with_global_dict) == "yours"); }
SECTION("create a bool global variable and redefine it") { REQUIRE(parser.process("{global mybool = 1 + 1 == 2}{global mybool = false}{mybool}", 0, nullptr, nullptr, &context_with_global_dict) == "false"); }
SECTION("create an ints local variable with repeat()") { REQUIRE(parser.process("{local myint = repeat(2*3, 4*6)}{myint[5]}", 0, nullptr, nullptr, nullptr) == "24"); }
SECTION("create a strings local variable with repeat()") { REQUIRE(parser.process("{local mystr = repeat(2*3, \"mine\" + \"only\" + \"mine\")}{mystr[5]}", 0, nullptr, nullptr, nullptr) == "mineonlymine"); }
SECTION("create a bools local variable with repeat()") { REQUIRE(parser.process("{local mybool = repeat(5, 1 + 1 == 2)}{mybool[4]}", 0, nullptr, nullptr, nullptr) == "true"); }
SECTION("create an ints global variable with repeat()") { REQUIRE(parser.process("{global myint = repeat(2*3, 4*6)}{myint[5]}", 0, nullptr, nullptr, &context_with_global_dict) == "24"); }
SECTION("create a strings global variable with repeat()") { REQUIRE(parser.process("{global mystr = repeat(2*3, \"mine\" + \"only\" + \"mine\")}{mystr[5]}", 0, nullptr, nullptr, &context_with_global_dict) == "mineonlymine"); }
SECTION("create a bools global variable with repeat()") { REQUIRE(parser.process("{global mybool = repeat(5, 1 + 1 == 2)}{mybool[4]}", 0, nullptr, nullptr, &context_with_global_dict) == "true"); }
SECTION("create an ints local variable with initializer list") { REQUIRE(parser.process("{local myint = (2*3, 4*6, 5*5)}{myint[1]}", 0, nullptr, nullptr, nullptr) == "24"); }
SECTION("create a strings local variable with initializer list") { REQUIRE(parser.process("{local mystr = (2*3, \"mine\" + \"only\" + \"mine\", 8)}{mystr[1]}", 0, nullptr, nullptr, nullptr) == "mineonlymine"); }
SECTION("create a bools local variable with initializer list") { REQUIRE(parser.process("{local mybool = (3*3 == 8, 1 + 1 == 2)}{mybool[1]}", 0, nullptr, nullptr, nullptr) == "true"); }
SECTION("create an ints global variable with initializer list") { REQUIRE(parser.process("{global myint = (2*3, 4*6, 5*5)}{myint[1]}", 0, nullptr, nullptr, &context_with_global_dict) == "24"); }
SECTION("create a strings global variable with initializer list") { REQUIRE(parser.process("{global mystr = (2*3, \"mine\" + \"only\" + \"mine\", 8)}{mystr[1]}", 0, nullptr, nullptr, &context_with_global_dict) == "mineonlymine"); }
SECTION("create a bools global variable with initializer list") { REQUIRE(parser.process("{global mybool = (2*3 == 8, 1 + 1 == 2, 5*5 != 33)}{mybool[1]}", 0, nullptr, nullptr, &context_with_global_dict) == "true"); }
SECTION("create an ints local variable by a copy") { REQUIRE(parser.process("{local myint = nozzle_temperature}{myint[0]}", 0, &config, nullptr, nullptr) == "357"); }
SECTION("create a strings local variable by a copy") { REQUIRE(parser.process("{local mystr = filament_notes}{mystr[0]}", 0, &config, nullptr, nullptr) == "testnotes"); }
SECTION("create a bools local variable by a copy") { REQUIRE(parser.process("{local mybool = enable_pressure_advance}{mybool[0]}", 0, &config, nullptr, nullptr) == "true"); }
SECTION("create an ints global variable by a copy") { REQUIRE(parser.process("{global myint = nozzle_temperature}{myint[0]}", 0, &config, nullptr, &context_with_global_dict) == "357"); }
SECTION("create a strings global variable by a copy") { REQUIRE(parser.process("{global mystr = filament_notes}{mystr[0]}", 0, &config, nullptr, &context_with_global_dict) == "testnotes"); }
SECTION("create a bools global variable by a copy") { REQUIRE(parser.process("{global mybool = enable_pressure_advance}{mybool[0]}", 0, &config, nullptr, &context_with_global_dict) == "true"); }
SECTION("create an ints local variable by a copy and overwrite it") {
REQUIRE(parser.process("{local myint = nozzle_temperature}{myint = repeat(2*3, 4*6)}{myint[5]}", 0, &config, nullptr, nullptr) == "24");
REQUIRE(parser.process("{local myint = nozzle_temperature}{myint = (2*3, 4*6)}{myint[1]}", 0, &config, nullptr, nullptr) == "24");
REQUIRE(parser.process("{local myint = nozzle_temperature}{myint = (1)}{myint = nozzle_temperature}{myint[0]}", 0, &config, nullptr, nullptr) == "357");
}
SECTION("create a strings local variable by a copy and overwrite it") {
REQUIRE(parser.process("{local mystr = filament_notes}{mystr = repeat(2*3, \"mine\" + \"only\" + \"mine\")}{mystr[5]}", 0, &config, nullptr, nullptr) == "mineonlymine");
REQUIRE(parser.process("{local mystr = filament_notes}{mystr = (2*3, \"mine\" + \"only\" + \"mine\")}{mystr[1]}", 0, &config, nullptr, nullptr) == "mineonlymine");
REQUIRE(parser.process("{local mystr = filament_notes}{mystr = (2*3, \"mine\" + \"only\" + \"mine\")}{mystr = filament_notes}{mystr[0]}", 0, &config, nullptr, nullptr) == "testnotes");
}
SECTION("create a bools local variable by a copy and overwrite it") {
REQUIRE(parser.process("{local mybool = enable_pressure_advance}{mybool = repeat(2*3, true)}{mybool[5]}", 0, &config, nullptr, nullptr) == "true");
REQUIRE(parser.process("{local mybool = enable_pressure_advance}{mybool = (false, true)}{mybool[1]}", 0, &config, nullptr, nullptr) == "true");
REQUIRE(parser.process("{local mybool = enable_pressure_advance}{mybool = (false, false)}{mybool = enable_pressure_advance}{mybool[0]}", 0, &config, nullptr, nullptr) == "true");
}
SECTION("size() of a non-empty vector returns the right size") { REQUIRE(parser.process("{local myint = (0, 1, 2, 3)}{size(myint)}", 0, nullptr, nullptr, nullptr) == "4"); }
SECTION("size() of a an empty vector returns the right size") { REQUIRE(parser.process("{local myint = (0);myint=();size(myint)}", 0, nullptr, nullptr, nullptr) == "0"); }
SECTION("empty() of a non-empty vector returns false") { REQUIRE(parser.process("{local myint = (0, 1, 2, 3)}{empty(myint)}", 0, nullptr, nullptr, nullptr) == "false"); }
SECTION("empty() of a an empty vector returns true") { REQUIRE(parser.process("{local myint = (0);myint=();empty(myint)}", 0, nullptr, nullptr, nullptr) == "true"); }
SECTION("nested if with new variables") {
std::string script =
"{if 1 == 1}{local myints = (5, 4, 3, 2, 1)}{else}{local myfloats = (1., 2., 3., 4., 5., 6., 7.)}{endif}"
"{myints[1]},{size(myints)}";
REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "4,5");
}
SECTION("nested if with new variables 2") {
std::string script =
"{if 1 == 0}{local myints = (5, 4, 3, 2, 1)}{else}{local myfloats = (1., 2., 3., 4., 5., 6., 7.)}{endif}"
"{size(myfloats)}";
REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "7");
}
SECTION("nested if with new variables 2, mixing }{ with ;") {
std::string script =
"{if 1 == 0 then local myints = (5, 4, 3, 2, 1);else;local myfloats = (1., 2., 3., 4., 5., 6., 7.);endif}"
"{size(myfloats)}";
REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "7");
}
SECTION("nested if with new variables, two level") {
std::string script =
"{if 1 == 1}{if 2 == 3}{nejaka / haluz}{else}{local myints = (6, 5, 4, 3, 2, 1)}{endif}{else}{if zase * haluz}{else}{local myfloats = (1., 2., 3., 4., 5., 6., 7.)}{endif}{endif}"
"{size(myints)}";
REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "6");
}
SECTION("if with empty block and ;") {
std::string script =
"{if false then else;local myfloats = (1., 2., 3., 4., 5., 6., 7.);endif}"
"{size(myfloats)}";
REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "7");
}
SECTION("nested if with new variables, two level, mixing }{ with ;") {
std::string script =
"{if 1 == 1 then if 2 == 3}nejaka / haluz{else local myints = (6, 5, 4, 3, 2, 1) endif else if zase * haluz then else local myfloats = (1., 2., 3., 4., 5., 6., 7.) endif endif}"
"{size(myints)}";
REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "6");
}
SECTION("nested if with new variables, two level, mixing }{ with ; 2") {
std::string script =
"{if 1 == 1 then if 2 == 3 then nejaka / haluz else}{local myints = (6, 5, 4, 3, 2, 1)}{endif else if zase * haluz then else local myfloats = (1., 2., 3., 4., 5., 6., 7.) endif endif}"
"{size(myints)}";
REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "6");
}
SECTION("nested if with new variables, two level, mixing }{ with ; 3") {
std::string script =
"{if 1 == 1 then if 2 == 3 then nejaka / haluz else}{local myints = (6, 5, 4, 3, 2, 1)}{endif else}{if zase * haluz}{else local myfloats = (1., 2., 3., 4., 5., 6., 7.) endif}{endif}"
"{size(myints)}";
REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "6");
}
SECTION("if else completely empty") { REQUIRE(parser.process("{if false then elsif false then else endif}", 0, nullptr, nullptr, nullptr) == ""); }
}