mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-29 20:01:26 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06cd4cbcc2 | ||
|
|
2ae1fdbd01 | ||
|
|
78b504be0e | ||
|
|
3ef782c6e5 |
@@ -189,7 +189,8 @@ the presets to a base is in [shared-bases.md](shared-bases.md#variant-arrays-on-
|
|||||||
2. Every key in `filament_options_with_variant` ([the full list](#the-four-key-sets)) that reaches the
|
2. Every key in `filament_options_with_variant` ([the full list](#the-four-key-sets)) that reaches the
|
||||||
preset, whether written, included or inherited, is resized to its variant count: write it at exactly
|
preset, whether written, included or inherited, is resized to its variant count: write it at exactly
|
||||||
that width, or leave it out. Keys outside the set
|
that width, or leave it out. Keys outside the set
|
||||||
(`filament_type`, plate temperatures, `fan_max_speed`, `slow_down_min_speed`, …) are never addressed by variant index; the preset contributes their first value however wide a
|
(`filament_type`, plate temperatures, `fan_max_speed`, `slow_down_min_speed`, `pressure_advance`,
|
||||||
|
…) are never addressed by variant index; the preset contributes their first value however wide a
|
||||||
file writes them.
|
file writes them.
|
||||||
3. Cover every variant the material is meant to print on across its `compatible_printers`. Leave out
|
3. Cover every variant the material is meant to print on across its `compatible_printers`. Leave out
|
||||||
a variant deliberately when the material should not be tuned for it (e.g. a TPU High Flow variant
|
a variant deliberately when the material should not be tuned for it (e.g. a TPU High Flow variant
|
||||||
@@ -454,7 +455,7 @@ no set: the variant-length resize leaves it alone, and only the pair rebuild of
|
|||||||
last for contrast; it is not a variant set.
|
last for contrast; it is not a variant set.
|
||||||
|
|
||||||
`check` and `fix-variant` read the four sets from `PrintConfig.cpp` on every run, so they follow the
|
`check` and `fix-variant` read the four sets from `PrintConfig.cpp` on every run, so they follow the
|
||||||
engine. The lists below are from the 2026-09-29 checkout; regenerate them from the repository root
|
engine. The lists below are from the 2026-09-25 checkout; regenerate them from the repository root
|
||||||
before relying on them (the recipe strips comments, since an initializer can carry a commented-out entry):
|
before relying on them (the recipe strips comments, since an initializer can carry a commented-out entry):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -477,7 +478,7 @@ EOF
|
|||||||
|
|
||||||
**`print_options_with_variant`**, process, stride 1 (45): `bridge_acceleration`, `bridge_speed`, `default_acceleration`, `default_jerk`, `default_junction_deviation`, `enable_overhang_speed`, `gap_infill_speed`, `infill_jerk`, `initial_layer_acceleration`, `initial_layer_infill_speed`, `initial_layer_jerk`, `initial_layer_speed`, `initial_layer_travel_acceleration`, `initial_layer_travel_jerk`, `initial_layer_travel_speed`, `inner_wall_acceleration`, `inner_wall_jerk`, `inner_wall_speed`, `internal_bridge_speed`, `internal_solid_infill_acceleration`, `internal_solid_infill_speed`, `outer_wall_acceleration`, `outer_wall_jerk`, `outer_wall_speed`, `overhang_1_4_speed`, `overhang_2_4_speed`, `overhang_3_4_speed`, `overhang_4_4_speed`, `print_extruder_id`, `print_extruder_variant`, `slowdown_for_curled_perimeters`, `small_perimeter_speed`, `small_perimeter_threshold`, `sparse_infill_acceleration`, `sparse_infill_speed`, `support_interface_speed`, `support_speed`, `top_solid_infill_flow_ratio`, `top_surface_acceleration`, `top_surface_jerk`, `top_surface_speed`, `travel_acceleration`, `travel_jerk`, `travel_speed`, `travel_speed_z`
|
**`print_options_with_variant`**, process, stride 1 (45): `bridge_acceleration`, `bridge_speed`, `default_acceleration`, `default_jerk`, `default_junction_deviation`, `enable_overhang_speed`, `gap_infill_speed`, `infill_jerk`, `initial_layer_acceleration`, `initial_layer_infill_speed`, `initial_layer_jerk`, `initial_layer_speed`, `initial_layer_travel_acceleration`, `initial_layer_travel_jerk`, `initial_layer_travel_speed`, `inner_wall_acceleration`, `inner_wall_jerk`, `inner_wall_speed`, `internal_bridge_speed`, `internal_solid_infill_acceleration`, `internal_solid_infill_speed`, `outer_wall_acceleration`, `outer_wall_jerk`, `outer_wall_speed`, `overhang_1_4_speed`, `overhang_2_4_speed`, `overhang_3_4_speed`, `overhang_4_4_speed`, `print_extruder_id`, `print_extruder_variant`, `slowdown_for_curled_perimeters`, `small_perimeter_speed`, `small_perimeter_threshold`, `sparse_infill_acceleration`, `sparse_infill_speed`, `support_interface_speed`, `support_speed`, `top_solid_infill_flow_ratio`, `top_surface_acceleration`, `top_surface_jerk`, `top_surface_speed`, `travel_acceleration`, `travel_jerk`, `travel_speed`, `travel_speed_z`
|
||||||
|
|
||||||
**`filament_options_with_variant`**, filament, stride 1 (54): `activate_air_filtration`, `activate_air_filtration_during_print`, `activate_air_filtration_on_completion`, `adaptive_pressure_advance`, `adaptive_pressure_advance_bridges`, `adaptive_pressure_advance_model`, `adaptive_pressure_advance_overhangs`, `complete_print_exhaust_fan_speed`, `during_print_exhaust_fan_speed`, `enable_pressure_advance`, `filament_adaptive_volumetric_speed`, `filament_cooling_before_tower`, `filament_deretraction_speed`, `filament_extruder_variant`, `filament_flow_ratio`, `filament_flush_temp`, `filament_flush_volumetric_speed`, `filament_ironing_flow`, `filament_ironing_inset`, `filament_ironing_spacing`, `filament_ironing_speed`, `filament_long_retractions_when_cut`, `filament_max_volumetric_speed`, `filament_pre_cooling_temperature`, `filament_pre_cooling_temperature_nc`, `filament_preheat_temperature_delta`, `filament_ramming_travel_time`, `filament_ramming_travel_time_nc`, `filament_ramming_volumetric_speed`, `filament_ramming_volumetric_speed_nc`, `filament_retract_after_wipe`, `filament_retract_before_wipe`, `filament_retract_length_nc`, `filament_retract_length_toolchange`, `filament_retract_lift_above`, `filament_retract_lift_below`, `filament_retract_lift_enforce`, `filament_retract_restart_extra`, `filament_retract_restart_extra_toolchange`, `filament_retract_when_changing_layer`, `filament_retraction_distances_when_cut`, `filament_retraction_length`, `filament_retraction_minimum_travel`, `filament_retraction_speed`, `filament_wipe`, `filament_wipe_distance`, `filament_z_hop`, `filament_z_hop_types`, `long_retractions_when_ec`, `nozzle_temperature`, `nozzle_temperature_initial_layer`, `pressure_advance`, `retraction_distances_when_ec`, `volumetric_speed_coefficients`
|
**`filament_options_with_variant`**, filament, stride 1 (48): `activate_air_filtration`, `activate_air_filtration_during_print`, `activate_air_filtration_on_completion`, `complete_print_exhaust_fan_speed`, `during_print_exhaust_fan_speed`, `filament_adaptive_volumetric_speed`, `filament_cooling_before_tower`, `filament_deretraction_speed`, `filament_extruder_variant`, `filament_flow_ratio`, `filament_flush_temp`, `filament_flush_volumetric_speed`, `filament_ironing_flow`, `filament_ironing_inset`, `filament_ironing_spacing`, `filament_ironing_speed`, `filament_long_retractions_when_cut`, `filament_max_volumetric_speed`, `filament_pre_cooling_temperature`, `filament_pre_cooling_temperature_nc`, `filament_preheat_temperature_delta`, `filament_ramming_travel_time`, `filament_ramming_travel_time_nc`, `filament_ramming_volumetric_speed`, `filament_ramming_volumetric_speed_nc`, `filament_retract_after_wipe`, `filament_retract_before_wipe`, `filament_retract_length_nc`, `filament_retract_length_toolchange`, `filament_retract_lift_above`, `filament_retract_lift_below`, `filament_retract_lift_enforce`, `filament_retract_restart_extra`, `filament_retract_restart_extra_toolchange`, `filament_retract_when_changing_layer`, `filament_retraction_distances_when_cut`, `filament_retraction_length`, `filament_retraction_minimum_travel`, `filament_retraction_speed`, `filament_wipe`, `filament_wipe_distance`, `filament_z_hop`, `filament_z_hop_types`, `long_retractions_when_ec`, `nozzle_temperature`, `nozzle_temperature_initial_layer`, `retraction_distances_when_ec`, `volumetric_speed_coefficients`
|
||||||
|
|
||||||
**`printer_extruder_options`**, machine, one value per extruder, not a variant set (8):
|
**`printer_extruder_options`**, machine, one value per extruder, not a variant set (8):
|
||||||
`default_nozzle_volume_type`, `extruder_max_nozzle_count`, `extruder_printable_area`,
|
`default_nozzle_volume_type`, `extruder_max_nozzle_count`, `extruder_printable_area`,
|
||||||
|
|||||||
@@ -244,10 +244,10 @@ preset for a 0.2 nozzle, explicitly revisit flow limits; do not infer a pressure
|
|||||||
required direction of change, from diameter alone.
|
required direction of change, from diameter alone.
|
||||||
|
|
||||||
On a printer with extruder variants, a filament tunes these per variant too:
|
On a printer with extruder variants, a filament tunes these per variant too:
|
||||||
`filament_max_volumetric_speed`, `filament_flow_ratio`, `nozzle_temperature`, pressure advance and the
|
`filament_max_volumetric_speed`, `filament_flow_ratio`, `nozzle_temperature` and the retraction
|
||||||
retraction overrides carry one value per variant of `filament_extruder_variant` (Standard, High Flow, …). The
|
overrides carry one value per variant of `filament_extruder_variant` (Standard, High Flow, …). The
|
||||||
exact key set is [`filament_options_with_variant`](extruder-variants.md#the-four-key-sets);
|
exact key set is [`filament_options_with_variant`](extruder-variants.md#the-four-key-sets);
|
||||||
`slow_down_min_speed` and `fan_max_speed` are not in it. Keep every such array at exactly that width, even where the
|
`slow_down_min_speed` and `pressure_advance` are not in it. Keep every such array at exactly that width, even where the
|
||||||
setting does not differ per variant, and measure the High Flow variant rather than copying Standard
|
setting does not differ per variant, and measure the High Flow variant rather than copying Standard
|
||||||
([extruder-variants.md](extruder-variants.md#filament)).
|
([extruder-variants.md](extruder-variants.md#filament)).
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "OrcaFilamentLibrary",
|
"name": "OrcaFilamentLibrary",
|
||||||
"version": "02.04.00.16",
|
"version": "02.04.00.15",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Orca Filament Library",
|
"description": "Orca Filament Library",
|
||||||
"filament_list": [
|
"filament_list": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
+30
-129
@@ -214,9 +214,9 @@ function ShowModelInfo( pModel )
|
|||||||
|
|
||||||
SendWXDebugInfo("Model Name: "+sModelName);
|
SendWXDebugInfo("Model Name: "+sModelName);
|
||||||
|
|
||||||
$('#ModelName').text(sModelName);
|
$('#ModelName').html(sModelName);
|
||||||
$('#ModelName').attr('title',sModelName);
|
$('#ModelName').attr('title',sModelName);
|
||||||
$('#ModelAuthorName').text(sModelAuthor);
|
$('#ModelAuthorName').html(sModelAuthor);
|
||||||
|
|
||||||
switch(UploadType)
|
switch(UploadType)
|
||||||
{
|
{
|
||||||
@@ -268,7 +268,7 @@ function ShowModelInfo( pModel )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#Model_Desc').empty().append( SanitizeDescHtml( html_decode(sModelDesc) ) );
|
$('#Model_Desc').html( html_decode(sModelDesc) );
|
||||||
|
|
||||||
let ModelPreviewList=pModel.preview_img;
|
let ModelPreviewList=pModel.preview_img;
|
||||||
let TotalPreview=ModelPreviewList.length;
|
let TotalPreview=ModelPreviewList.length;
|
||||||
@@ -281,15 +281,16 @@ function ShowModelInfo( pModel )
|
|||||||
|
|
||||||
if(TotalPreview>0)
|
if(TotalPreview>0)
|
||||||
{
|
{
|
||||||
$('#ModelPreviewList').empty();
|
let htmlPreview='';
|
||||||
for(let pn=0;pn<TotalPreview;pn++)
|
for(let pn=0;pn<TotalPreview;pn++)
|
||||||
{
|
{
|
||||||
//let FTmpPath=decodeURIComponent(ModelPreviewList[pn]);
|
//let FTmpPath=decodeURIComponent(ModelPreviewList[pn]);
|
||||||
let FTmpPath=ModelPreviewList[pn]['filepath'];
|
let FTmpPath=ModelPreviewList[pn]['filepath'];
|
||||||
|
|
||||||
$('#ModelPreviewList').append( $('<div class="swiper-slide"></div>').append( $('<img class="Model_PrevImg" />').attr('src',FTmpPath) ) );
|
htmlPreview+='<div class="swiper-slide"><img class="Model_PrevImg" src="'+FTmpPath+'" /></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('#ModelPreviewList').html(htmlPreview);
|
||||||
$('#Model_Preview_Image').viewer({
|
$('#Model_Preview_Image').viewer({
|
||||||
title: false,
|
title: false,
|
||||||
fullsreen: false,
|
fullsreen: false,
|
||||||
@@ -409,8 +410,7 @@ function ConstructFileHtml( ID, pItem )
|
|||||||
{
|
{
|
||||||
let fTotal=pItem.length;
|
let fTotal=pItem.length;
|
||||||
|
|
||||||
let pBoard=$('#'+ID+' .FileListBoard');
|
let strHtml='';
|
||||||
pBoard.empty();
|
|
||||||
for( let f=0;f<fTotal;f++ )
|
for( let f=0;f<fTotal;f++ )
|
||||||
{
|
{
|
||||||
let pOne=pItem[f];
|
let pOne=pItem[f];
|
||||||
@@ -443,139 +443,39 @@ function ConstructFileHtml( ID, pItem )
|
|||||||
ImgPath='img/default.png';
|
ImgPath='img/default.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add html. File names come from the 3MF, so build the nodes rather than concatenating markup.
|
//Add html
|
||||||
let pIconImg=$('<img />').attr('src',ImgPath);
|
|
||||||
let pMenu=$('<div class="FileMenu"><img src="img/s.svg" /></div>');
|
|
||||||
if( strClass!='ImageIcon' )
|
if( strClass!='ImageIcon' )
|
||||||
{
|
{
|
||||||
pMenu.on('click', function(){ OnClickOpenFile(tPath); });
|
strHtml+='<div class="FileItem">'+
|
||||||
|
' <div class="'+strClass+'"><img src="'+ImgPath+'" /></div>'+
|
||||||
|
' <div class="FileText">'+
|
||||||
|
' <div class="FileName">'+tName+'</div>'+
|
||||||
|
' </div>'+
|
||||||
|
' <div class="FileMenu" onClick="OnClickOpenFile(\''+tPath+'\')"><img src="img/s.svg" /></div>'+
|
||||||
|
'</div>';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImgID++;
|
ImgID++;
|
||||||
let TmpImgID="AF"+ImgID;
|
let TmpImgID="AF"+ImgID;
|
||||||
|
|
||||||
pIconImg.attr('id',TmpImgID);
|
strHtml+='<div class="FileItem">'+
|
||||||
pMenu.on('click', function(){ OnClickOpenImage(TmpImgID); });
|
' <div class="'+strClass+'"><img id="'+TmpImgID+'" src="'+ImgPath+'" /></div>'+
|
||||||
|
' <div class="FileText">'+
|
||||||
|
' <div class="FileName">'+tName+'</div>'+
|
||||||
|
' </div>'+
|
||||||
|
' <div class="FileMenu" onClick="OnClickOpenImage(\''+TmpImgID+'\')"><img src="img/s.svg" /></div>'+
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pFileItem=$('<div class="FileItem"></div>');
|
$('#'+ID+' .FileListBoard').html(strHtml);
|
||||||
pFileItem.append( $('<div></div>').addClass(strClass).append(pIconImg) );
|
|
||||||
pFileItem.append( $('<div class="FileText"></div>').append( $('<div class="FileName"></div>').text(tName).attr('title',tName) ) );
|
|
||||||
pFileItem.append( pMenu );
|
|
||||||
pBoard.append( pFileItem );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( fTotal>0 )
|
if( fTotal>0 )
|
||||||
$('#'+ID).show();
|
$('#'+ID).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Descriptions are untrusted 3MF metadata that may carry rich-text HTML (e.g. from MakerWorld).
|
|
||||||
// Rebuild them from an inert parse, keeping only plain formatting tags and http(s) links and images.
|
|
||||||
var DescAllowedTags=['P','BR','B','STRONG','I','EM','U','S','STRIKE','DEL','INS','SUB','SUP','SMALL','MARK',
|
|
||||||
'Q','ABBR','KBD','WBR','H1','H2','H3','H4','H5','H6','UL','OL','LI','DL','DT','DD','BLOCKQUOTE','PRE','CODE',
|
|
||||||
'HR','SPAN','DIV','FIGURE','FIGCAPTION','TABLE','CAPTION','THEAD','TBODY','TFOOT','TR','TH','TD','A','IMG'];
|
|
||||||
// Plain attributes kept per tag; the numeric ones must be plain non-negative integers.
|
|
||||||
var DescAllowedAttrs={'IMG':['alt','title','width','height'],'TD':['colspan','rowspan'],'TH':['colspan','rowspan'],'OL':['start']};
|
|
||||||
var DescNumericAttrs=['width','height','colspan','rowspan','start'];
|
|
||||||
// Dropped together with their content; any other unknown tag is unwrapped to its children.
|
|
||||||
var DescDroppedTags=['SCRIPT','STYLE','TEMPLATE','NOSCRIPT','TEXTAREA','TITLE','IFRAME','FRAME','OBJECT','EMBED','SVG','MATH'];
|
|
||||||
|
|
||||||
function IsHttpUrl( strUrl )
|
|
||||||
{
|
|
||||||
// The scheme must be written as is, so nothing the URL parser would strip can precede or split it.
|
|
||||||
if( typeof strUrl!='string' || !/^https?:/i.test(strUrl) )
|
|
||||||
return false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
let sProtocol=new URL(strUrl).protocol;
|
|
||||||
return sProtocol=='http:' || sProtocol=='https:';
|
|
||||||
}
|
|
||||||
catch(e)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Images load as soon as the page opens, so only https sources are kept: no plain-http requests to the local network.
|
|
||||||
function IsHttpsUrl( strUrl )
|
|
||||||
{
|
|
||||||
return IsHttpUrl(strUrl) && new URL(strUrl).protocol=='https:';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Embedded YouTube players become a plain link to the video.
|
|
||||||
function GetYouTubeEmbedUrl( pNode )
|
|
||||||
{
|
|
||||||
let sSrc=pNode.getAttribute('src');
|
|
||||||
if( !IsHttpUrl(sSrc) )
|
|
||||||
return null;
|
|
||||||
let pUrl=new URL(sSrc);
|
|
||||||
return ( pUrl.origin=='https://www.youtube.com' && pUrl.pathname.indexOf('/embed/')==0 ) ? pUrl.href : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function CopyDescNodes( pSrc, pDst )
|
|
||||||
{
|
|
||||||
for( let pNode=pSrc.firstChild;pNode!=null;pNode=pNode.nextSibling )
|
|
||||||
{
|
|
||||||
if( pNode.nodeType==Node.TEXT_NODE )
|
|
||||||
{
|
|
||||||
pDst.appendChild( document.createTextNode(pNode.nodeValue) );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if( pNode.nodeType!=Node.ELEMENT_NODE )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let sTag=pNode.nodeName.toUpperCase();
|
|
||||||
if( sTag=='IFRAME' )
|
|
||||||
{
|
|
||||||
let sVideoUrl=GetYouTubeEmbedUrl(pNode);
|
|
||||||
if( sVideoUrl!=null )
|
|
||||||
{
|
|
||||||
let pLink=document.createElement('A');
|
|
||||||
pLink.setAttribute('href',sVideoUrl);
|
|
||||||
pLink.textContent=sVideoUrl;
|
|
||||||
pDst.appendChild(pLink);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if( $.inArray(sTag,DescDroppedTags)>=0 )
|
|
||||||
continue;
|
|
||||||
if( $.inArray(sTag,DescAllowedTags)<0 )
|
|
||||||
{
|
|
||||||
CopyDescNodes(pNode,pDst);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let pElem=document.createElement(sTag);
|
|
||||||
if( sTag=='A' && IsHttpUrl(pNode.getAttribute('href')) )
|
|
||||||
pElem.setAttribute('href',pNode.getAttribute('href'));
|
|
||||||
else if( sTag=='IMG' )
|
|
||||||
{
|
|
||||||
if( !IsHttpsUrl(pNode.getAttribute('src')) )
|
|
||||||
continue;
|
|
||||||
pElem.setAttribute('src',pNode.getAttribute('src'));
|
|
||||||
}
|
|
||||||
$.each( DescAllowedAttrs[sTag]||[], function(i,sAttr){
|
|
||||||
let sValue=pNode.getAttribute(sAttr);
|
|
||||||
if( sValue!=null && ( $.inArray(sAttr,DescNumericAttrs)<0 || /^\d+$/.test(sValue) ) )
|
|
||||||
pElem.setAttribute(sAttr,sValue);
|
|
||||||
});
|
|
||||||
CopyDescNodes(pNode,pElem);
|
|
||||||
pDst.appendChild(pElem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function SanitizeDescHtml( strHtml )
|
|
||||||
{
|
|
||||||
let pFragment=document.createDocumentFragment();
|
|
||||||
// A DOMParser document is inert: it runs no scripts and loads no resources.
|
|
||||||
let pDoc=new DOMParser().parseFromString(strHtml,'text/html');
|
|
||||||
if( pDoc && pDoc.body )
|
|
||||||
CopyDescNodes(pDoc.body,pFragment);
|
|
||||||
return pFragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ShowProfilelInfo( pProfile )
|
function ShowProfilelInfo( pProfile )
|
||||||
{
|
{
|
||||||
//==========Profile Info==========
|
//==========Profile Info==========
|
||||||
@@ -583,10 +483,10 @@ function ShowProfilelInfo( pProfile )
|
|||||||
let sProfileAuthor=decodeURIComponent(pProfile.author);
|
let sProfileAuthor=decodeURIComponent(pProfile.author);
|
||||||
let sProfileDesc=decodeURIComponent(pProfile.description);
|
let sProfileDesc=decodeURIComponent(pProfile.description);
|
||||||
|
|
||||||
$('#ProfileName').text(sProfileName);
|
$('#ProfileName').html(sProfileName);
|
||||||
$('#ProfileAuthor').text(sProfileAuthor);
|
$('#ProfileAuthor').html(sProfileAuthor);
|
||||||
|
|
||||||
$('#Profile_Desc').empty().append( SanitizeDescHtml( html_decode(sProfileDesc) ) );
|
$('#Profile_Desc').html( html_decode(sProfileDesc) );
|
||||||
|
|
||||||
let ProfilePreviewList=pProfile.preview_img;
|
let ProfilePreviewList=pProfile.preview_img;
|
||||||
let TotalPreview=ProfilePreviewList.length;
|
let TotalPreview=ProfilePreviewList.length;
|
||||||
@@ -599,14 +499,15 @@ function ShowProfilelInfo( pProfile )
|
|||||||
|
|
||||||
if(TotalPreview>0)
|
if(TotalPreview>0)
|
||||||
{
|
{
|
||||||
$('#ProfilePreviewList').empty();
|
let htmlPreview='';
|
||||||
for(let pn=0;pn<TotalPreview;pn++)
|
for(let pn=0;pn<TotalPreview;pn++)
|
||||||
{
|
{
|
||||||
let FTmpPath=ProfilePreviewList[pn]['filepath'];
|
let FTmpPath=ProfilePreviewList[pn]['filepath'];
|
||||||
|
|
||||||
$('#ProfilePreviewList').append( $('<div class="swiper-slide"></div>').append( $('<img class="Model_PrevImg" />').attr('src',FTmpPath) ) );
|
htmlPreview+='<div class="swiper-slide"><img class="Model_PrevImg" src="'+FTmpPath+'" /></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('#ProfilePreviewList').html(htmlPreview);
|
||||||
$('#Profile_Preview_Image').viewer({
|
$('#Profile_Preview_Image').viewer({
|
||||||
title: false,
|
title: false,
|
||||||
fullsreen: false,
|
fullsreen: false,
|
||||||
|
|||||||
@@ -3476,14 +3476,6 @@ int CLI::run(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
new_variant_counts = old_variant_counts;
|
new_variant_counts = old_variant_counts;
|
||||||
//filament_variant_count = old_variant_counts;
|
//filament_variant_count = old_variant_counts;
|
||||||
//ORCA: lay the per-variant options out one value per variant of the current filaments before each
|
|
||||||
// loaded filament replaces its own variants, including an option only a loaded filament
|
|
||||||
// defines, which otherwise starts as a single default value and never reaches the others.
|
|
||||||
for (const DynamicPrintConfig &config : load_filaments_config)
|
|
||||||
for (const std::string &opt_key : filament_options_with_variant)
|
|
||||||
if (opt_key != "filament_extruder_variant" && config.has(opt_key))
|
|
||||||
m_print_config.option(opt_key, true);
|
|
||||||
normalize_filament_values_to_variants(m_print_config);
|
|
||||||
for (int index = 0; index < load_filaments_config.size(); index++) {
|
for (int index = 0; index < load_filaments_config.size(); index++) {
|
||||||
DynamicPrintConfig& config = load_filaments_config[index];
|
DynamicPrintConfig& config = load_filaments_config[index];
|
||||||
int filament_index = load_filaments_index[index];
|
int filament_index = load_filaments_index[index];
|
||||||
@@ -3655,25 +3647,6 @@ int CLI::run(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ORCA: a per-variant option the loaded filament does not define keeps the values of the
|
|
||||||
// variants the filament already had, and a variant new to it takes its first one's.
|
|
||||||
const int old_start = old_start_indice[filament_index - 1];
|
|
||||||
std::vector<int> kept_variant_indice = new_variant_indice;
|
|
||||||
for (int &i : kept_variant_indice)
|
|
||||||
if (i < 0)
|
|
||||||
i = old_start;
|
|
||||||
for (const std::string &opt_key : filament_options_with_variant) {
|
|
||||||
if (config.has(opt_key))
|
|
||||||
continue;
|
|
||||||
auto *opt_vec_dst = dynamic_cast<ConfigOptionVectorBase *>(m_print_config.option(opt_key));
|
|
||||||
if (opt_vec_dst == nullptr || opt_vec_dst->size() < size_t(old_start + old_variant_count))
|
|
||||||
continue;
|
|
||||||
// set_with_restore_2() pads its source in place
|
|
||||||
std::unique_ptr<ConfigOption> old_values(opt_vec_dst->clone());
|
|
||||||
opt_vec_dst->set_with_restore_2(static_cast<ConfigOptionVectorBase *>(old_values.get()), kept_variant_indice, old_start,
|
|
||||||
old_variant_count, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//update the old index
|
//update the old index
|
||||||
if (old_variant_count != new_variant_count)
|
if (old_variant_count != new_variant_count)
|
||||||
{
|
{
|
||||||
@@ -4108,9 +4081,6 @@ int CLI::run(int argc, char **argv)
|
|||||||
if (printer_technology == ptFFF) {
|
if (printer_technology == ptFFF) {
|
||||||
fff_print_config.apply(m_print_config, true);
|
fff_print_config.apply(m_print_config, true);
|
||||||
m_print_config.apply(fff_print_config, true);
|
m_print_config.apply(fff_print_config, true);
|
||||||
//ORCA: an option no preset or project defines has just come in as its single default value, and a
|
|
||||||
// command line override may hold one value per filament.
|
|
||||||
normalize_filament_values_to_variants(m_print_config);
|
|
||||||
} else {
|
} else {
|
||||||
boost::nowide::cerr << "invalid printer_technology " << std::endl;
|
boost::nowide::cerr << "invalid printer_technology " << std::endl;
|
||||||
record_exit_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH], sliced_info);
|
record_exit_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH], sliced_info);
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
|
|||||||
its.indices.emplace_back(indices[0], indices[1], indices[2]);
|
its.indices.emplace_back(indices[0], indices[1], indices[2]);
|
||||||
int face_index =its.indices.size() - 1;
|
int face_index =its.indices.size() - 1;
|
||||||
RGBA face_color;
|
RGBA face_color;
|
||||||
auto set_face_color = [&uvs, &data, &mtl_data, &obj_info, &face_color](int face_index, const std::string mtl_name, const std::array<int, 3> &corners) {
|
auto set_face_color = [&uvs, &data, &mtl_data, &obj_info, &face_color](int face_index, const std::string mtl_name) {
|
||||||
if (mtl_data.new_mtl_unmap.find(mtl_name) != mtl_data.new_mtl_unmap.end()) {
|
if (mtl_data.new_mtl_unmap.find(mtl_name) != mtl_data.new_mtl_unmap.end()) {
|
||||||
bool is_merge_ka_kd = true;
|
bool is_merge_ka_kd = true;
|
||||||
for (size_t n = 0; n < 3; n++) {
|
for (size_t n = 0; n < 3; n++) {
|
||||||
@@ -174,7 +174,7 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
|
|||||||
return Vec2f::Zero();
|
return Vec2f::Zero();
|
||||||
return Vec2f(data.textureCoordinates[idx * OBJ_TEXCOORD_LENGTH], data.textureCoordinates[idx * OBJ_TEXCOORD_LENGTH + 1]);
|
return Vec2f(data.textureCoordinates[idx * OBJ_TEXCOORD_LENGTH], data.textureCoordinates[idx * OBJ_TEXCOORD_LENGTH + 1]);
|
||||||
};
|
};
|
||||||
std::array<Vec2f, 3> uv_array{uv_at(uvs[corners[0]]), uv_at(uvs[corners[1]]), uv_at(uvs[corners[2]])};
|
std::array<Vec2f, 3> uv_array{uv_at(uvs[0]), uv_at(uvs[1]), uv_at(uvs[2])};
|
||||||
obj_info.uvs.emplace_back(uv_array);
|
obj_info.uvs.emplace_back(uv_array);
|
||||||
}
|
}
|
||||||
obj_info.face_colors.emplace_back(face_color);
|
obj_info.face_colors.emplace_back(face_color);
|
||||||
@@ -185,27 +185,27 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
auto set_face_color_by_mtl = [&data, &set_face_color](int face_index, const std::array<int, 3> &corners) {
|
auto set_face_color_by_mtl = [&data, &set_face_color](int face_index) {
|
||||||
if (data.usemtls.size() == 1) {
|
if (data.usemtls.size() == 1) {
|
||||||
set_face_color(face_index, data.usemtls[0].name, corners);
|
set_face_color(face_index, data.usemtls[0].name);
|
||||||
} else {
|
} else {
|
||||||
for (size_t k = 0; k < data.usemtls.size(); k++) {
|
for (size_t k = 0; k < data.usemtls.size(); k++) {
|
||||||
auto mtl = data.usemtls[k];
|
auto mtl = data.usemtls[k];
|
||||||
if (face_index >= mtl.face_start && face_index <= mtl.face_end) {
|
if (face_index >= mtl.face_start && face_index <= mtl.face_end) {
|
||||||
set_face_color(face_index, data.usemtls[k].name, corners);
|
set_face_color(face_index, data.usemtls[k].name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (exist_mtl) {
|
if (exist_mtl) {
|
||||||
set_face_color_by_mtl(face_index, {0, 1, 2});
|
set_face_color_by_mtl(face_index);
|
||||||
}
|
}
|
||||||
if (cnt == 4) {
|
if (cnt == 4) {
|
||||||
its.indices.emplace_back(indices[0], indices[2], indices[3]);
|
its.indices.emplace_back(indices[0], indices[2], indices[3]);
|
||||||
int face_index = its.indices.size() - 1;
|
int face_index = its.indices.size() - 1;
|
||||||
if (exist_mtl) {
|
if (exist_mtl) {
|
||||||
set_face_color_by_mtl(face_index, {0, 2, 3});
|
set_face_color_by_mtl(face_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,12 +217,8 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
|
|||||||
message = _L("This OBJ file couldn't be read because it's empty.");
|
message = _L("This OBJ file couldn't be read because it's empty.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (meshptr->volume() < 0) {
|
if (meshptr->volume() < 0)
|
||||||
meshptr->flip_triangles();
|
meshptr->flip_triangles();
|
||||||
// Flipping swaps corners 1 and 2 of every face, so the UVs have to follow.
|
|
||||||
for (std::array<Vec2f, 3> &uv : obj_info.uvs)
|
|
||||||
std::swap(uv[1], uv[2]);
|
|
||||||
}
|
|
||||||
// Hand the parsed material table back so callers can build a TexturedMesh from it.
|
// Hand the parsed material table back so callers can build a TexturedMesh from it.
|
||||||
if (out_mtl)
|
if (out_mtl)
|
||||||
*out_mtl = mtl_data;
|
*out_mtl = mtl_data;
|
||||||
|
|||||||
+68
-48
@@ -1497,7 +1497,12 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
|||||||
check_add_eol(toolchange_gcode_str);
|
check_add_eol(toolchange_gcode_str);
|
||||||
|
|
||||||
// SoftFever: set new PA for new filament
|
// SoftFever: set new PA for new filament
|
||||||
gcode += gcodegen.set_filament_pressure_advance(new_filament_id);
|
if (gcodegen.config().enable_pressure_advance.get_at(new_filament_id)) {
|
||||||
|
gcode += gcodegen.writer().set_pressure_advance(gcodegen.config().pressure_advance.get_at(new_filament_id));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
gcodegen.m_pa_processor->resetPreviousPA(gcodegen.config().pressure_advance.get_at(new_filament_id));
|
||||||
|
}
|
||||||
|
|
||||||
// A phony move to the end position at the wipe tower.
|
// A phony move to the end position at the wipe tower.
|
||||||
gcodegen.writer().travel_to_xy((end_pos + plate_origin_2d).cast<double>());
|
gcodegen.writer().travel_to_xy((end_pos + plate_origin_2d).cast<double>());
|
||||||
@@ -1821,8 +1826,12 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
|||||||
check_add_eol(toolchange_gcode_str);
|
check_add_eol(toolchange_gcode_str);
|
||||||
|
|
||||||
// SoftFever: set new PA for new filament
|
// SoftFever: set new PA for new filament
|
||||||
if (new_extruder_id != -1)
|
if (new_extruder_id != -1 && gcodegen.config().enable_pressure_advance.get_at(new_extruder_id)) {
|
||||||
gcode += gcodegen.set_filament_pressure_advance(new_extruder_id);
|
gcode += gcodegen.writer().set_pressure_advance(gcodegen.config().pressure_advance.get_at(new_extruder_id));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
gcodegen.m_pa_processor->resetPreviousPA(gcodegen.config().pressure_advance.get_at(new_extruder_id));
|
||||||
|
}
|
||||||
|
|
||||||
// A phony move to the end position at the wipe tower.
|
// A phony move to the end position at the wipe tower.
|
||||||
gcodegen.writer().travel_to_xy((end_pos + plate_origin_2d).cast<double>());
|
gcodegen.writer().travel_to_xy((end_pos + plate_origin_2d).cast<double>());
|
||||||
@@ -3223,7 +3232,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
m_cooling_buffer->set_current_extruder(initial_extruder_id, extruder_id);
|
m_cooling_buffer->set_current_extruder(initial_extruder_id, extruder_id);
|
||||||
|
|
||||||
// Orca: Initialise AdaptivePA processor filter
|
// Orca: Initialise AdaptivePA processor filter
|
||||||
m_pa_processor = std::make_unique<AdaptivePAProcessor>(*this);
|
m_pa_processor = std::make_unique<AdaptivePAProcessor>(*this, tool_ordering.all_extruders());
|
||||||
|
|
||||||
// Update output variables after the extruders were initialized.
|
// Update output variables after the extruders were initialized.
|
||||||
m_placeholder_parser_integration.init(m_writer);
|
m_placeholder_parser_integration.init(m_writer);
|
||||||
@@ -3788,7 +3797,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Orca: add missing PA settings for initial filament
|
// Orca: add missing PA settings for initial filament
|
||||||
file.write(set_filament_pressure_advance(initial_non_support_extruder_id));
|
if (m_config.enable_pressure_advance.get_at(initial_non_support_extruder_id)) {
|
||||||
|
file.write(m_writer.set_pressure_advance(m_config.pressure_advance.get_at(initial_non_support_extruder_id)));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(initial_non_support_extruder_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//flush FanMover buffer to avoid modifying the start gcode if it's manual.
|
//flush FanMover buffer to avoid modifying the start gcode if it's manual.
|
||||||
@@ -8376,16 +8390,12 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
|
|
||||||
// Orca: Dynamic PA
|
// Orca: Dynamic PA
|
||||||
// If adaptive PA is enabled, by default evaluate PA on all extrusion moves
|
// If adaptive PA is enabled, by default evaluate PA on all extrusion moves
|
||||||
// The PA settings and the PA_CHANGE tags use the filament config index of the filament's extruder variant
|
|
||||||
const unsigned int pa_config_index = (unsigned int) get_filament_config_index(m_writer.filament()->id());
|
|
||||||
const bool adaptive_pa = m_config.adaptive_pressure_advance.get_at(pa_config_index) && m_config.enable_pressure_advance.get_at(pa_config_index);
|
|
||||||
const bool adaptive_pa_overhangs = adaptive_pa && m_config.adaptive_pressure_advance_overhangs.get_at(pa_config_index);
|
|
||||||
bool is_pa_calib = m_curr_print->calib_mode() == CalibMode::Calib_PA_Line ||
|
bool is_pa_calib = m_curr_print->calib_mode() == CalibMode::Calib_PA_Line ||
|
||||||
m_curr_print->calib_mode() == CalibMode::Calib_PA_Pattern ||
|
m_curr_print->calib_mode() == CalibMode::Calib_PA_Pattern ||
|
||||||
m_curr_print->calib_mode() == CalibMode::Calib_PA_Tower;
|
m_curr_print->calib_mode() == CalibMode::Calib_PA_Tower;
|
||||||
bool evaluate_adaptive_pa = false;
|
bool evaluate_adaptive_pa = false;
|
||||||
bool role_change = (m_last_extrusion_role != path.role());
|
bool role_change = (m_last_extrusion_role != path.role());
|
||||||
if (!is_pa_calib && adaptive_pa) {
|
if (!is_pa_calib && FILAMENT_CONFIG(adaptive_pressure_advance) && FILAMENT_CONFIG(enable_pressure_advance)) {
|
||||||
evaluate_adaptive_pa = true;
|
evaluate_adaptive_pa = true;
|
||||||
// If we have already emmited a PA change because the m_multi_flow_segment_path_pa_set is set
|
// If we have already emmited a PA change because the m_multi_flow_segment_path_pa_set is set
|
||||||
// skip re-issuing the PA change tag.
|
// skip re-issuing the PA change tag.
|
||||||
@@ -8468,7 +8478,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
// Post processor flag generation code segment when option to emit only at role changes is enabled
|
// Post processor flag generation code segment when option to emit only at role changes is enabled
|
||||||
// Variables published to the post processor:
|
// Variables published to the post processor:
|
||||||
// 1) Tag to trigger a PA evaluation (because a role change was identified and the user has requested dynamic PA adjustments)
|
// 1) Tag to trigger a PA evaluation (because a role change was identified and the user has requested dynamic PA adjustments)
|
||||||
// 2) Current filament config index (to identify the PA model for the currently used filament and its extruder variant)
|
// 2) Current extruder ID (to identify the PA model for the currently used extruder)
|
||||||
// 3) mm3_per_mm value (to then multiply by the final model print speed after slowdown for cooling is applied)
|
// 3) mm3_per_mm value (to then multiply by the final model print speed after slowdown for cooling is applied)
|
||||||
// 4) the current acceleration (to pass to the model for evaluation)
|
// 4) the current acceleration (to pass to the model for evaluation)
|
||||||
// 5) whether this is an external perimeter (for future use)
|
// 5) whether this is an external perimeter (for future use)
|
||||||
@@ -8479,7 +8489,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
if (m_multi_flow_segment_path_average_mm3_per_mm > 0) {
|
if (m_multi_flow_segment_path_average_mm3_per_mm > 0) {
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
m_multi_flow_segment_path_average_mm3_per_mm,
|
m_multi_flow_segment_path_average_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8492,7 +8502,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
// to issue a zero flow PA change command for this
|
// to issue a zero flow PA change command for this
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8600,7 +8610,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
// or a flow change, so emit the flag to evaluate PA for the upcomming extrusion
|
// or a flow change, so emit the flag to evaluate PA for the upcomming extrusion
|
||||||
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
||||||
// Dont emit tag if it has just already been emitted from a role change above
|
// Dont emit tag if it has just already been emitted from a role change above
|
||||||
if(_mm3_per_mm >0 && adaptive_pa_overhangs && !evaluate_adaptive_pa){
|
if(_mm3_per_mm >0 &&
|
||||||
|
FILAMENT_CONFIG(adaptive_pressure_advance) &&
|
||||||
|
FILAMENT_CONFIG(enable_pressure_advance) &&
|
||||||
|
FILAMENT_CONFIG(adaptive_pressure_advance_overhangs) &&
|
||||||
|
!evaluate_adaptive_pa){
|
||||||
if(writer().get_current_speed() > F){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
if(writer().get_current_speed() > F){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
||||||
if(m_config.gcode_comments){
|
if(m_config.gcode_comments){
|
||||||
sprintf(buf, "; Ramp down-non-variable\n");
|
sprintf(buf, "; Ramp down-non-variable\n");
|
||||||
@@ -8608,7 +8622,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
}
|
}
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8623,7 +8637,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
}
|
}
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8829,7 +8843,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
// ORCA: Adaptive PA code segment when adjusting PA within the same feature
|
// ORCA: Adaptive PA code segment when adjusting PA within the same feature
|
||||||
// There is a speed change or flow change so emit the flag to evaluate PA for the upcomming extrusion
|
// There is a speed change or flow change so emit the flag to evaluate PA for the upcomming extrusion
|
||||||
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
||||||
if(_mm3_per_mm >0 && adaptive_pa_overhangs){
|
if(_mm3_per_mm >0 &&
|
||||||
|
EXTRUDER_CONFIG(adaptive_pressure_advance) &&
|
||||||
|
EXTRUDER_CONFIG(enable_pressure_advance) &&
|
||||||
|
EXTRUDER_CONFIG(adaptive_pressure_advance_overhangs) ){
|
||||||
if(last_set_speed > new_speed){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
if(last_set_speed > new_speed){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
||||||
if(m_config.gcode_comments) {
|
if(m_config.gcode_comments) {
|
||||||
sprintf(buf, "; Ramp up-variable\n");
|
sprintf(buf, "; Ramp up-variable\n");
|
||||||
@@ -8837,7 +8854,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
}
|
}
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8852,7 +8869,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
}
|
}
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -9405,29 +9422,33 @@ void GCode::update_placeholder_parser_with_variant_params()
|
|||||||
if (num_filaments == 0)
|
if (num_filaments == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Helper: remap config arrays from variant index space to filament_id index space.
|
// Helpers: remap config arrays from variant index space to filament_id index space.
|
||||||
// After remapping, gcode templates can use param[filament_id] directly.
|
// After remapping, gcode templates can use param[filament_id] directly.
|
||||||
auto remap_by_filament = [&](const auto &src) {
|
auto remap_floats_by_filament = [&](const auto &src) {
|
||||||
std::decay_t<decltype(src.values)> dst(num_filaments);
|
std::vector<double> dst(num_filaments);
|
||||||
|
for (size_t i = 0; i < num_filaments; ++i)
|
||||||
|
dst[i] = src.get_at(get_filament_config_index(i));
|
||||||
|
return dst;
|
||||||
|
};
|
||||||
|
auto remap_ints_by_filament = [&](const auto &src) {
|
||||||
|
std::vector<int> dst(num_filaments);
|
||||||
for (size_t i = 0; i < num_filaments; ++i)
|
for (size_t i = 0; i < num_filaments; ++i)
|
||||||
dst[i] = src.get_at(get_filament_config_index(i));
|
dst[i] = src.get_at(get_filament_config_index(i));
|
||||||
return dst;
|
return dst;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- filament_options_with_variant: gcode indexes by filament_id ---
|
// --- filament_options_with_variant: gcode indexes by filament_id ---
|
||||||
this->placeholder_parser().set("filament_max_volumetric_speed", new ConfigOptionFloats(remap_by_filament(m_config.filament_max_volumetric_speed)));
|
this->placeholder_parser().set("filament_max_volumetric_speed", new ConfigOptionFloats(remap_floats_by_filament(m_config.filament_max_volumetric_speed)));
|
||||||
this->placeholder_parser().set("filament_pre_cooling_temperature", new ConfigOptionInts(remap_by_filament(m_config.filament_pre_cooling_temperature)));
|
this->placeholder_parser().set("filament_pre_cooling_temperature", new ConfigOptionInts(remap_ints_by_filament(m_config.filament_pre_cooling_temperature)));
|
||||||
this->placeholder_parser().set("filament_pre_cooling_temperature_nc", new ConfigOptionInts(remap_by_filament(m_config.filament_pre_cooling_temperature_nc)));
|
this->placeholder_parser().set("filament_pre_cooling_temperature_nc", new ConfigOptionInts(remap_ints_by_filament(m_config.filament_pre_cooling_temperature_nc)));
|
||||||
this->placeholder_parser().set("filament_cooling_before_tower", new ConfigOptionFloats(remap_by_filament(m_config.filament_cooling_before_tower)));
|
this->placeholder_parser().set("filament_cooling_before_tower", new ConfigOptionFloats(remap_floats_by_filament(m_config.filament_cooling_before_tower)));
|
||||||
this->placeholder_parser().set("nozzle_temperature_initial_layer", new ConfigOptionInts(remap_by_filament(m_config.nozzle_temperature_initial_layer)));
|
this->placeholder_parser().set("nozzle_temperature_initial_layer", new ConfigOptionInts(remap_ints_by_filament(m_config.nozzle_temperature_initial_layer)));
|
||||||
this->placeholder_parser().set("nozzle_temperature", new ConfigOptionInts(remap_by_filament(m_config.nozzle_temperature)));
|
this->placeholder_parser().set("nozzle_temperature", new ConfigOptionInts(remap_ints_by_filament(m_config.nozzle_temperature)));
|
||||||
// first_layer_temperature is a legacy alias of nozzle_temperature_initial_layer
|
// first_layer_temperature is a legacy alias of nozzle_temperature_initial_layer
|
||||||
this->placeholder_parser().set("first_layer_temperature", new ConfigOptionInts(remap_by_filament(m_config.nozzle_temperature_initial_layer)));
|
this->placeholder_parser().set("first_layer_temperature", new ConfigOptionInts(remap_ints_by_filament(m_config.nozzle_temperature_initial_layer)));
|
||||||
this->placeholder_parser().set("pressure_advance", new ConfigOptionFloats(remap_by_filament(m_config.pressure_advance)));
|
|
||||||
this->placeholder_parser().set("enable_pressure_advance", new ConfigOptionBools(remap_by_filament(m_config.enable_pressure_advance)));
|
|
||||||
|
|
||||||
// --- printer_options_with_variant_1: in m_config these are already merged as filament-indexed ---
|
// --- printer_options_with_variant_1: in m_config these are already merged as filament-indexed ---
|
||||||
this->placeholder_parser().set("retraction_distances_when_cut", new ConfigOptionFloats(remap_by_filament(m_config.retraction_distances_when_cut)));
|
this->placeholder_parser().set("retraction_distances_when_cut", new ConfigOptionFloats(remap_floats_by_filament(m_config.retraction_distances_when_cut)));
|
||||||
// hotend_cooling_rate / hotend_heating_rate: gcode uses [filament_map[x]-1] (extruder_id), no remap needed
|
// hotend_cooling_rate / hotend_heating_rate: gcode uses [filament_map[x]-1] (extruder_id), no remap needed
|
||||||
|
|
||||||
// --- filament_map: per-layer dynamic, sync from m_config to placeholder_parser ---
|
// --- filament_map: per-layer dynamic, sync from m_config to placeholder_parser ---
|
||||||
@@ -9437,9 +9458,9 @@ void GCode::update_placeholder_parser_with_variant_params()
|
|||||||
{
|
{
|
||||||
// Fast purge mode uses filament_flush_temp_fast; Default is inert.
|
// Fast purge mode uses filament_flush_temp_fast; Default is inert.
|
||||||
bool use_fast_flush = m_config.prime_volume_mode == PrimeVolumeMode::pvmFast;
|
bool use_fast_flush = m_config.prime_volume_mode == PrimeVolumeMode::pvmFast;
|
||||||
auto flush_v_speed = remap_by_filament(m_config.filament_flush_volumetric_speed);
|
auto flush_v_speed = remap_floats_by_filament(m_config.filament_flush_volumetric_speed);
|
||||||
auto filament_max_v = remap_by_filament(m_config.filament_max_volumetric_speed);
|
auto filament_max_v = remap_floats_by_filament(m_config.filament_max_volumetric_speed);
|
||||||
auto flush_temps = remap_by_filament(use_fast_flush ? m_config.filament_flush_temp_fast
|
auto flush_temps = remap_ints_by_filament(use_fast_flush ? m_config.filament_flush_temp_fast
|
||||||
: m_config.filament_flush_temp);
|
: m_config.filament_flush_temp);
|
||||||
for (size_t i = 0; i < num_filaments; ++i) {
|
for (size_t i = 0; i < num_filaments; ++i) {
|
||||||
if (flush_v_speed[i] == 0)
|
if (flush_v_speed[i] == 0)
|
||||||
@@ -9492,7 +9513,12 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
|||||||
gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, new_filament_id, &config);
|
gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, new_filament_id, &config);
|
||||||
check_add_eol(gcode);
|
check_add_eol(gcode);
|
||||||
}
|
}
|
||||||
gcode += set_filament_pressure_advance(new_filament_id);
|
if (m_config.enable_pressure_advance.get_at(new_filament_id)) {
|
||||||
|
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(new_filament_id));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(new_filament_id));
|
||||||
|
}
|
||||||
|
|
||||||
gcode += m_writer.toolchange(new_filament_id, new_extruder_id);
|
gcode += m_writer.toolchange(new_filament_id, new_extruder_id);
|
||||||
if (Extruder *fil = m_writer.filament())
|
if (Extruder *fil = m_writer.filament())
|
||||||
@@ -9883,24 +9909,18 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
|||||||
if (m_ooze_prevention.enable && !defer_temp_wait)
|
if (m_ooze_prevention.enable && !defer_temp_wait)
|
||||||
gcode += m_ooze_prevention.post_toolchange(*this);
|
gcode += m_ooze_prevention.post_toolchange(*this);
|
||||||
|
|
||||||
gcode += set_filament_pressure_advance(new_filament_id);
|
if (m_config.enable_pressure_advance.get_at(new_filament_id)) {
|
||||||
|
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(new_filament_id));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(new_filament_id));
|
||||||
|
}
|
||||||
//Orca: tool changer or IDEX's firmware may change Z position, so we set it to unknown/undefined
|
//Orca: tool changer or IDEX's firmware may change Z position, so we set it to unknown/undefined
|
||||||
m_last_pos_defined = false;
|
m_last_pos_defined = false;
|
||||||
|
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GCode::set_filament_pressure_advance(unsigned int filament_id)
|
|
||||||
{
|
|
||||||
const size_t fi = get_filament_config_index(filament_id);
|
|
||||||
if (!m_config.enable_pressure_advance.get_at(fi))
|
|
||||||
return {};
|
|
||||||
// Orca: Adaptive PA
|
|
||||||
// Reset Adaptive PA processor last PA value
|
|
||||||
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(fi));
|
|
||||||
return m_writer.set_pressure_advance(m_config.pressure_advance.get_at(fi));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string polygon_to_string(const Polygon &polygon, Print *print, bool is_print_space = false) {
|
inline std::string polygon_to_string(const Polygon &polygon, Print *print, bool is_print_space = false) {
|
||||||
std::ostringstream gcode;
|
std::ostringstream gcode;
|
||||||
gcode << "[";
|
gcode << "[";
|
||||||
|
|||||||
@@ -281,8 +281,6 @@ public:
|
|||||||
// extra_retract forwards a PETG pre-extrusion over-extrusion; default 0 -> identical to the plain deretract.
|
// extra_retract forwards a PETG pre-extrusion over-extrusion; default 0 -> identical to the plain deretract.
|
||||||
std::string unretract(float extra_retract = 0.f) { return m_writer.unlift() + m_writer.unretract(extra_retract); }
|
std::string unretract(float extra_retract = 0.f) { return m_writer.unlift() + m_writer.unretract(extra_retract); }
|
||||||
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1, bool defer_temp_wait = false);
|
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1, bool defer_temp_wait = false);
|
||||||
// Sets the pressure advance of the filament's extruder variant, if enabled for it.
|
|
||||||
std::string set_filament_pressure_advance(unsigned int filament_id);
|
|
||||||
bool is_BBL_Printer();
|
bool is_BBL_Printer();
|
||||||
WipeTowerType wipe_tower_type();
|
WipeTowerType wipe_tower_type();
|
||||||
|
|
||||||
|
|||||||
@@ -21,31 +21,39 @@ namespace Slic3r {
|
|||||||
*
|
*
|
||||||
* @param gcodegen A reference to the GCode object that generates the G-code.
|
* @param gcodegen A reference to the GCode object that generates the G-code.
|
||||||
*/
|
*/
|
||||||
AdaptivePAProcessor::AdaptivePAProcessor(GCode &gcodegen)
|
AdaptivePAProcessor::AdaptivePAProcessor(GCode &gcodegen, const std::vector<unsigned int> &tools_used)
|
||||||
: m_gcodegen(gcodegen),
|
: m_gcodegen(gcodegen),
|
||||||
m_config(gcodegen.config()),
|
m_config(gcodegen.config()),
|
||||||
m_last_predicted_pa(0.0),
|
m_last_predicted_pa(0.0),
|
||||||
m_max_next_feedrate(0.0),
|
m_max_next_feedrate(0.0),
|
||||||
m_next_feedrate(0.0),
|
m_next_feedrate(0.0),
|
||||||
m_current_feedrate(0.0),
|
m_current_feedrate(0.0),
|
||||||
m_last_config_index(-1),
|
m_last_extruder_id(-1),
|
||||||
m_pa_change_pattern(R"(; PA_CHANGE:T(\d+) MM3MM:([0-9]*\.[0-9]+) ACCEL:(\d+) BR:(\d+) RC:(\d+) OV:(\d+))"),
|
m_pa_change_pattern(R"(; PA_CHANGE:T(\d+) MM3MM:([0-9]*\.[0-9]+) ACCEL:(\d+) BR:(\d+) RC:(\d+) OV:(\d+))"),
|
||||||
m_g1_f_pattern(R"(G1 F([0-9]+))")
|
m_g1_f_pattern(R"(G1 F([0-9]+))")
|
||||||
{
|
{
|
||||||
|
// Constructor body can be used for further initialization if necessary
|
||||||
|
for (unsigned int tool : tools_used) {
|
||||||
|
// Only enable model for the tool if both PA and adaptive PA options are enabled
|
||||||
|
if(m_config.adaptive_pressure_advance.get_at(tool) && m_config.enable_pressure_advance.get_at(tool)){
|
||||||
|
auto interpolator = std::make_unique<AdaptivePAInterpolator>();
|
||||||
|
// Get calibration values from extruder
|
||||||
|
std::string pa_calibration_values = m_config.adaptive_pressure_advance_model.get_at(tool);
|
||||||
|
// Setup the model and store it in the tool-interpolation model map
|
||||||
|
interpolator->parseAndSetData(pa_calibration_values);
|
||||||
|
m_AdaptivePAInterpolators[tool] = std::move(interpolator);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to get the interpolator for a specific filament config index.
|
// Method to get the interpolator for a specific tool ID
|
||||||
// The model is built the first time an index is requested, as the indices in use depend on
|
AdaptivePAInterpolator* AdaptivePAProcessor::getInterpolator(unsigned int tool_id) {
|
||||||
// the extruder variant each filament prints with.
|
auto it = m_AdaptivePAInterpolators.find(tool_id);
|
||||||
AdaptivePAInterpolator* AdaptivePAProcessor::getInterpolator(unsigned int config_index) {
|
if (it != m_AdaptivePAInterpolators.end()) {
|
||||||
auto [it, inserted] = m_AdaptivePAInterpolators.try_emplace(config_index);
|
|
||||||
// Only enable model for the index if both PA and adaptive PA options are enabled
|
|
||||||
if (inserted && m_config.adaptive_pressure_advance.get_at(config_index) && m_config.enable_pressure_advance.get_at(config_index)) {
|
|
||||||
it->second = std::make_unique<AdaptivePAInterpolator>();
|
|
||||||
it->second->parseAndSetData(m_config.adaptive_pressure_advance_model.get_at(config_index));
|
|
||||||
}
|
|
||||||
return it->second.get();
|
return it->second.get();
|
||||||
}
|
}
|
||||||
|
return nullptr; // Handle the case where the tool_id was not found
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Processes a layer of G-code and applies adaptive pressure advance.
|
* @brief Processes a layer of G-code and applies adaptive pressure advance.
|
||||||
@@ -100,17 +108,16 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
|
|||||||
// the PA for that material is set. As no tag below will be found for this extruder, the original PA is retained.
|
// the PA for that material is set. As no tag below will be found for this extruder, the original PA is retained.
|
||||||
if (line.find("; PA_CHANGE") == 0) { // prune lines quickly before running regex check as regex is more expensive to run
|
if (line.find("; PA_CHANGE") == 0) { // prune lines quickly before running regex check as regex is more expensive to run
|
||||||
if (std::regex_search(line, m_match, m_pa_change_pattern)) {
|
if (std::regex_search(line, m_match, m_pa_change_pattern)) {
|
||||||
// The tag carries the filament config index, which selects the PA settings of the filament's extruder variant
|
int extruder_id = std::stoi(m_match[1].str());
|
||||||
int config_index = std::stoi(m_match[1].str());
|
|
||||||
mm3mm_value = std::stod(m_match[2].str());
|
mm3mm_value = std::stod(m_match[2].str());
|
||||||
accel_value = std::stod(m_match[3].str());
|
accel_value = std::stod(m_match[3].str());
|
||||||
int isBridge = std::stoi(m_match[4].str());
|
int isBridge = std::stoi(m_match[4].str());
|
||||||
int roleChange = std::stoi(m_match[5].str());
|
int roleChange = std::stoi(m_match[5].str());
|
||||||
int isOverhang = std::stoi(m_match[6].str());
|
int isOverhang = std::stoi(m_match[6].str());
|
||||||
|
|
||||||
// Check if the filament config index has changed
|
// Check if the extruder ID has changed
|
||||||
bool config_index_changed = (config_index != m_last_config_index);
|
bool extruder_changed = (extruder_id != m_last_extruder_id);
|
||||||
m_last_config_index = config_index;
|
m_last_extruder_id = extruder_id;
|
||||||
|
|
||||||
// Save the PA_CHANGE line to output later after finding feedrate
|
// Save the PA_CHANGE line to output later after finding feedrate
|
||||||
pa_change_line = line;
|
pa_change_line = line;
|
||||||
@@ -205,23 +212,23 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
|
|||||||
|
|
||||||
// Calculate the predicted PA using the upcomming feature maximum feedrate
|
// Calculate the predicted PA using the upcomming feature maximum feedrate
|
||||||
// Get the interpolator for the active tool
|
// Get the interpolator for the active tool
|
||||||
AdaptivePAInterpolator* interpolator = getInterpolator(m_last_config_index);
|
AdaptivePAInterpolator* interpolator = getInterpolator(m_last_extruder_id);
|
||||||
|
|
||||||
double predicted_pa = 0;
|
double predicted_pa = 0;
|
||||||
double adaptive_PA_speed = 0;
|
double adaptive_PA_speed = 0;
|
||||||
|
|
||||||
if(!interpolator){ // Tool not found in the interpolator map
|
if(!interpolator){ // Tool not found in the interpolator map
|
||||||
// Tool not found in the PA interpolator to tool map
|
// Tool not found in the PA interpolator to tool map
|
||||||
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_config_index) ? m_config.pressure_advance.get_at(m_last_config_index) : 0;
|
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_extruder_id) ? m_config.pressure_advance.get_at(m_last_extruder_id) : 0;
|
||||||
if(m_config.gcode_comments) output << "; APA: Tool doesnt have APA enabled\n";
|
if(m_config.gcode_comments) output << "; APA: Tool doesnt have APA enabled\n";
|
||||||
} else if (!interpolator->isInitialised() || (!m_config.adaptive_pressure_advance.get_at(m_last_config_index)) )
|
} else if (!interpolator->isInitialised() || (!m_config.adaptive_pressure_advance.get_at(m_last_extruder_id)) )
|
||||||
// Check if the model is not initialised by the constructor for the active extruder
|
// Check if the model is not initialised by the constructor for the active extruder
|
||||||
// Also check that adaptive PA is enabled for that extruder. This should not be needed
|
// Also check that adaptive PA is enabled for that extruder. This should not be needed
|
||||||
// as the PA change flag should not be set upstream (in the GCode.cpp file) if adaptive PA is disabled
|
// as the PA change flag should not be set upstream (in the GCode.cpp file) if adaptive PA is disabled
|
||||||
// however check for robustness sake.
|
// however check for robustness sake.
|
||||||
{
|
{
|
||||||
// Model failed or adaptive pressure advance not enabled - use default value from m_config
|
// Model failed or adaptive pressure advance not enabled - use default value from m_config
|
||||||
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_config_index) ? m_config.pressure_advance.get_at(m_last_config_index) : 0;
|
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_extruder_id) ? m_config.pressure_advance.get_at(m_last_extruder_id) : 0;
|
||||||
if(m_config.gcode_comments) output << "; APA: Interpolator setup failed, using default pressure advance\n";
|
if(m_config.gcode_comments) output << "; APA: Interpolator setup failed, using default pressure advance\n";
|
||||||
} else { // Model setup succeeded
|
} else { // Model setup succeeded
|
||||||
// Proceed to identify the print speed to use to calculate the adaptive PA value
|
// Proceed to identify the print speed to use to calculate the adaptive PA value
|
||||||
@@ -242,18 +249,18 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
|
|||||||
predicted_pa = (*interpolator)(mm3mm_value * adaptive_PA_speed, accel_value);
|
predicted_pa = (*interpolator)(mm3mm_value * adaptive_PA_speed, accel_value);
|
||||||
|
|
||||||
// This is a bridge, use the dedicated PA setting.
|
// This is a bridge, use the dedicated PA setting.
|
||||||
if(isBridge && m_config.adaptive_pressure_advance_bridges.get_at(m_last_config_index) > EPSILON)
|
if(isBridge && m_config.adaptive_pressure_advance_bridges.get_at(m_last_extruder_id) > EPSILON)
|
||||||
predicted_pa = m_config.adaptive_pressure_advance_bridges.get_at(m_last_config_index);
|
predicted_pa = m_config.adaptive_pressure_advance_bridges.get_at(m_last_extruder_id);
|
||||||
|
|
||||||
if (predicted_pa < 0) { // If extrapolation fails, fall back to the default PA for the extruder.
|
if (predicted_pa < 0) { // If extrapolation fails, fall back to the default PA for the extruder.
|
||||||
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_config_index) ? m_config.pressure_advance.get_at(m_last_config_index) : 0;
|
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_extruder_id) ? m_config.pressure_advance.get_at(m_last_extruder_id) : 0;
|
||||||
if(m_config.gcode_comments) output << "; APA: Interpolation failed, using fallback pressure advance value\n";
|
if(m_config.gcode_comments) output << "; APA: Interpolation failed, using fallback pressure advance value\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(m_config.gcode_comments) {
|
if(m_config.gcode_comments) {
|
||||||
// Output debug GCode comments
|
// Output debug GCode comments
|
||||||
output << pa_change_line << '\n'; // Output PA change command tag
|
output << pa_change_line << '\n'; // Output PA change command tag
|
||||||
if(isBridge && m_config.adaptive_pressure_advance_bridges.get_at(m_last_config_index) > EPSILON)
|
if(isBridge && m_config.adaptive_pressure_advance_bridges.get_at(m_last_extruder_id) > EPSILON)
|
||||||
output << "; APA Model Override (bridge)\n";
|
output << "; APA Model Override (bridge)\n";
|
||||||
output << "; APA Current Speed: " << std::to_string(m_current_feedrate) << "\n";
|
output << "; APA Current Speed: " << std::to_string(m_current_feedrate) << "\n";
|
||||||
output << "; APA Next Speed: " << std::to_string(m_next_feedrate) << "\n";
|
output << "; APA Next Speed: " << std::to_string(m_next_feedrate) << "\n";
|
||||||
@@ -262,7 +269,7 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
|
|||||||
output << "; APA Flow rate: " << std::to_string(mm3mm_value * m_max_next_feedrate) << "\n";
|
output << "; APA Flow rate: " << std::to_string(mm3mm_value * m_max_next_feedrate) << "\n";
|
||||||
output << "; APA Prev PA: " << std::to_string(m_last_predicted_pa) << " New PA: " << std::to_string(predicted_pa) << "\n";
|
output << "; APA Prev PA: " << std::to_string(m_last_predicted_pa) << " New PA: " << std::to_string(predicted_pa) << "\n";
|
||||||
}
|
}
|
||||||
if (config_index_changed || std::fabs(predicted_pa - m_last_predicted_pa) > EPSILON) {
|
if (extruder_changed || std::fabs(predicted_pa - m_last_predicted_pa) > EPSILON) {
|
||||||
output << m_gcodegen.writer().set_pressure_advance(predicted_pa); // Use m_writer to set pressure advance
|
output << m_gcodegen.writer().set_pressure_advance(predicted_pa); // Use m_writer to set pressure advance
|
||||||
m_last_predicted_pa = predicted_pa; // Update the last predicted PA value
|
m_last_predicted_pa = predicted_pa; // Update the last predicted PA value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <regex>
|
#include <regex>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
#include "AdaptivePAInterpolator.hpp"
|
#include "AdaptivePAInterpolator.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
@@ -32,7 +33,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param gcodegen A reference to the GCode object that generates the G-code.
|
* @param gcodegen A reference to the GCode object that generates the G-code.
|
||||||
*/
|
*/
|
||||||
AdaptivePAProcessor(GCode &gcodegen);
|
AdaptivePAProcessor(GCode &gcodegen, const std::vector<unsigned int> &tools_used);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Processes a layer of G-code and applies adaptive pressure advance.
|
* @brief Processes a layer of G-code and applies adaptive pressure advance.
|
||||||
@@ -69,25 +70,28 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
GCode &m_gcodegen; ///< Reference to the GCode object.
|
GCode &m_gcodegen; ///< Reference to the GCode object.
|
||||||
std::unordered_map<unsigned int, std::unique_ptr<AdaptivePAInterpolator>> m_AdaptivePAInterpolators; ///< Map between Interpolator objects and filament config indices (null when adaptive PA is off)
|
std::unordered_map<unsigned int, std::unique_ptr<AdaptivePAInterpolator>> m_AdaptivePAInterpolators; ///< Map between Interpolator objects and tool ID's
|
||||||
const PrintConfig &m_config; ///< Reference to the print configuration.
|
const PrintConfig &m_config; ///< Reference to the print configuration.
|
||||||
double m_last_predicted_pa; ///< Last predicted pressure advance value.
|
double m_last_predicted_pa; ///< Last predicted pressure advance value.
|
||||||
double m_max_next_feedrate; ///< Maximum feed rate (speed) for the upcomming island. If no speed is found, the previous island speed is used.
|
double m_max_next_feedrate; ///< Maximum feed rate (speed) for the upcomming island. If no speed is found, the previous island speed is used.
|
||||||
double m_next_feedrate; ///< First feed rate (speed) for the upcomming island.
|
double m_next_feedrate; ///< First feed rate (speed) for the upcomming island.
|
||||||
double m_current_feedrate; ///< Current, latest feedrate.
|
double m_current_feedrate; ///< Current, latest feedrate.
|
||||||
int m_last_config_index; ///< Filament config index of the last PA_CHANGE tag.
|
int m_last_extruder_id; ///< Last used extruder ID.
|
||||||
|
|
||||||
std::regex m_pa_change_pattern; ///< Regular expression to detect PA_CHANGE pattern.
|
std::regex m_pa_change_pattern; ///< Regular expression to detect PA_CHANGE pattern.
|
||||||
std::regex m_g1_f_pattern; ///< Regular expression to detect G1 F pattern.
|
std::regex m_g1_f_pattern; ///< Regular expression to detect G1 F pattern.
|
||||||
std::smatch m_match; ///< Match results for regular expressions.
|
std::smatch m_match; ///< Match results for regular expressions.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the PA interpolator attached to the specified filament config index.
|
* @brief Get the PA interpolator attached to the specified tool ID.
|
||||||
*
|
*
|
||||||
* @param config_index The filament config index (one per filament and extruder variant) for which the PA interpolation model is to be returned.
|
* This method manually sets the adaptive PA internally held value.
|
||||||
* @return The Adaptive PA Interpolator object corresponding to that index, or nullptr when adaptive PA is off for it.
|
* Call this when changing tools or in any other case where the internally assumed last PA value may be incorrect
|
||||||
|
*
|
||||||
|
* @param An integer with the tool ID for which the PA interpolation model is to be returned.
|
||||||
|
* @return The Adaptive PA Interpolator object corresponding to that tool.
|
||||||
*/
|
*/
|
||||||
AdaptivePAInterpolator* getInterpolator(unsigned int config_index);
|
AdaptivePAInterpolator* getInterpolator(unsigned int tool_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|||||||
+5
-11
@@ -2439,18 +2439,12 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
|
|||||||
if (m_default_region_config.precise_outer_wall && m_default_region_config.wall_sequence != WallSequence::InnerOuter)
|
if (m_default_region_config.precise_outer_wall && m_default_region_config.wall_sequence != WallSequence::InnerOuter)
|
||||||
warn(L("The precise wall option will be ignored for outer-inner or inner-outer-inner wall sequences."), "precise_outer_wall");
|
warn(L("The precise wall option will be ignored for outer-inner or inner-outer-inner wall sequences."), "precise_outer_wall");
|
||||||
|
|
||||||
// check adaptive pressure advance model of every extruder variant column of the used filaments
|
// check adaptive pressure advance model
|
||||||
const std::vector<int> &self_index = m_config.filament_self_index.values;
|
for (unsigned int extruder_id : extruders) {
|
||||||
const size_t pa_columns = std::max(m_config.adaptive_pressure_advance_model.size(), size_t(extruders.back()) + 1);
|
if (m_config.adaptive_pressure_advance.get_at(extruder_id) &&
|
||||||
for (size_t column = 0; column < pa_columns; ++column) {
|
m_config.enable_pressure_advance.get_at(extruder_id)) {
|
||||||
// filament_self_index maps a column to its filament once the filament arrays hold one column per variant
|
|
||||||
const unsigned int filament_id = self_index.size() == pa_columns ? self_index[column] - 1 : column;
|
|
||||||
if (!std::binary_search(extruders.begin(), extruders.end(), filament_id))
|
|
||||||
continue;
|
|
||||||
if (m_config.adaptive_pressure_advance.get_at(column) &&
|
|
||||||
m_config.enable_pressure_advance.get_at(column)) {
|
|
||||||
|
|
||||||
const std::string pa_model = m_config.adaptive_pressure_advance_model.get_at(column);
|
const std::string pa_model = m_config.adaptive_pressure_advance_model.get_at(extruder_id);
|
||||||
if (!pa_model.empty()) {
|
if (!pa_model.empty()) {
|
||||||
std::string validation_error = AdaptivePAProcessor::validate_adaptive_pa_model(pa_model);
|
std::string validation_error = AdaptivePAProcessor::validate_adaptive_pa_model(pa_model);
|
||||||
if (!validation_error.empty()) {
|
if (!validation_error.empty()) {
|
||||||
|
|||||||
@@ -9403,10 +9403,6 @@ void PrintConfigDef::handle_legacy_composite(DynamicPrintConfig &config)
|
|||||||
}
|
}
|
||||||
config.set_key_value("wiping_volumes_use_custom_matrix", new ConfigOptionBool(custom));
|
config.set_key_value("wiping_volumes_use_custom_matrix", new ConfigOptionBool(custom));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orca: a config saved before a key joined filament_options_with_variant stores it once per filament
|
|
||||||
// rather than once per filament variant, and one exported by an older CLI may store a single value.
|
|
||||||
normalize_filament_values_to_variants(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PrintConfigDef print_config_def;
|
const PrintConfigDef print_config_def;
|
||||||
@@ -9509,13 +9505,6 @@ std::set<std::string> filament_options_with_variant = {
|
|||||||
"filament_ironing_spacing",
|
"filament_ironing_spacing",
|
||||||
"filament_ironing_inset",
|
"filament_ironing_inset",
|
||||||
"filament_ironing_speed",
|
"filament_ironing_speed",
|
||||||
// Orca: pressure advance
|
|
||||||
"enable_pressure_advance",
|
|
||||||
"pressure_advance",
|
|
||||||
"adaptive_pressure_advance",
|
|
||||||
"adaptive_pressure_advance_model",
|
|
||||||
"adaptive_pressure_advance_overhangs",
|
|
||||||
"adaptive_pressure_advance_bridges",
|
|
||||||
"activate_air_filtration",
|
"activate_air_filtration",
|
||||||
"activate_air_filtration_during_print",
|
"activate_air_filtration_during_print",
|
||||||
"activate_air_filtration_on_completion",
|
"activate_air_filtration_on_completion",
|
||||||
@@ -10723,25 +10712,6 @@ void set_variant_override(ConfigOptionVectorBase &target, const ConfigOptionVect
|
|||||||
target.set_to_index(&source, indices, stride);
|
target.set_to_index(&source, indices, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
void normalize_filament_values_to_variants(DynamicPrintConfig &config)
|
|
||||||
{
|
|
||||||
const auto *self_index = config.option<ConfigOptionInts>("filament_self_index");
|
|
||||||
if (self_index == nullptr || self_index->empty())
|
|
||||||
return;
|
|
||||||
const int filament_count = *std::max_element(self_index->values.begin(), self_index->values.end());
|
|
||||||
if (filament_count <= 0 || size_t(filament_count) >= self_index->size())
|
|
||||||
return;
|
|
||||||
for (const std::string &key : filament_options_with_variant) {
|
|
||||||
auto *opt = dynamic_cast<ConfigOptionVectorBase *>(config.option(key));
|
|
||||||
if (opt == nullptr || (opt->size() != size_t(filament_count) && opt->size() != 1))
|
|
||||||
continue;
|
|
||||||
std::unique_ptr<ConfigOption> per_filament(opt->clone());
|
|
||||||
// set_at() takes the first value for a filament past the end of a single-value vector
|
|
||||||
for (size_t variant = 0; variant < self_index->size(); ++variant)
|
|
||||||
opt->set_at(per_filament.get(), variant, self_index->values[variant] - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//used for object/region config
|
//used for object/region config
|
||||||
//use the smallest of multiple to single
|
//use the smallest of multiple to single
|
||||||
|
|||||||
@@ -884,11 +884,6 @@ extern std::set<std::string> empty_options;
|
|||||||
void set_variant_override(ConfigOptionVectorBase &target, const ConfigOptionVectorBase &source,
|
void set_variant_override(ConfigOptionVectorBase &target, const ConfigOptionVectorBase &source,
|
||||||
const std::vector<int> &variant_index, int stride = 1);
|
const std::vector<int> &variant_index, int stride = 1);
|
||||||
|
|
||||||
// Orca: lays every filament_options_with_variant option out one value per filament variant, as
|
|
||||||
// filament_self_index maps the variants to filaments. An option holding one value per filament, or a
|
|
||||||
// single value, gives every variant of a filament that filament's value; other lengths are left alone.
|
|
||||||
void normalize_filament_values_to_variants(DynamicPrintConfig &config);
|
|
||||||
|
|
||||||
extern std::set<std::string> filament_dev_options;
|
extern std::set<std::string> filament_dev_options;
|
||||||
|
|
||||||
extern void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPrintConfig& dest_config, std::vector<int> variant_index, std::set<std::string>& key_set1, int stride = 1);
|
extern void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPrintConfig& dest_config, std::vector<int> variant_index, std::set<std::string>& key_set1, int stride = 1);
|
||||||
|
|||||||
@@ -263,12 +263,6 @@ extern bool is_path_within_root(const std::string &rel_path, const boost::filesy
|
|||||||
// True if a symlink stored at link_rel_path (relative to root) with this target stays inside root: the target
|
// True if a symlink stored at link_rel_path (relative to root) with this target stays inside root: the target
|
||||||
// must be relative, and joined to the link's directory it must pass is_path_within_root.
|
// must be relative, and joined to the link's directory it must pass is_path_within_root.
|
||||||
extern bool is_symlink_target_within_root(const std::string &link_rel_path, const std::string &target, const boost::filesystem::path &root);
|
extern bool is_symlink_target_within_root(const std::string &link_rel_path, const std::string &target, const boost::filesystem::path &root);
|
||||||
// True if path names an entry strictly inside root: it must be spelled with root as its prefix,
|
|
||||||
// and must still resolve inside root once symlinks are followed.
|
|
||||||
extern bool is_absolute_path_within_root(const boost::filesystem::path &path, const boost::filesystem::path &root);
|
|
||||||
// True if a file with this name is of a type that the desktop opens as plain content, so it cannot run code.
|
|
||||||
// Anything unknown is not safe.
|
|
||||||
extern bool is_safe_to_open_file_name(const std::string &file_name);
|
|
||||||
|
|
||||||
// Orca: custom protocal support utils
|
// Orca: custom protocal support utils
|
||||||
inline bool is_orca_open(const std::string& url) { return boost::starts_with(url, "orcaslicer://open"); }
|
inline bool is_orca_open(const std::string& url) { return boost::starts_with(url, "orcaslicer://open"); }
|
||||||
|
|||||||
@@ -70,7 +70,6 @@
|
|||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
#include <boost/nowide/fstream.hpp>
|
#include <boost/nowide/fstream.hpp>
|
||||||
@@ -1128,28 +1127,6 @@ bool is_symlink_target_within_root(const std::string &link_rel_path, const std::
|
|||||||
return is_path_within_root((sep == std::string::npos ? std::string() : link_rel_path.substr(0, sep + 1)) + target, root);
|
return is_path_within_root((sep == std::string::npos ? std::string() : link_rel_path.substr(0, sep + 1)) + target, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_absolute_path_within_root(const boost::filesystem::path &path, const boost::filesystem::path &root)
|
|
||||||
{
|
|
||||||
const boost::filesystem::path rel = path.lexically_relative(root);
|
|
||||||
return !rel.empty() && rel != "." && is_path_within_root(rel.string(), root);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_safe_to_open_file_name(const std::string &file_name)
|
|
||||||
{
|
|
||||||
// Formats that cannot carry macros or scripts. Legacy and OpenDocument office files, HTML and SVG are left out on purpose.
|
|
||||||
static const std::vector<std::string> safe_extensions = {
|
|
||||||
"jpg", "jpeg", "jfif", "pjpeg", "pjp", "png", "gif", "bmp", "webp", "tif", "tiff",
|
|
||||||
"pdf", "txt", "md", "csv", "docx", "xlsx", "pptx",
|
|
||||||
"stl", "obj", "3mf", "amf", "ply", "step", "stp", "iges", "igs", "dxf",
|
|
||||||
"mp4", "mov", "webm"};
|
|
||||||
// The name must end in the extension itself: Windows drops trailing dots and spaces and reads ':' as a stream separator.
|
|
||||||
const size_t dot = file_name.find_last_of('.');
|
|
||||||
if (dot == std::string::npos || file_name.find_first_of("/\\:") != std::string::npos)
|
|
||||||
return false;
|
|
||||||
const std::string extension = boost::algorithm::to_lower_copy(file_name.substr(dot + 1));
|
|
||||||
return std::find(safe_extensions.begin(), safe_extensions.end(), extension) != safe_extensions.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_img_file(const std::string &path)
|
bool is_img_file(const std::string &path)
|
||||||
{
|
{
|
||||||
return boost::iends_with(path, ".png") || boost::iends_with(path, ".svg");
|
return boost::iends_with(path, ".png") || boost::iends_with(path, ".svg");
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ void AuFile::on_dclick(wxMouseEvent &evt)
|
|||||||
if (m_type == AddFileButton)
|
if (m_type == AddFileButton)
|
||||||
return;
|
return;
|
||||||
else
|
else
|
||||||
desktop_open_project_attachment(this, m_file_path);
|
wxLaunchDefaultApplication(m_file_path.wstring(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuFile::on_mouse_left_up(wxMouseEvent &evt)
|
void AuFile::on_mouse_left_up(wxMouseEvent &evt)
|
||||||
|
|||||||
@@ -171,16 +171,14 @@ void ConfigManipulation::check_adaptive_pressure_advance_model(DynamicPrintConfi
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* model = config->option<ConfigOptionStrings>("adaptive_pressure_advance_model");
|
const auto* model = config->option<ConfigOptionStrings>("adaptive_pressure_advance_model");
|
||||||
if (model == nullptr)
|
if (model == nullptr || model->values.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Each extruder variant holds its own model.
|
std::string raw_model;
|
||||||
std::string error;
|
for (const std::string& chunk : model->values)
|
||||||
for (const std::string& variant_model : model->values) {
|
raw_model += chunk;
|
||||||
error = AdaptivePAProcessor::validate_adaptive_pa_model(variant_model);
|
|
||||||
if (!error.empty())
|
std::string error = AdaptivePAProcessor::validate_adaptive_pa_model(raw_model);
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!error.empty()) {
|
if (!error.empty()) {
|
||||||
wxString msg_text = _L("Adaptive Pressure Advance model validation failed:\n");
|
wxString msg_text = _L("Adaptive Pressure Advance model validation failed:\n");
|
||||||
msg_text += from_u8(error);
|
msg_text += from_u8(error);
|
||||||
|
|||||||
@@ -30,13 +30,11 @@
|
|||||||
|
|
||||||
#include "AboutDialog.hpp"
|
#include "AboutDialog.hpp"
|
||||||
#include "MsgDialog.hpp"
|
#include "MsgDialog.hpp"
|
||||||
#include "Plater.hpp"
|
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
|
|
||||||
#include "WebUserLoginDialog.hpp"
|
#include "WebUserLoginDialog.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@@ -645,26 +643,4 @@ void desktop_open_any_folder( const std::string& path )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool desktop_open_project_attachment(wxWindow *parent, const boost::filesystem::path &path)
|
|
||||||
{
|
|
||||||
// The auxiliary path is UTF-8, which is what boost::filesystem reads a narrow string as.
|
|
||||||
const boost::filesystem::path aux_root(wxGetApp().plater()->model().get_auxiliary_file_temp_path());
|
|
||||||
boost::system::error_code ec;
|
|
||||||
if (!is_absolute_path_within_root(path, aux_root) || !boost::filesystem::is_regular_file(path, ec))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Attachments come with the project and carry no download mark, so the desktop would open them without a warning.
|
|
||||||
if (!is_safe_to_open_file_name(path.filename().string())) {
|
|
||||||
MessageDialog dlg(parent,
|
|
||||||
wxString::Format(_L("\"%s\" is not a plain document, image or model file. Opening it may run it as a "
|
|
||||||
"program or script on this computer.\n\n"
|
|
||||||
"Only open attachments from projects you trust. Open it anyway?"),
|
|
||||||
from_path(path.filename())),
|
|
||||||
_L("Open attachment"), wxICON_WARNING | wxYES_NO);
|
|
||||||
if (dlg.ShowModal() != wxID_YES)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return wxLaunchDefaultApplication(from_path(path), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|||||||
@@ -86,9 +86,6 @@ extern void about();
|
|||||||
extern void desktop_open_datadir_folder();
|
extern void desktop_open_datadir_folder();
|
||||||
// Ask the destop to open one folder
|
// Ask the destop to open one folder
|
||||||
extern void desktop_open_any_folder(const std::string& path);
|
extern void desktop_open_any_folder(const std::string& path);
|
||||||
// Ask the desktop to open a file from the project's auxiliary directory, after a confirmation
|
|
||||||
// unless its type is known to be plain content. Returns false if the file was not opened.
|
|
||||||
extern bool desktop_open_project_attachment(wxWindow *parent, const boost::filesystem::path &path);
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
|||||||
+15
-27
@@ -286,30 +286,6 @@ static void set_config_values(DynamicPrintConfig *config, const std::string &key
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orca: a calibration print sets pressure advance explicitly to 0 on each extruder variant that
|
|
||||||
// has it disabled, so the value stored in the printer does not skew the result. Variants with
|
|
||||||
// pressure advance enabled keep their own value.
|
|
||||||
static void zero_pressure_advance_where_disabled(DynamicPrintConfig *filament_config)
|
|
||||||
{
|
|
||||||
auto enable_pa = filament_config->option<ConfigOptionBools>("enable_pressure_advance");
|
|
||||||
auto pa = filament_config->option<ConfigOptionFloats>("pressure_advance");
|
|
||||||
auto adaptive_pa = filament_config->option<ConfigOptionBools>("adaptive_pressure_advance");
|
|
||||||
if (!enable_pa || !pa || !adaptive_pa || pa->empty() || adaptive_pa->empty())
|
|
||||||
return;
|
|
||||||
// All variant keys share the variant count; widen a short one rather than index past it.
|
|
||||||
if (pa->size() < enable_pa->size())
|
|
||||||
pa->resize(enable_pa->size());
|
|
||||||
if (adaptive_pa->size() < enable_pa->size())
|
|
||||||
adaptive_pa->resize(enable_pa->size());
|
|
||||||
for (size_t variant = 0; variant < enable_pa->size(); ++variant) {
|
|
||||||
if (enable_pa->get_at(variant))
|
|
||||||
continue;
|
|
||||||
enable_pa->values[variant] = true;
|
|
||||||
pa->values[variant] = 0.0;
|
|
||||||
adaptive_pa->values[variant] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Plater::has_illegal_filename_characters(const wxString& wxs_name)
|
bool Plater::has_illegal_filename_characters(const wxString& wxs_name)
|
||||||
{
|
{
|
||||||
std::string name = into_u8(wxs_name);
|
std::string name = into_u8(wxs_name);
|
||||||
@@ -17088,7 +17064,11 @@ void Plater::calib_input_shaping_freq(const Calib_Params& params)
|
|||||||
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_jerk", 0);
|
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_jerk", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
zero_pressure_advance_where_disabled(filament_config);
|
if (!filament_config->option<ConfigOptionBools>("enable_pressure_advance")->get_at(0)) {
|
||||||
|
set_config_values<bool, ConfigOptionBools>(filament_config, "enable_pressure_advance", true);
|
||||||
|
set_config_values<double, ConfigOptionFloatsNullable>(filament_config, "pressure_advance", 0.0);
|
||||||
|
set_config_values<bool, ConfigOptionBools>(filament_config, "adaptive_pressure_advance", false);
|
||||||
|
}
|
||||||
|
|
||||||
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
||||||
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{false});
|
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{false});
|
||||||
@@ -17150,7 +17130,11 @@ void Plater::calib_input_shaping_damp(const Calib_Params& params)
|
|||||||
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_jerk", 0);
|
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_jerk", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
zero_pressure_advance_where_disabled(filament_config);
|
if (!filament_config->option<ConfigOptionBools>("enable_pressure_advance")->get_at(0)) {
|
||||||
|
set_config_values<bool, ConfigOptionBools>(filament_config, "enable_pressure_advance", true);
|
||||||
|
set_config_values<double, ConfigOptionFloatsNullable>(filament_config, "pressure_advance", 0.0);
|
||||||
|
set_config_values<bool, ConfigOptionBools>(filament_config, "adaptive_pressure_advance", false);
|
||||||
|
}
|
||||||
|
|
||||||
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
||||||
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{false});
|
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{false});
|
||||||
@@ -17212,7 +17196,11 @@ void Plater::Calib_Cornering(const Calib_Params& params)
|
|||||||
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_jerk", 0);
|
set_config_values<double, ConfigOptionFloatsNullable>(print_config, "default_jerk", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
zero_pressure_advance_where_disabled(filament_config);
|
if (!filament_config->option<ConfigOptionBools>("enable_pressure_advance")->get_at(0)) {
|
||||||
|
set_config_values<bool, ConfigOptionBools>(filament_config, "enable_pressure_advance", true);
|
||||||
|
set_config_values<double, ConfigOptionFloatsNullable>(filament_config, "pressure_advance", 0.0);
|
||||||
|
set_config_values<bool, ConfigOptionBools>(filament_config, "adaptive_pressure_advance", false);
|
||||||
|
}
|
||||||
|
|
||||||
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
||||||
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{true});
|
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{true});
|
||||||
|
|||||||
@@ -293,8 +293,10 @@ void ProjectPanel::OnScriptMessage(wxWebViewEvent& evt)
|
|||||||
if (!accessory_path.empty()) {
|
if (!accessory_path.empty()) {
|
||||||
std::string decode_path = wxGetApp().url_decode(accessory_path.ToStdString());
|
std::string decode_path = wxGetApp().url_decode(accessory_path.ToStdString());
|
||||||
fs::path path(decode_path);
|
fs::path path(decode_path);
|
||||||
if (!desktop_open_project_attachment(this, path))
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "open_3mf_accessory: not opening " << decode_path;
|
if (fs::exists(path)) {
|
||||||
|
wxLaunchDefaultApplication(path.wstring(), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strCmd == "request_3mf_info") {
|
else if (strCmd == "request_3mf_info") {
|
||||||
|
|||||||
+19
-20
@@ -4415,15 +4415,15 @@ void TabFilament::build()
|
|||||||
optgroup->append_single_option_line("pellet_flow_coefficient", "printer_basic_information_advanced#pellet-modded-printer");
|
optgroup->append_single_option_line("pellet_flow_coefficient", "printer_basic_information_advanced#pellet-modded-printer");
|
||||||
optgroup->append_single_option_line("filament_flow_ratio", "material_flow_ratio_and_pressure_advance#flow-ratio", 0);
|
optgroup->append_single_option_line("filament_flow_ratio", "material_flow_ratio_and_pressure_advance#flow-ratio", 0);
|
||||||
|
|
||||||
optgroup->append_single_option_line("enable_pressure_advance", "material_flow_ratio_and_pressure_advance#pressure-advance", 0);
|
optgroup->append_single_option_line("enable_pressure_advance", "material_flow_ratio_and_pressure_advance#pressure-advance");
|
||||||
optgroup->append_single_option_line("pressure_advance", "material_flow_ratio_and_pressure_advance#pressure-advance", 0);
|
optgroup->append_single_option_line("pressure_advance", "material_flow_ratio_and_pressure_advance#pressure-advance");
|
||||||
|
|
||||||
// Orca: adaptive pressure advance and calibration model
|
// Orca: adaptive pressure advance and calibration model
|
||||||
optgroup->append_single_option_line("adaptive_pressure_advance", "material_flow_ratio_and_pressure_advance#enable-adaptive-pressure-advance-beta", 0);
|
optgroup->append_single_option_line("adaptive_pressure_advance", "material_flow_ratio_and_pressure_advance#enable-adaptive-pressure-advance-beta");
|
||||||
optgroup->append_single_option_line("adaptive_pressure_advance_overhangs", "material_flow_ratio_and_pressure_advance#enable-adaptive-pressure-advance-for-overhangs-beta", 0);
|
optgroup->append_single_option_line("adaptive_pressure_advance_overhangs", "material_flow_ratio_and_pressure_advance#enable-adaptive-pressure-advance-for-overhangs-beta");
|
||||||
optgroup->append_single_option_line("adaptive_pressure_advance_bridges", "material_flow_ratio_and_pressure_advance#pressure-advance-for-bridges", 0);
|
optgroup->append_single_option_line("adaptive_pressure_advance_bridges", "material_flow_ratio_and_pressure_advance#pressure-advance-for-bridges");
|
||||||
|
|
||||||
Option option = optgroup->get_option("adaptive_pressure_advance_model", 0);
|
Option option = optgroup->get_option("adaptive_pressure_advance_model");
|
||||||
option.opt.full_width = true;
|
option.opt.full_width = true;
|
||||||
option.opt.is_code = true;
|
option.opt.is_code = true;
|
||||||
option.opt.height = 15;
|
option.opt.height = 15;
|
||||||
@@ -4432,7 +4432,7 @@ void TabFilament::build()
|
|||||||
DynamicPrintConfig& filament_config = m_preset_bundle->filaments.get_edited_preset().config;
|
DynamicPrintConfig& filament_config = m_preset_bundle->filaments.get_edited_preset().config;
|
||||||
|
|
||||||
update_dirty();
|
update_dirty();
|
||||||
if (opt_key.substr(0, opt_key.find('#')) == "adaptive_pressure_advance_model")
|
if (opt_key == "adaptive_pressure_advance_model")
|
||||||
m_config_manipulation.check_adaptive_pressure_advance_model(&filament_config);
|
m_config_manipulation.check_adaptive_pressure_advance_model(&filament_config);
|
||||||
|
|
||||||
on_value_change(opt_key, value);
|
on_value_change(opt_key, value);
|
||||||
@@ -4829,11 +4829,8 @@ void TabFilament::toggle_options()
|
|||||||
}
|
}
|
||||||
if (m_active_page->title() == L("Filament"))
|
if (m_active_page->title() == L("Filament"))
|
||||||
{
|
{
|
||||||
const int selection = m_variant_combo ? m_variant_combo->GetSelection() : 0;
|
bool pa = m_config->opt_bool("enable_pressure_advance", 0);
|
||||||
const unsigned int variant_idx = (unsigned int) std::max(selection, 0);
|
toggle_option("pressure_advance", pa);
|
||||||
|
|
||||||
bool pa = m_config->opt_bool("enable_pressure_advance", variant_idx);
|
|
||||||
toggle_option("pressure_advance", pa, 0);
|
|
||||||
|
|
||||||
//Orca: Enable the plates that should be visible when multi bed support is enabled or a BBL printer is selected; otherwise, enable only the plate visible for the selected bed type.
|
//Orca: Enable the plates that should be visible when multi bed support is enabled or a BBL printer is selected; otherwise, enable only the plate visible for the selected bed type.
|
||||||
DynamicConfig& proj_cfg = m_preset_bundle->project_config;
|
DynamicConfig& proj_cfg = m_preset_bundle->project_config;
|
||||||
@@ -4861,12 +4858,12 @@ void TabFilament::toggle_options()
|
|||||||
// Orca: adaptive pressure advance and calibration model
|
// Orca: adaptive pressure advance and calibration model
|
||||||
// If PA is not enabled, disable adaptive pressure advance and hide the model section
|
// If PA is not enabled, disable adaptive pressure advance and hide the model section
|
||||||
// If adaptive PA is not enabled, hide the adaptive PA model section
|
// If adaptive PA is not enabled, hide the adaptive PA model section
|
||||||
toggle_option("adaptive_pressure_advance", pa, 0);
|
toggle_option("adaptive_pressure_advance", pa);
|
||||||
toggle_option("adaptive_pressure_advance_overhangs", pa, 0);
|
toggle_option("adaptive_pressure_advance_overhangs", pa);
|
||||||
bool has_adaptive_pa = m_config->opt_bool("adaptive_pressure_advance", variant_idx);
|
bool has_adaptive_pa = m_config->opt_bool("adaptive_pressure_advance", 0);
|
||||||
toggle_line("adaptive_pressure_advance_overhangs", has_adaptive_pa && pa, 0);
|
toggle_line("adaptive_pressure_advance_overhangs", has_adaptive_pa && pa);
|
||||||
toggle_line("adaptive_pressure_advance_model", has_adaptive_pa && pa, 0);
|
toggle_line("adaptive_pressure_advance_model", has_adaptive_pa && pa);
|
||||||
toggle_line("adaptive_pressure_advance_bridges", has_adaptive_pa && pa, 0);
|
toggle_line("adaptive_pressure_advance_bridges", has_adaptive_pa && pa);
|
||||||
|
|
||||||
bool is_pellet_printer = printer_cfg.opt_bool("pellet_modded_printer");
|
bool is_pellet_printer = printer_cfg.opt_bool("pellet_modded_printer");
|
||||||
toggle_line("pellet_flow_coefficient", is_pellet_printer);
|
toggle_line("pellet_flow_coefficient", is_pellet_printer);
|
||||||
@@ -4874,6 +4871,8 @@ void TabFilament::toggle_options()
|
|||||||
|
|
||||||
toggle_line("activate_chamber_temp_control", printer_cfg.opt_bool("support_chamber_temp_control"));
|
toggle_line("activate_chamber_temp_control", printer_cfg.opt_bool("support_chamber_temp_control"));
|
||||||
|
|
||||||
|
const int selection = m_variant_combo ? m_variant_combo->GetSelection() : 0;
|
||||||
|
const unsigned int variant_idx = (unsigned int) std::max(selection, 0);
|
||||||
std::string volumetric_speed_cos = m_config->opt_string("volumetric_speed_coefficients", variant_idx);
|
std::string volumetric_speed_cos = m_config->opt_string("volumetric_speed_coefficients", variant_idx);
|
||||||
bool enable_fit = volumetric_speed_cos != "0 0 0 0 0 0";
|
bool enable_fit = volumetric_speed_cos != "0 0 0 0 0 0";
|
||||||
toggle_option("filament_adaptive_volumetric_speed", enable_fit, 256 + variant_idx);
|
toggle_option("filament_adaptive_volumetric_speed", enable_fit, 256 + variant_idx);
|
||||||
@@ -5206,6 +5205,7 @@ void TabPrinter::build_fff()
|
|||||||
optgroup->append_single_option_line("adaptive_bed_mesh_margin", "printer_basic_information_adaptive_bed_mesh#mesh-margin");
|
optgroup->append_single_option_line("adaptive_bed_mesh_margin", "printer_basic_information_adaptive_bed_mesh#mesh-margin");
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Accessory"), "param_accessory");
|
optgroup = page->new_optgroup(L("Accessory"), "param_accessory");
|
||||||
|
optgroup->append_single_option_line("nozzle_type", "printer_basic_information_accessory#nozzle-type", 0);
|
||||||
optgroup->append_single_option_line("nozzle_hrc", "printer_basic_information_accessory#nozzle-hrc");
|
optgroup->append_single_option_line("nozzle_hrc", "printer_basic_information_accessory#nozzle-hrc");
|
||||||
optgroup->append_single_option_line("auxiliary_fan", "printer_basic_information_accessory#auxiliary-part-cooling-fan");
|
optgroup->append_single_option_line("auxiliary_fan", "printer_basic_information_accessory#auxiliary-part-cooling-fan");
|
||||||
optgroup->append_single_option_line("fan_direction");
|
optgroup->append_single_option_line("fan_direction");
|
||||||
@@ -5720,7 +5720,6 @@ if (is_marlin_flavor)
|
|||||||
|
|
||||||
auto optgroup = page->new_optgroup(L("Basic information"), L"param_information", -1, true);
|
auto optgroup = page->new_optgroup(L("Basic information"), L"param_information", -1, true);
|
||||||
optgroup->append_single_option_line("nozzle_diameter", "printer_extruder_basic_information#nozzle-diameter", extruder_idx);
|
optgroup->append_single_option_line("nozzle_diameter", "printer_extruder_basic_information#nozzle-diameter", extruder_idx);
|
||||||
optgroup->append_single_option_line("nozzle_type", "printer_basic_information_accessory#nozzle-type", extruder_idx);
|
|
||||||
//optgroup->append_single_option_line("nozzle_volume_type", "", extruder_idx);
|
//optgroup->append_single_option_line("nozzle_volume_type", "", extruder_idx);
|
||||||
|
|
||||||
optgroup->append_single_option_line("nozzle_volume", "printer_extruder_basic_information#nozzle-volume", extruder_idx);
|
optgroup->append_single_option_line("nozzle_volume", "printer_extruder_basic_information#nozzle-volume", extruder_idx);
|
||||||
@@ -5732,7 +5731,7 @@ if (is_marlin_flavor)
|
|||||||
optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value)
|
optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value)
|
||||||
{
|
{
|
||||||
bool is_SEMM = m_config->opt_bool("single_extruder_multi_material");
|
bool is_SEMM = m_config->opt_bool("single_extruder_multi_material");
|
||||||
if (is_SEMM && m_extruders_count > 1 && boost::starts_with(opt_key, "nozzle_diameter"))
|
if (is_SEMM && m_extruders_count > 1 && opt_key.find_first_of("nozzle_diameter") != std::string::npos)
|
||||||
{
|
{
|
||||||
SuppressBackgroundProcessingUpdate sbpu;
|
SuppressBackgroundProcessingUpdate sbpu;
|
||||||
const double new_nd = boost::any_cast<double>(value);
|
const double new_nd = boost::any_cast<double>(value);
|
||||||
|
|||||||
@@ -31,15 +31,14 @@ int UserManager::parse_json(std::string payload)
|
|||||||
{
|
{
|
||||||
bool restored_json = false;
|
bool restored_json = false;
|
||||||
json j;
|
json j;
|
||||||
|
|
||||||
//bind/unbind
|
|
||||||
|
|
||||||
try {
|
|
||||||
json j_pre = json::parse(payload);
|
json j_pre = json::parse(payload);
|
||||||
if (j_pre.empty()) {
|
if (j_pre.empty()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//bind/unbind
|
||||||
|
|
||||||
|
try {
|
||||||
if (j_pre.contains("bind")) {
|
if (j_pre.contains("bind")) {
|
||||||
if (j_pre["bind"].contains("command")) {
|
if (j_pre["bind"].contains("command")) {
|
||||||
|
|
||||||
|
|||||||
@@ -274,4 +274,13 @@ bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionTyp
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Duet::get_err_code_from_body(const std::string &body) const
|
||||||
|
{
|
||||||
|
pt::ptree root;
|
||||||
|
std::istringstream iss (body); // wrap returned json to istringstream
|
||||||
|
pt::read_json(iss, root);
|
||||||
|
|
||||||
|
return root.get<int>("err", 0);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ private:
|
|||||||
ConnectionType connect(wxString &msg) const;
|
ConnectionType connect(wxString &msg) const;
|
||||||
void disconnect(ConnectionType connectionType) const;
|
void disconnect(ConnectionType connectionType) const;
|
||||||
bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType, bool simulationMode) const;
|
bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType, bool simulationMode) const;
|
||||||
|
int get_err_code_from_body(const std::string &body) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,6 +146,15 @@ bool ESP3D::start_print(wxString& msg, const std::string& filename) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ESP3D::get_err_code_from_body(const std::string& body) const
|
||||||
|
{
|
||||||
|
pt::ptree root;
|
||||||
|
std::istringstream iss(body); // wrap returned json to istringstream
|
||||||
|
pt::read_json(iss, root);
|
||||||
|
|
||||||
|
return root.get<int>("err", 0);
|
||||||
|
}
|
||||||
|
|
||||||
// ESP3D only accepts 8.3 filenames else it crashes marlin and other undefined behaviour
|
// ESP3D only accepts 8.3 filenames else it crashes marlin and other undefined behaviour
|
||||||
std::string ESP3D::get_short_name(const std::string& filename) const
|
std::string ESP3D::get_short_name(const std::string& filename) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ private:
|
|||||||
std::string m_console_port;
|
std::string m_console_port;
|
||||||
|
|
||||||
bool start_print(wxString& msg, const std::string& filename) const;
|
bool start_print(wxString& msg, const std::string& filename) const;
|
||||||
|
int get_err_code_from_body(const std::string& body) const;
|
||||||
std::string get_short_name(const std::string& filename) const;
|
std::string get_short_name(const std::string& filename) const;
|
||||||
std::string format_command(const std::string& path, const std::string& arg, const std::string& val) const;
|
std::string format_command(const std::string& path, const std::string& arg, const std::string& val) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -510,22 +510,12 @@ bool Flashforge::fetch_material_slots(std::vector<FlashforgeMaterialSlot>& slots
|
|||||||
if (!request_local_api_json("detail", json{{"serialNumber", m_serial_number}, {"checkCode", m_check_code}}.dump(), body, msg))
|
if (!request_local_api_json("detail", json{{"serialNumber", m_serial_number}, {"checkCode", m_check_code}}.dump(), body, msg))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!parse_material_slots(body, slots, supports_material_station)) {
|
const auto parsed = json::parse(body, nullptr, false, true);
|
||||||
|
if (parsed.is_discarded()) {
|
||||||
msg = _(L("Flashforge returned an invalid JSON response."));
|
msg = _(L("Flashforge returned an invalid JSON response."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Flashforge::parse_material_slots(const std::string& body, std::vector<FlashforgeMaterialSlot>& slots, bool* supports_material_station)
|
|
||||||
{
|
|
||||||
slots.clear();
|
|
||||||
|
|
||||||
const auto parsed = json::parse(body, nullptr, false, true);
|
|
||||||
if (parsed.is_discarded())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto& detail = parsed.contains("detail") ? parsed["detail"] : parsed;
|
const auto& detail = parsed.contains("detail") ? parsed["detail"] : parsed;
|
||||||
const auto& station = detail.contains("matlStationInfo") ? detail["matlStationInfo"] :
|
const auto& station = detail.contains("matlStationInfo") ? detail["matlStationInfo"] :
|
||||||
detail.contains("MatlStationInfo") ? detail["MatlStationInfo"] : json();
|
detail.contains("MatlStationInfo") ? detail["MatlStationInfo"] : json();
|
||||||
@@ -552,21 +542,12 @@ bool Flashforge::parse_material_slots(const std::string& body, std::vector<Flash
|
|||||||
if (supports_material_station != nullptr)
|
if (supports_material_station != nullptr)
|
||||||
*supports_material_station = reports_material_station;
|
*supports_material_station = reports_material_station;
|
||||||
|
|
||||||
// Fields are read leniently: firmware may send numbers as strings or flags as numbers.
|
|
||||||
for (const auto& slot : slot_infos) {
|
for (const auto& slot : slot_infos) {
|
||||||
if (!slot.is_object())
|
|
||||||
continue;
|
|
||||||
FlashforgeMaterialSlot info;
|
FlashforgeMaterialSlot info;
|
||||||
info.slot_id = static_cast<int>(slots.size()) + 1;
|
info.slot_id = slot.value("slotId", static_cast<int>(slots.size()) + 1);
|
||||||
if (const auto it = slot.find("slotId"); it != slot.end())
|
info.has_filament = slot.value("hasFilament", false);
|
||||||
try_parse_json_int(*it, info.slot_id);
|
info.material_name = slot.value("materialName", std::string());
|
||||||
int has_filament = 0;
|
info.material_color = slot.value("materialColor", std::string());
|
||||||
if (const auto it = slot.find("hasFilament"); it != slot.end() && try_parse_json_int(*it, has_filament))
|
|
||||||
info.has_filament = has_filament != 0;
|
|
||||||
if (const auto it = slot.find("materialName"); it != slot.end() && it->is_string())
|
|
||||||
info.material_name = it->get<std::string>();
|
|
||||||
if (const auto it = slot.find("materialColor"); it != slot.end() && it->is_string())
|
|
||||||
info.material_color = it->get<std::string>();
|
|
||||||
slots.emplace_back(std::move(info));
|
slots.emplace_back(std::move(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -689,4 +670,13 @@ std::string Flashforge::extract_host_name() const
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Flashforge::get_err_code_from_body(const std::string& body) const
|
||||||
|
{
|
||||||
|
pt::ptree root;
|
||||||
|
std::istringstream iss(body); // wrap returned json to istringstream
|
||||||
|
pt::read_json(iss, root);
|
||||||
|
|
||||||
|
return root.get<int>("err", 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|||||||
@@ -45,8 +45,6 @@ public:
|
|||||||
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
|
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
|
||||||
std::string get_host() const override { return m_host; }
|
std::string get_host() const override { return m_host; }
|
||||||
bool fetch_material_slots(std::vector<FlashforgeMaterialSlot>& slots, bool* supports_material_station, wxString& msg) const;
|
bool fetch_material_slots(std::vector<FlashforgeMaterialSlot>& slots, bool* supports_material_station, wxString& msg) const;
|
||||||
// Parses a local API "detail" reply. Returns false when the body is not valid JSON.
|
|
||||||
static bool parse_material_slots(const std::string& body, std::vector<FlashforgeMaterialSlot>& slots, bool* supports_material_station);
|
|
||||||
static bool discover_printers(std::vector<FlashforgeDiscoveredPrinter>& printers, wxString& msg, int timeout_ms = 10000, int idle_timeout_ms = 1500, int max_retries = 3);
|
static bool discover_printers(std::vector<FlashforgeDiscoveredPrinter>& printers, wxString& msg, int timeout_ms = 10000, int idle_timeout_ms = 1500, int max_retries = 3);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -70,6 +68,7 @@ private:
|
|||||||
bool request_local_api_json(const std::string& path, const std::string& body, std::string& response_body, wxString& error_msg) const;
|
bool request_local_api_json(const std::string& path, const std::string& body, std::string& response_body, wxString& error_msg) const;
|
||||||
std::string make_http_url(const std::string& path) const;
|
std::string make_http_url(const std::string& path) const;
|
||||||
std::string extract_host_name() const;
|
std::string extract_host_name() const;
|
||||||
|
int get_err_code_from_body(const std::string &body) const;
|
||||||
bool connect(wxString& msg) const;
|
bool connect(wxString& msg) const;
|
||||||
bool start_print(wxString& msg, const std::string& filename) const;
|
bool start_print(wxString& msg, const std::string& filename) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -141,4 +141,13 @@ bool MKS::start_print(wxString& msg, const std::string& filename) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MKS::get_err_code_from_body(const std::string& body) const
|
||||||
|
{
|
||||||
|
pt::ptree root;
|
||||||
|
std::istringstream iss(body); // wrap returned json to istringstream
|
||||||
|
pt::read_json(iss, root);
|
||||||
|
|
||||||
|
return root.get<int>("err", 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // Slic3r
|
} // Slic3r
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ private:
|
|||||||
|
|
||||||
std::string get_upload_url(const std::string& filename) const;
|
std::string get_upload_url(const std::string& filename) const;
|
||||||
bool start_print(wxString& msg, const std::string& filename) const;
|
bool start_print(wxString& msg, const std::string& filename) const;
|
||||||
|
int get_err_code_from_body(const std::string& body) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,10 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <sstream>
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <boost/property_tree/ptree.hpp>
|
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
|
||||||
|
|
||||||
#include <wx/string.h>
|
#include <wx/string.h>
|
||||||
#include <wx/app.h>
|
#include <wx/app.h>
|
||||||
@@ -175,20 +172,6 @@ std::string moonraker_error_reason(const std::string &body)
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int PrintHost::get_err_code_from_body(const std::string &body)
|
|
||||||
{
|
|
||||||
boost::property_tree::ptree root;
|
|
||||||
std::istringstream iss(body);
|
|
||||||
try {
|
|
||||||
boost::property_tree::read_json(iss, root);
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "PrintHost: response is not valid JSON: " << ex.what();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return root.get<int>("err", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
wxString PrintHost::format_error(const std::string &body, const std::string &error, unsigned status) const
|
wxString PrintHost::format_error(const std::string &body, const std::string &error, unsigned status) const
|
||||||
{
|
{
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
@@ -432,10 +415,12 @@ void PrintHostJobQueue::priv::remove_source()
|
|||||||
source_to_remove.clear();
|
source_to_remove.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PrintHostJobQueue::upload_job(PrintHostJob &job, PrintHost::ProgressFn progress_fn, PrintHost::ErrorFn error_fn, PrintHost::InfoFn info_fn)
|
void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job)
|
||||||
{
|
{
|
||||||
|
emit_progress(0); // Indicate the upload is starting
|
||||||
|
|
||||||
// Captured before upload_data is moved into upload() below.
|
// Captured before upload_data is moved into upload() below.
|
||||||
const std::string upload_filename = job.upload_data.source_path.filename().string();
|
const std::string upload_filename = the_job.upload_data.source_path.filename().string();
|
||||||
|
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
@@ -444,37 +429,19 @@ bool PrintHostJobQueue::upload_job(PrintHostJob &job, PrintHost::ProgressFn prog
|
|||||||
fire_lifecycle_event(LifecycleEvent::UploadStarted, ctx);
|
fire_lifecycle_event(LifecycleEvent::UploadStarted, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = false;
|
bool success = the_job.printhost->upload(std::move(the_job.upload_data),
|
||||||
std::string error;
|
[this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); },
|
||||||
// A throwing upload must not stop the worker, or later jobs would stay queued forever.
|
[this](wxString error) { this->error_fn(std::move(error)); },
|
||||||
try {
|
[this](wxString tag, wxString host) { this->info_fn(std::move(tag), std::move(host)); }
|
||||||
success = job.printhost->upload(std::move(job.upload_data), std::move(progress_fn), error_fn, std::move(info_fn));
|
);
|
||||||
} catch (const std::exception &e) {
|
|
||||||
error = e.what();
|
|
||||||
error_fn(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = upload_filename;
|
ctx.name = upload_filename;
|
||||||
ctx.code = success ? LifecycleEvtCode::Ok : LifecycleEvtCode::Error;
|
ctx.code = success ? LifecycleEvtCode::Ok : LifecycleEvtCode::Error;
|
||||||
ctx.msg = error;
|
|
||||||
fire_lifecycle_event(LifecycleEvent::UploadFinished, ctx);
|
fire_lifecycle_event(LifecycleEvent::UploadFinished, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job)
|
|
||||||
{
|
|
||||||
emit_progress(0); // Indicate the upload is starting
|
|
||||||
|
|
||||||
bool success = PrintHostJobQueue::upload_job(the_job,
|
|
||||||
[this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); },
|
|
||||||
[this](wxString error) { this->error_fn(std::move(error)); },
|
|
||||||
[this](wxString tag, wxString host) { this->info_fn(std::move(tag), std::move(host)); }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
emit_progress(100);
|
emit_progress(100);
|
||||||
if (the_job.switch_to_device_tab) {
|
if (the_job.switch_to_device_tab) {
|
||||||
|
|||||||
@@ -87,8 +87,6 @@ public:
|
|||||||
|
|
||||||
static PrintHost* get_print_host(DynamicPrintConfig *config);
|
static PrintHost* get_print_host(DynamicPrintConfig *config);
|
||||||
static std::string get_print_host_webui(DynamicPrintConfig *config);
|
static std::string get_print_host_webui(DynamicPrintConfig *config);
|
||||||
// Reads the "err" field of a JSON reply, 0 when absent. Returns -1 when the body is not valid JSON.
|
|
||||||
static int get_err_code_from_body(const std::string &body);
|
|
||||||
|
|
||||||
//Support for cloud webui login
|
//Support for cloud webui login
|
||||||
virtual bool is_cloud() const { return false; }
|
virtual bool is_cloud() const { return false; }
|
||||||
@@ -152,10 +150,6 @@ public:
|
|||||||
void enqueue(PrintHostJob job);
|
void enqueue(PrintHostJob job);
|
||||||
void cancel(size_t id);
|
void cancel(size_t id);
|
||||||
|
|
||||||
// Uploads the job, firing UploadStarted and a matching UploadFinished. An exception thrown by
|
|
||||||
// the upload is reported through error_fn and makes the upload fail.
|
|
||||||
static bool upload_job(PrintHostJob &job, PrintHost::ProgressFn progress_fn, PrintHost::ErrorFn error_fn, PrintHost::InfoFn info_fn);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct priv;
|
struct priv;
|
||||||
std::shared_ptr<priv> p;
|
std::shared_ptr<priv> p;
|
||||||
|
|||||||
@@ -654,4 +654,13 @@ bool UltiMaker::start_print(wxString &msg, const std::string &filename, Connecti
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int UltiMaker::get_err_code_from_body(const std::string &body) const
|
||||||
|
{
|
||||||
|
pt::ptree root;
|
||||||
|
std::istringstream iss (body); // wrap returned json to istringstream
|
||||||
|
pt::read_json(iss, root);
|
||||||
|
|
||||||
|
return root.get<int>("err", 0);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ private:
|
|||||||
void set_auth(Http& http) const;
|
void set_auth(Http& http) const;
|
||||||
void disconnect(ConnectionType connectionType) const;
|
void disconnect(ConnectionType connectionType) const;
|
||||||
bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const;
|
bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const;
|
||||||
|
int get_err_code_from_body(const std::string &body) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -768,128 +768,3 @@ TEST_CASE("Each filament prints with its variant of the extruder's variant strin
|
|||||||
CHECK(gcode.find("; nozzle_temperature = " + resolved + "\n") != std::string::npos);
|
CHECK(gcode.find("; nozzle_temperature = " + resolved + "\n") != std::string::npos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// An adaptive pressure advance model predicting the same pressure advance at every flow and acceleration.
|
|
||||||
static std::string constant_pressure_advance_model(const std::string &pa)
|
|
||||||
{
|
|
||||||
return pa + ",1,1000\n" + pa + ",500,1000\n" + pa + ",1,100000\n" + pa + ",500,100000";
|
|
||||||
}
|
|
||||||
|
|
||||||
// The pressure advance values a Klipper G-code sets.
|
|
||||||
static std::set<std::string> pressure_advance_values(const std::string &gcode)
|
|
||||||
{
|
|
||||||
const std::string token = "SET_PRESSURE_ADVANCE ADVANCE=";
|
|
||||||
std::set<std::string> values;
|
|
||||||
std::istringstream stream(gcode);
|
|
||||||
for (std::string line; std::getline(stream, line);)
|
|
||||||
if (line.rfind(token, 0) == 0)
|
|
||||||
values.insert(line.substr(token.size(), line.find(';') - token.size()));
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pressure advance, and the adaptive pressure advance model, are tuned per extruder variant like the
|
|
||||||
// other filament variant settings.
|
|
||||||
TEST_CASE("Each filament sets the pressure advance of its extruder variant", "[MultiFilament]")
|
|
||||||
{
|
|
||||||
auto [nozzle_volume_type, filament, pressure_advance, adaptive_pressure_advance] = GENERATE(table<NozzleVolumeType, int, std::string, std::string>({
|
|
||||||
{ nvtStandard, 1, "0.021", "0.012" },
|
|
||||||
{ nvtHighFlow, 1, "0.037", "0.034" },
|
|
||||||
{ nvtHighFlow, 2, "0.043", "0.056" }, // filament 2 defines no High Flow variant
|
|
||||||
}));
|
|
||||||
const bool adaptive = GENERATE(false, true);
|
|
||||||
DYNAMIC_SECTION(get_nozzle_volume_type_string(nozzle_volume_type) << " nozzle, filament " << filament << (adaptive ? ", adaptive" : "")) {
|
|
||||||
DynamicPrintConfig config = multifilament_config(2, {
|
|
||||||
{ "gcode_flavor", "klipper" },
|
|
||||||
{ "extruder_variant_list", "Direct Drive Standard,Direct Drive High Flow" },
|
|
||||||
// filament 1 defines Standard (0.021) and High Flow (0.037), filament 2 Standard (0.043)
|
|
||||||
{ "filament_extruder_variant", "Direct Drive Standard;Direct Drive High Flow;Direct Drive Standard" },
|
|
||||||
{ "filament_self_index", "1,1,2" },
|
|
||||||
{ "enable_pressure_advance", "1,1,1" },
|
|
||||||
{ "pressure_advance", "0.021,0.037,0.043" },
|
|
||||||
{ "adaptive_pressure_advance", adaptive ? "1,1,1" : "0,0,0" },
|
|
||||||
{ "sparse_infill_filament_id", filament },
|
|
||||||
{ "internal_solid_filament_id", filament },
|
|
||||||
{ "top_surface_filament_id", filament },
|
|
||||||
{ "bottom_surface_filament_id", filament },
|
|
||||||
{ "outer_wall_filament_id", filament },
|
|
||||||
{ "inner_wall_filament_id", filament },
|
|
||||||
{ "enable_prime_tower", 0 },
|
|
||||||
{ "skirt_loops", 0 },
|
|
||||||
{ "brim_type", "no_brim" },
|
|
||||||
// custom G-code indexes the per-filament arrays by filament
|
|
||||||
{ "machine_start_gcode", "; start pressure advance {pressure_advance[initial_extruder]}" },
|
|
||||||
});
|
|
||||||
config.option<ConfigOptionStrings>("adaptive_pressure_advance_model")->values = {
|
|
||||||
constant_pressure_advance_model("0.012"), constant_pressure_advance_model("0.034"), constant_pressure_advance_model("0.056") };
|
|
||||||
config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type", true)->values = { nozzle_volume_type };
|
|
||||||
const std::string gcode = slice({ cube(20) }, config);
|
|
||||||
|
|
||||||
// The toolchange sets the variant's pressure advance; with adaptive pressure advance, the
|
|
||||||
// prediction of the variant's model then replaces it.
|
|
||||||
std::set<std::string> expected{ pressure_advance };
|
|
||||||
if (adaptive)
|
|
||||||
expected.insert(adaptive_pressure_advance);
|
|
||||||
CHECK(pressure_advance_values(gcode) == expected);
|
|
||||||
CHECK(gcode.find("; start pressure advance " + pressure_advance + "\n") != std::string::npos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// On a printer with two extruders, a filament takes the pressure advance of the variant of the extruder
|
|
||||||
// it is mapped to, whichever filament and extruder that is.
|
|
||||||
TEST_CASE("Each filament sets the pressure advance of its extruder variant on a two-extruder printer", "[MultiFilament]")
|
|
||||||
{
|
|
||||||
auto [filament, extruder, pressure_advance, adaptive_pressure_advance] = GENERATE(table<int, int, std::string, std::string>({
|
|
||||||
{ 1, 1, "0.021", "0.012" },
|
|
||||||
{ 1, 2, "0.037", "0.034" },
|
|
||||||
{ 2, 1, "0.043", "0.056" },
|
|
||||||
{ 2, 2, "0.049", "0.078" },
|
|
||||||
}));
|
|
||||||
const bool adaptive = GENERATE(false, true);
|
|
||||||
DYNAMIC_SECTION("filament " << filament << " on extruder " << extruder << (adaptive ? ", adaptive" : "")) {
|
|
||||||
// the other filament goes on the other extruder
|
|
||||||
const std::string filament_map = filament == 1 ? std::to_string(extruder) + "," + std::to_string(3 - extruder) :
|
|
||||||
std::to_string(3 - extruder) + "," + std::to_string(extruder);
|
|
||||||
DynamicPrintConfig config = multifilament_config(2, {
|
|
||||||
{ "gcode_flavor", "klipper" },
|
|
||||||
{ "single_extruder_multi_material", 0 },
|
|
||||||
{ "nozzle_diameter", "0.4,0.4" },
|
|
||||||
{ "extruder_printable_height", "0,0" },
|
|
||||||
// extruder 1 has a Standard nozzle, extruder 2 a High Flow one
|
|
||||||
{ "printer_extruder_id", "1,2" },
|
|
||||||
{ "printer_extruder_variant", "Direct Drive Standard;Direct Drive High Flow" },
|
|
||||||
{ "extruder_variant_list", "Direct Drive Standard;Direct Drive High Flow" },
|
|
||||||
{ "filament_map", filament_map },
|
|
||||||
// both filaments define Standard and High Flow
|
|
||||||
{ "filament_extruder_variant", "Direct Drive Standard;Direct Drive High Flow;Direct Drive Standard;Direct Drive High Flow" },
|
|
||||||
{ "filament_self_index", "1,1,2,2" },
|
|
||||||
{ "enable_pressure_advance", "1,1,1,1" },
|
|
||||||
{ "pressure_advance", "0.021,0.037,0.043,0.049" },
|
|
||||||
{ "adaptive_pressure_advance", adaptive ? "1,1,1,1" : "0,0,0,0" },
|
|
||||||
{ "sparse_infill_filament_id", filament },
|
|
||||||
{ "internal_solid_filament_id", filament },
|
|
||||||
{ "top_surface_filament_id", filament },
|
|
||||||
{ "bottom_surface_filament_id", filament },
|
|
||||||
{ "outer_wall_filament_id", filament },
|
|
||||||
{ "inner_wall_filament_id", filament },
|
|
||||||
{ "enable_prime_tower", 0 },
|
|
||||||
{ "skirt_loops", 0 },
|
|
||||||
{ "brim_type", "no_brim" },
|
|
||||||
// custom G-code indexes the per-filament arrays by filament
|
|
||||||
{ "machine_start_gcode", "; start pressure advance {pressure_advance[initial_extruder]}" },
|
|
||||||
});
|
|
||||||
config.option<ConfigOptionStrings>("adaptive_pressure_advance_model")->values = {
|
|
||||||
constant_pressure_advance_model("0.012"), constant_pressure_advance_model("0.034"),
|
|
||||||
constant_pressure_advance_model("0.056"), constant_pressure_advance_model("0.078") };
|
|
||||||
config.option<ConfigOptionEnumsGeneric>("extruder_type", true)->values = { etDirectDrive, etDirectDrive };
|
|
||||||
config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type", true)->values = { nvtStandard, nvtHighFlow };
|
|
||||||
// keep the mapping above rather than grouping the filaments automatically
|
|
||||||
config.option<ConfigOptionEnum<FilamentMapMode>>("filament_map_mode", true)->value = fmmManual;
|
|
||||||
const std::string gcode = slice({ cube(20) }, config);
|
|
||||||
|
|
||||||
std::set<std::string> expected{ pressure_advance };
|
|
||||||
if (adaptive)
|
|
||||||
expected.insert(adaptive_pressure_advance);
|
|
||||||
CHECK(pressure_advance_values(gcode) == expected);
|
|
||||||
CHECK(gcode.find("; start pressure advance " + pressure_advance + "\n") != std::string::npos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -717,15 +717,3 @@ TEST_CASE("get_index_for_extruder scales the variant column by the requested str
|
|||||||
REQUIRE(col0_stride2 == 0);
|
REQUIRE(col0_stride2 == 0);
|
||||||
REQUIRE(col1_stride2 == 2);
|
REQUIRE(col1_stride2 == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A per-variant filament option read with a single value gives it to every filament variant. A project
|
|
||||||
// exported by an older CLI holds a single value for an option no loaded preset defined, such as
|
|
||||||
// filament_ironing_flow.
|
|
||||||
TEST_CASE("A per-variant filament option read with a single value gives it to every filament variant", "[Config]")
|
|
||||||
{
|
|
||||||
// filament 1 defines Standard and High Flow, filament 2 Standard
|
|
||||||
DynamicPrintConfig config;
|
|
||||||
config.option<ConfigOptionInts>("filament_self_index", true)->values = {1, 1, 2};
|
|
||||||
config.load_from_ini_string("pressure_advance = 0.021", ForwardCompatibilitySubstitutionRule::Disable);
|
|
||||||
REQUIRE(config.option<ConfigOptionFloats>("pressure_advance")->values == std::vector<double>({0.021, 0.021, 0.021}));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ struct LoadedObj
|
|||||||
ObjInfo info;
|
ObjInfo info;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Loads an OBJ made of the given lines, with a material library that defines material "a".
|
// A tetrahedron with a material and two texture coordinates, (0.25, 0.5) and (0.75, 1).
|
||||||
LoadedObj load_textured_obj(const std::string &body)
|
// Only the first face and the vt lines are varied; the other three faces reference vt 1.
|
||||||
|
LoadedObj load_textured_tetrahedron(const std::string &first_face, const std::string &vts = "vt 0.25 0.5\nvt 0.75 1\n")
|
||||||
{
|
{
|
||||||
ScopedTemporaryFile obj(".obj");
|
ScopedTemporaryFile obj(".obj");
|
||||||
ScopedTemporaryFile mtl(".mtl");
|
ScopedTemporaryFile mtl(".mtl");
|
||||||
@@ -30,7 +31,12 @@ LoadedObj load_textured_obj(const std::string &body)
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
boost::nowide::ofstream out(obj.string());
|
boost::nowide::ofstream out(obj.string());
|
||||||
out << "mtllib " << mtl.path().filename().string() << "\n" << body;
|
out << "mtllib " << mtl.path().filename().string() << "\n"
|
||||||
|
<< "v 0 0 0\nv 10 0 0\nv 0 10 0\nv 0 0 10\n"
|
||||||
|
<< vts
|
||||||
|
<< "usemtl a\n"
|
||||||
|
<< first_face << "\n"
|
||||||
|
<< "f 1/1 2/1 4/1\nf 1/1 4/1 3/1\nf 2/1 3/1 4/1\n";
|
||||||
}
|
}
|
||||||
LoadedObj loaded;
|
LoadedObj loaded;
|
||||||
std::string message;
|
std::string message;
|
||||||
@@ -38,21 +44,6 @@ LoadedObj load_textured_obj(const std::string &body)
|
|||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A tetrahedron with a material and two texture coordinates, (0.25, 0.5) and (0.75, 1).
|
|
||||||
// Only the first face and the vt lines are varied; the other three faces reference vt 1.
|
|
||||||
LoadedObj load_textured_tetrahedron(const std::string &first_face, const std::string &vts = "vt 0.25 0.5\nvt 0.75 1\n")
|
|
||||||
{
|
|
||||||
return load_textured_obj("v 0 0 0\nv 10 0 0\nv 0 10 0\nv 0 0 10\n" + vts + "usemtl a\n" + first_face + "\n" +
|
|
||||||
"f 1/1 2/1 4/1\nf 1/1 4/1 3/1\nf 2/1 3/1 4/1\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Texture coordinate n is (n / 10, n / 20), so a UV identifies the vt it came from.
|
|
||||||
void check_uv_is_vt(const Vec2f &uv, int vt)
|
|
||||||
{
|
|
||||||
CHECK_THAT(uv.x(), WithinAbs(vt / 10., 1e-6));
|
|
||||||
CHECK_THAT(uv.y(), WithinAbs(vt / 20., 1e-6));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST_CASE("An out-of-range texture index falls back to a zero UV and keeps the geometry", "[OBJ][Regression]")
|
TEST_CASE("An out-of-range texture index falls back to a zero UV and keeps the geometry", "[OBJ][Regression]")
|
||||||
@@ -129,39 +120,3 @@ TEST_CASE("A texture coordinate with w does not shift the indices of the ones af
|
|||||||
CHECK_THAT(uv[2].x(), WithinAbs(0.75, 1e-6));
|
CHECK_THAT(uv[2].x(), WithinAbs(0.75, 1e-6));
|
||||||
CHECK_THAT(uv[2].y(), WithinAbs(1., 1e-6));
|
CHECK_THAT(uv[2].y(), WithinAbs(1., 1e-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Both triangles of a quad take the texture coordinates of their own corners", "[OBJ][Regression]")
|
|
||||||
{
|
|
||||||
const LoadedObj loaded = load_textured_obj("v 0 0 0\nv 10 0 0\nv 10 10 0\nv 0 10 0\n"
|
|
||||||
"vt 0.1 0.05\nvt 0.2 0.1\nvt 0.3 0.15\nvt 0.4 0.2\n"
|
|
||||||
"usemtl a\n"
|
|
||||||
"f 1/1 2/2 3/3 4/4\n");
|
|
||||||
|
|
||||||
REQUIRE(loaded.ok);
|
|
||||||
REQUIRE(loaded.mesh.facets_count() == 2);
|
|
||||||
REQUIRE(loaded.info.uvs.size() == 2);
|
|
||||||
check_uv_is_vt(loaded.info.uvs[0][0], 1);
|
|
||||||
check_uv_is_vt(loaded.info.uvs[0][1], 2);
|
|
||||||
check_uv_is_vt(loaded.info.uvs[0][2], 3);
|
|
||||||
check_uv_is_vt(loaded.info.uvs[1][0], 1);
|
|
||||||
check_uv_is_vt(loaded.info.uvs[1][1], 3);
|
|
||||||
check_uv_is_vt(loaded.info.uvs[1][2], 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Texture coordinates follow the corners of a mesh that is flipped on load", "[OBJ][Regression]")
|
|
||||||
{
|
|
||||||
// The faces wind inwards, so the loader flips them. Vertex n uses vt n.
|
|
||||||
const LoadedObj loaded = load_textured_obj("v 0 0 0\nv 10 0 0\nv 0 10 0\nv 0 0 10\n"
|
|
||||||
"vt 0.1 0.05\nvt 0.2 0.1\nvt 0.3 0.15\nvt 0.4 0.2\n"
|
|
||||||
"usemtl a\n"
|
|
||||||
"f 1/1 2/2 3/3\nf 1/1 4/4 2/2\nf 1/1 3/3 4/4\nf 2/2 4/4 3/3\n");
|
|
||||||
|
|
||||||
REQUIRE(loaded.ok);
|
|
||||||
const indexed_triangle_set &its = loaded.mesh.its;
|
|
||||||
CHECK(its_volume(its) > 0.f);
|
|
||||||
REQUIRE(its.indices.size() == 4);
|
|
||||||
REQUIRE(loaded.info.uvs.size() == 4);
|
|
||||||
for (size_t face = 0; face < its.indices.size(); ++face)
|
|
||||||
for (int corner = 0; corner < 3; ++corner)
|
|
||||||
check_uv_is_vt(loaded.info.uvs[face][corner], its.indices[face][corner] + 1);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5482,39 +5482,3 @@ TEST_CASE("Config import confines zip entries, preset names and bundle ids to th
|
|||||||
CHECK_FALSE(any_filename_contains(temp_dir.path(), "bundle-escape"));
|
CHECK_FALSE(any_filename_contains(temp_dir.path(), "bundle-escape"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A project saved before a key joined filament_options_with_variant stores it once per filament,
|
|
||||||
// while the keys that were already per variant store it once per filament variant. Loading such a
|
|
||||||
// project gives every variant of a filament that filament's value.
|
|
||||||
TEST_CASE("A project saved with pressure advance per filament applies it to every variant of the filament", "[Preset][Bundle]")
|
|
||||||
{
|
|
||||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
|
||||||
config.opt<ConfigOptionStrings>("filament_colour")->values = { "#FF0000", "#00FF00" };
|
|
||||||
config.opt<ConfigOptionFloats>("filament_diameter")->values = { 1.75, 1.75 };
|
|
||||||
config.option<ConfigOptionStrings>("filament_settings_id", true)->values = { "Project PLA", "Project PETG" };
|
|
||||||
// A multi-variant printer: full_print_config() leaves the list out, and the loader splits the
|
|
||||||
// variant keys per filament only when the project carries it.
|
|
||||||
config.option<ConfigOptionStrings>("extruder_variant_list", true)->values = { "Direct Drive Standard,Direct Drive High Flow" };
|
|
||||||
// filament 1 defines Standard and High Flow, filament 2 Standard
|
|
||||||
config.opt<ConfigOptionStrings>("filament_extruder_variant")->values = { "Direct Drive Standard", "Direct Drive High Flow", "Direct Drive Standard" };
|
|
||||||
config.opt<ConfigOptionInts>("filament_self_index")->values = { 1, 1, 2 };
|
|
||||||
config.opt<ConfigOptionFloatsNullable>("filament_flow_ratio")->values = { 0.95, 0.96, 0.97 }; // one per filament variant
|
|
||||||
// One per filament, read through the loader that project files go through.
|
|
||||||
config.load_from_ini_string("pressure_advance = 0.021,0.043", ForwardCompatibilitySubstitutionRule::Disable);
|
|
||||||
// The CLI slices the config as loaded.
|
|
||||||
check_double_vector(config.opt<ConfigOptionFloats>("pressure_advance")->values, { 0.021, 0.021, 0.043 });
|
|
||||||
check_double_vector(config.opt<ConfigOptionFloatsNullable>("filament_flow_ratio")->values, { 0.95, 0.96, 0.97 });
|
|
||||||
// The GUI normalizes the config before load; mirror that so only the production path runs.
|
|
||||||
Preset::normalize(config);
|
|
||||||
|
|
||||||
PresetBundle bundle;
|
|
||||||
bundle.load_config_model("test.3mf", std::move(config));
|
|
||||||
|
|
||||||
REQUIRE(bundle.filament_presets.size() == 2);
|
|
||||||
const DynamicPrintConfig &pla = bundle.filaments.find_preset(bundle.filament_presets[0], false, true)->config;
|
|
||||||
const DynamicPrintConfig &petg = bundle.filaments.find_preset(bundle.filament_presets[1], false, true)->config;
|
|
||||||
check_double_vector(pla.opt<ConfigOptionFloats>("pressure_advance")->values, { 0.021, 0.021 });
|
|
||||||
check_double_vector(petg.opt<ConfigOptionFloats>("pressure_advance")->values, { 0.043 });
|
|
||||||
check_double_vector(pla.opt<ConfigOptionFloatsNullable>("filament_flow_ratio")->values, { 0.95, 0.96 });
|
|
||||||
check_double_vector(petg.opt<ConfigOptionFloatsNullable>("filament_flow_ratio")->values, { 0.97 });
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -322,68 +322,3 @@ TEST_CASE("is_symlink_target_within_root rejects a target that passes through a
|
|||||||
CHECK(is_symlink_target_within_root("link", "in/lib.so", root));
|
CHECK(is_symlink_target_within_root("link", "in/lib.so", root));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST_CASE("is_absolute_path_within_root accepts only entries inside the root", "[utils]") {
|
|
||||||
namespace fs = boost::filesystem;
|
|
||||||
ScopedTemporaryDir outer;
|
|
||||||
const fs::path root = outer.path() / "Auxiliaries";
|
|
||||||
fs::create_directories(root / "Others");
|
|
||||||
const fs::path inside = root / "Others" / "note.txt";
|
|
||||||
const fs::path outside = outer.path() / "secret.txt";
|
|
||||||
std::ofstream(inside.string()) << "inside";
|
|
||||||
std::ofstream(outside.string()) << "outside";
|
|
||||||
|
|
||||||
SECTION("a file inside the root") {
|
|
||||||
REQUIRE(is_absolute_path_within_root(inside, root));
|
|
||||||
}
|
|
||||||
SECTION("a path inside the root whose file does not exist yet") {
|
|
||||||
REQUIRE(is_absolute_path_within_root(root / "Others" / "missing.txt", root));
|
|
||||||
}
|
|
||||||
SECTION("the root itself") {
|
|
||||||
REQUIRE_FALSE(is_absolute_path_within_root(root, root));
|
|
||||||
}
|
|
||||||
SECTION("a parent-directory escape spelled under the root") {
|
|
||||||
REQUIRE_FALSE(is_absolute_path_within_root(root / "Others" / ".." / ".." / "secret.txt", root));
|
|
||||||
}
|
|
||||||
SECTION("an absolute path elsewhere") {
|
|
||||||
REQUIRE_FALSE(is_absolute_path_within_root(outside, root));
|
|
||||||
}
|
|
||||||
SECTION("a sibling directory sharing the root's name as a prefix") {
|
|
||||||
const fs::path sibling = outer.path() / "Auxiliaries2" / "note.txt";
|
|
||||||
REQUIRE_FALSE(is_absolute_path_within_root(sibling, root));
|
|
||||||
}
|
|
||||||
SECTION("a relative path") {
|
|
||||||
REQUIRE_FALSE(is_absolute_path_within_root(fs::path("Others") / "note.txt", root));
|
|
||||||
}
|
|
||||||
SECTION("an empty path") {
|
|
||||||
REQUIRE_FALSE(is_absolute_path_within_root(fs::path(), root));
|
|
||||||
}
|
|
||||||
#ifndef _WIN32
|
|
||||||
// Creating symlinks on Windows needs elevated rights or developer mode.
|
|
||||||
SECTION("a symlink inside the root that points outside") {
|
|
||||||
const fs::path link = root / "Others" / "link.txt";
|
|
||||||
fs::create_symlink(outside, link);
|
|
||||||
REQUIRE_FALSE(is_absolute_path_within_root(link, root));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("is_safe_to_open_file_name accepts plain documents, images and models", "[utils]") {
|
|
||||||
const std::string safe = GENERATE(as<std::string>{},
|
|
||||||
"Manual.pdf", "BOM.xlsx", "BOM.csv", "guide.docx", "notes.txt", "README.md", "photo.JPG", "render.png",
|
|
||||||
"assembly.step", "part.stl", "project.3mf", "drawing.dxf", "build.mp4", "setup.exe.pdf", ".pdf");
|
|
||||||
INFO(safe);
|
|
||||||
CHECK(is_safe_to_open_file_name(safe));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("is_safe_to_open_file_name rejects programs and anything it does not know", "[utils]") {
|
|
||||||
const std::string unsafe = GENERATE(as<std::string>{},
|
|
||||||
"setup.exe", "SETUP.EXE", "Manual.pdf.exe", "run.bat", "shortcut.lnk", "site.url", "script.ps1", "help.chm",
|
|
||||||
"tool.jar", "script.py", "Install.command", "install.sh", "launcher.desktop", "Printer.AppImage",
|
|
||||||
// Documents that can carry macros or scripts.
|
|
||||||
"BOM.xls", "BOM.xlsm", "guide.doc", "guide.docm", "sheet.ods", "page.html", "logo.svg", "bundle.zip",
|
|
||||||
// No extension, an unknown one, or a name the desktop would read differently.
|
|
||||||
"readme", "pdf", "data.xyz", "", "...", "Manual.pdf.", "Manual.pdf ", "setup.exe:note.txt", "dir.pdf/readme");
|
|
||||||
INFO(unsafe);
|
|
||||||
CHECK_FALSE(is_safe_to_open_file_name(unsafe));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ add_executable(${_TEST_NAME}_tests
|
|||||||
test_plugin_audit.cpp
|
test_plugin_audit.cpp
|
||||||
test_shortcuts.cpp
|
test_shortcuts.cpp
|
||||||
test_file_url.cpp
|
test_file_url.cpp
|
||||||
test_user_manager.cpp
|
|
||||||
../fff_print/test_helpers.cpp
|
../fff_print/test_helpers.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
#include <catch2/catch_all.hpp>
|
#include <catch2/catch_all.hpp>
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "libslic3r/LifecycleEvents.hpp"
|
|
||||||
#include "slic3r/Utils/PrintHost.hpp"
|
#include "slic3r/Utils/PrintHost.hpp"
|
||||||
#include "slic3r/Utils/Flashforge.hpp"
|
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
|
|
||||||
@@ -31,41 +24,6 @@ public:
|
|||||||
std::string get_host() const override { return {}; }
|
std::string get_host() const override { return {}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThrowingPrintHost : public TestPrintHost
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool upload(PrintHostUpload, ProgressFn, ErrorFn, InfoFn) const override { throw std::runtime_error("reply could not be read"); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UploadEvents
|
|
||||||
{
|
|
||||||
std::vector<LifecycleEvent> events;
|
|
||||||
std::vector<LifecycleEvtCode> codes;
|
|
||||||
std::vector<std::string> errors;
|
|
||||||
bool uploaded{false};
|
|
||||||
|
|
||||||
explicit UploadEvents(std::unique_ptr<PrintHost> host)
|
|
||||||
{
|
|
||||||
set_lifecycle_hook_fn([this](LifecycleEvent event, const LifecycleEventContext& ctx) {
|
|
||||||
events.push_back(event);
|
|
||||||
codes.push_back(ctx.code);
|
|
||||||
});
|
|
||||||
|
|
||||||
PrintHostJob job;
|
|
||||||
job.printhost = std::move(host);
|
|
||||||
job.upload_data.source_path = "plate.gcode";
|
|
||||||
try {
|
|
||||||
uploaded = PrintHostJobQueue::upload_job(job, [](Http::Progress, bool&) {},
|
|
||||||
[this](wxString error) { errors.push_back(error.ToStdString()); },
|
|
||||||
[](wxString, wxString) {});
|
|
||||||
} catch (...) {
|
|
||||||
set_lifecycle_hook_fn(nullptr);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
set_lifecycle_hook_fn(nullptr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string format_error(const std::string& body, const std::string& error, unsigned status)
|
std::string format_error(const std::string& body, const std::string& error, unsigned status)
|
||||||
{
|
{
|
||||||
return TestPrintHost().format_error(body, error, status).ToStdString();
|
return TestPrintHost().format_error(body, error, status).ToStdString();
|
||||||
@@ -88,14 +46,6 @@ std::string moonraker_error(int code, const std::string& message, const std::str
|
|||||||
constexpr const char* k_busy_file_403 =
|
constexpr const char* k_busy_file_403 =
|
||||||
R"JSON({"error": {"code": 403, "message": "Forbidden", "traceback": "Traceback (most recent call last):\n\n File \"/home/lava/moonraker/moonraker/components/file_manager/file_manager.py\", line 1017, in _finish_gcode_upload\n can_start = self._handle_operation_check(check_path)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nmoonraker.utils.exceptions.ServerError: File currently in use\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n\n File \"/home/lava/moonraker/moonraker/components/application.py\", line 1069, in post\n raise tornado.web.HTTPError(\ntornado.web.HTTPError: HTTP 403: Forbidden (File is loaded, upload not permitted)\n"}})JSON";
|
R"JSON({"error": {"code": 403, "message": "Forbidden", "traceback": "Traceback (most recent call last):\n\n File \"/home/lava/moonraker/moonraker/components/file_manager/file_manager.py\", line 1017, in _finish_gcode_upload\n can_start = self._handle_operation_check(check_path)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nmoonraker.utils.exceptions.ServerError: File currently in use\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n\n File \"/home/lava/moonraker/moonraker/components/application.py\", line 1069, in post\n raise tornado.web.HTTPError(\ntornado.web.HTTPError: HTTP 403: Forbidden (File is loaded, upload not permitted)\n"}})JSON";
|
||||||
|
|
||||||
// Replies a print host can send instead of JSON: a proxy or login page, nothing, a cut-off body.
|
|
||||||
const std::vector<std::string> non_json_replies = {
|
|
||||||
"<html><body>proxy login required</body></html>",
|
|
||||||
"",
|
|
||||||
"{\"err\":",
|
|
||||||
"{\"detail\":{\"matlStationInfo\":{\"slotInfos\":[{\"slotId\":1,",
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST_CASE("A Klipper upload error shows its reason instead of a Python traceback", "[PrintHost][Regression]")
|
TEST_CASE("A Klipper upload error shows its reason instead of a Python traceback", "[PrintHost][Regression]")
|
||||||
@@ -261,114 +211,3 @@ TEST_CASE("Error bodies that are not a Moonraker envelope are left unchanged", "
|
|||||||
CHECK(format_error("", "curl:Could not connect", 0) == "curl:Could not connect");
|
CHECK(format_error("", "curl:Could not connect", 0) == "curl:Could not connect");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Print host error code is read from a JSON reply", "[PrintHost]")
|
|
||||||
{
|
|
||||||
CHECK(PrintHost::get_err_code_from_body(R"({"err":0})") == 0);
|
|
||||||
CHECK(PrintHost::get_err_code_from_body(R"({"err":2})") == 2);
|
|
||||||
CHECK(PrintHost::get_err_code_from_body(R"({"status":"ok"})") == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Print host error code reports a reply that is not JSON as an error", "[PrintHost]")
|
|
||||||
{
|
|
||||||
const std::string body = GENERATE(from_range(non_json_replies));
|
|
||||||
int err = 0;
|
|
||||||
REQUIRE_NOTHROW(err = PrintHost::get_err_code_from_body(body));
|
|
||||||
CHECK(err != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Print host error code tolerates a wrongly typed err field", "[PrintHost]")
|
|
||||||
{
|
|
||||||
const std::string body = GENERATE(as<std::string>{}, R"({"err":"busy"})", R"({"err":{"code":1}})", R"([1,2])");
|
|
||||||
CHECK_NOTHROW(PrintHost::get_err_code_from_body(body));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Flashforge material slots are read from a well-formed reply", "[PrintHost][Flashforge]")
|
|
||||||
{
|
|
||||||
const std::string body = R"({"code":0,"detail":{"hasMatlStation":true,"matlStationInfo":{"slotCnt":2,"slotInfos":[
|
|
||||||
{"slotId":1,"hasFilament":true,"materialName":"PLA","materialColor":"#FFFFFF"},
|
|
||||||
{"slotId":2,"hasFilament":false,"materialName":"","materialColor":""}]}}})";
|
|
||||||
|
|
||||||
std::vector<FlashforgeMaterialSlot> slots;
|
|
||||||
bool supports_station = false;
|
|
||||||
REQUIRE(Flashforge::parse_material_slots(body, slots, &supports_station));
|
|
||||||
CHECK(supports_station);
|
|
||||||
REQUIRE(slots.size() == 2);
|
|
||||||
CHECK(slots[0].slot_id == 1);
|
|
||||||
CHECK(slots[0].has_filament);
|
|
||||||
CHECK(slots[0].material_name == "PLA");
|
|
||||||
CHECK(slots[0].material_color == "#FFFFFF");
|
|
||||||
CHECK(slots[1].slot_id == 2);
|
|
||||||
CHECK_FALSE(slots[1].has_filament);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Flashforge material slots accept numbers as strings and flags as numbers", "[PrintHost][Flashforge]")
|
|
||||||
{
|
|
||||||
const std::string body = R"({"detail":{"matlStationInfo":{"slotInfos":[
|
|
||||||
{"slotId":"3","hasFilament":1,"materialName":null,"materialColor":7}]}}})";
|
|
||||||
|
|
||||||
std::vector<FlashforgeMaterialSlot> slots;
|
|
||||||
REQUIRE_NOTHROW(Flashforge::parse_material_slots(body, slots, nullptr));
|
|
||||||
REQUIRE(slots.size() == 1);
|
|
||||||
CHECK(slots[0].slot_id == 3);
|
|
||||||
CHECK(slots[0].has_filament);
|
|
||||||
CHECK(slots[0].material_name.empty());
|
|
||||||
CHECK(slots[0].material_color.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Flashforge material slots skip entries that are not objects", "[PrintHost][Flashforge]")
|
|
||||||
{
|
|
||||||
const std::string body = R"({"detail":{"matlStationInfo":{"slotInfos":[5,"slot",null,[],
|
|
||||||
{"slotId":4,"hasFilament":true,"materialName":"PETG"}]}}})";
|
|
||||||
|
|
||||||
std::vector<FlashforgeMaterialSlot> slots;
|
|
||||||
REQUIRE_NOTHROW(Flashforge::parse_material_slots(body, slots, nullptr));
|
|
||||||
REQUIRE(slots.size() == 1);
|
|
||||||
CHECK(slots[0].slot_id == 4);
|
|
||||||
CHECK(slots[0].material_name == "PETG");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Flashforge material slots tolerate slot info that is not a list", "[PrintHost][Flashforge]")
|
|
||||||
{
|
|
||||||
const std::string body = GENERATE(as<std::string>{},
|
|
||||||
R"({"detail":{"matlStationInfo":{"slotInfos":5}}})",
|
|
||||||
R"({"detail":{"matlStationInfo":{"slotInfos":"none"}}})",
|
|
||||||
R"({"detail":{"matlStationInfo":7}})",
|
|
||||||
R"({"detail":"offline"})");
|
|
||||||
|
|
||||||
std::vector<FlashforgeMaterialSlot> slots;
|
|
||||||
bool ok = false;
|
|
||||||
REQUIRE_NOTHROW(ok = Flashforge::parse_material_slots(body, slots, nullptr));
|
|
||||||
CHECK(ok);
|
|
||||||
CHECK(slots.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Flashforge material slots reject a reply that is not JSON", "[PrintHost][Flashforge]")
|
|
||||||
{
|
|
||||||
const std::string body = GENERATE(from_range(non_json_replies));
|
|
||||||
std::vector<FlashforgeMaterialSlot> slots;
|
|
||||||
bool ok = true;
|
|
||||||
REQUIRE_NOTHROW(ok = Flashforge::parse_material_slots(body, slots, nullptr));
|
|
||||||
CHECK_FALSE(ok);
|
|
||||||
CHECK(slots.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("An upload that throws still finishes with an error", "[PrintHost][LifecycleEvents]")
|
|
||||||
{
|
|
||||||
UploadEvents run(std::make_unique<ThrowingPrintHost>());
|
|
||||||
|
|
||||||
CHECK_FALSE(run.uploaded);
|
|
||||||
CHECK(run.errors == std::vector<std::string>{"reply could not be read"});
|
|
||||||
CHECK(run.events == std::vector<LifecycleEvent>{LifecycleEvent::UploadStarted, LifecycleEvent::UploadFinished});
|
|
||||||
CHECK(run.codes == std::vector<LifecycleEvtCode>{LifecycleEvtCode::Ok, LifecycleEvtCode::Error});
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("A successful upload finishes without an error", "[PrintHost][LifecycleEvents]")
|
|
||||||
{
|
|
||||||
UploadEvents run(std::make_unique<TestPrintHost>());
|
|
||||||
|
|
||||||
CHECK(run.uploaded);
|
|
||||||
CHECK(run.errors.empty());
|
|
||||||
CHECK(run.events == std::vector<LifecycleEvent>{LifecycleEvent::UploadStarted, LifecycleEvent::UploadFinished});
|
|
||||||
CHECK(run.codes == std::vector<LifecycleEvtCode>{LifecycleEvtCode::Ok, LifecycleEvtCode::Ok});
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
#include <catch2/catch_all.hpp>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "slic3r/GUI/UserManager.hpp"
|
|
||||||
|
|
||||||
using namespace Slic3r;
|
|
||||||
|
|
||||||
TEST_CASE("User message that is not JSON is rejected without throwing", "[UserManager]")
|
|
||||||
{
|
|
||||||
const std::string payload = GENERATE(as<std::string>{}, "not json", "", "<html></html>", "{\"bind\":");
|
|
||||||
UserManager manager;
|
|
||||||
int result = 0;
|
|
||||||
REQUIRE_NOTHROW(result = manager.parse_json(payload));
|
|
||||||
CHECK(result == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("User message without a successful bind is ignored", "[UserManager]")
|
|
||||||
{
|
|
||||||
const std::string payload = GENERATE(as<std::string>{}, "{}", R"({"bind":{"command":"unbind"}})", R"({"bind":"bind"})", "[1]");
|
|
||||||
UserManager manager;
|
|
||||||
CHECK(manager.parse_json(payload) == -1);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user