mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-15 15:03:49 +00:00
Add real slice validation for all printers (#14771)
# Description Adds a --slice (-s) mode to the profile validator that slices a two-colour cube through every shipped printer, expanding all custom g-code (change_filament_gcode, machine start/end, etc.). This catches invalid-placeholder / bad-flow / slicing errors that the static JSON checks and unit tests can't see. Included: - Validator: new -s sweep mode; per-profile error attribution in the log; resolves the synthetic 2nd-filament nozzle-mapping so multi-nozzle BBL printers (incl. the Direct-Drive+Bowden X2D) validate cleanly. - CI, two complementary paths: - check_profiles.yml — runs the sweep on profile-only PRs (nightly binary). - build_all.yml — new parallel slice_check_linux job runs it on engine/src PRs with the PR-built binary (build_all doesn't trigger on resources/**, so no overlap). Runs off the build's artifact, so it doesn't lengthen the build leg. - Profile fixes surfaced by the sweep: Creality, FLSun, Ginger, Qidi, RatRig, iQ. - Engine: whitelist BBL firmware T-opcodes (T1001/T65279/T65535) in the time estimator (log-only, no g-code change); dedupe a per-filament/per-layer log flood in get_config_index. # Screenshots/Recordings/Graphs <!-- > Please attach relevant screenshots to showcase the UI changes. > Please attach images that can help explain the changes. --> ## Tests <!-- > Please describe the tests that you have conducted to verify the changes made in this PR. --> <!-- > A guide for users on how to download the artifacts from this PR. --> [How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
This commit is contained in:
24
.github/workflows/build_all.yml
vendored
24
.github/workflows/build_all.yml
vendored
@@ -165,6 +165,30 @@ jobs:
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-14' }}
|
||||
artifact: ${{ github.sha }}-tests-macos-arm64
|
||||
test-dir: build/arm64/tests
|
||||
# Slice a two-colour cube through every shipped printer with this PR's engine
|
||||
# so all custom g-code (change_filament_gcode, machine start/end, etc.) is
|
||||
# expanded - catches slicing regressions the static profile checks and unit
|
||||
# tests can't see. Profile-only PRs are covered by check_profiles.yml (nightly
|
||||
# binary); this covers src/engine PRs with the PR-built binary. Runs in
|
||||
# parallel off build_linux's artifact so it doesn't lengthen the build leg.
|
||||
slice_check_linux:
|
||||
name: Slice check (Linux x86_64)
|
||||
needs: build_linux
|
||||
if: ${{ !cancelled() && success() }}
|
||||
runs-on: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-24.04' }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
- name: Download profile validator
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: ${{ github.sha }}-profile-validator-linux-x86_64
|
||||
path: validator-bin
|
||||
- name: Validate slice (expand custom g-code)
|
||||
timeout-minutes: 60
|
||||
run: |
|
||||
chmod +x validator-bin/OrcaSlicer_profile_validator
|
||||
./validator-bin/OrcaSlicer_profile_validator -p "${{ github.workspace }}/resources/profiles" -s -l 2
|
||||
publish_test_results:
|
||||
name: Publish Test Results
|
||||
needs: [unit_tests_linux_x86_64, unit_tests_linux_aarch64, unit_tests_windows_x64, unit_tests_windows_arm64, unit_tests_macos_arm64]
|
||||
|
||||
14
.github/workflows/build_orca.yml
vendored
14
.github/workflows/build_orca.yml
vendored
@@ -508,6 +508,20 @@ jobs:
|
||||
retention-days: 5
|
||||
if-no-files-found: error
|
||||
|
||||
# Ship the freshly-built validator so the parallel slice_check_linux job
|
||||
# (build_all.yml) can slice-sweep the shipped profiles with this PR's
|
||||
# engine. Stable sha-based name mirrors the tests artifact above so the
|
||||
# downstream job downloads it by exact name.
|
||||
- name: Upload profile validator (for slice check)
|
||||
if: runner.os == 'Linux' && inputs.arch != 'aarch64'
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ github.sha }}-profile-validator-linux-x86_64
|
||||
overwrite: true
|
||||
path: ./build/src/Release/OrcaSlicer_profile_validator
|
||||
retention-days: 5
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Run external slicer regression tests
|
||||
if: runner.os == 'Linux' && inputs.arch != 'aarch64'
|
||||
timeout-minutes: 20
|
||||
|
||||
22
.github/workflows/check_profiles.yml
vendored
22
.github/workflows/check_profiles.yml
vendored
@@ -49,6 +49,15 @@ jobs:
|
||||
set +e
|
||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 2>&1 | tee ${{ runner.temp }}/validate_system.log
|
||||
exit ${PIPESTATUS[0]}
|
||||
# Slice a two-colour cube through every printer so all custom g-code (incl. change_filament_gcode)
|
||||
# is expanded - catches undefined-placeholder / invalid-flow bugs the static checks above cannot see.
|
||||
- name: validate slice (expand custom g-code)
|
||||
id: validate_slice
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set +e
|
||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -s -l 2 2>&1 | tee ${{ runner.temp }}/validate_slice.log
|
||||
exit ${PIPESTATUS[0]}
|
||||
# For now run filament subtype check only for BBL profiles until we fix other vendors' profiles.
|
||||
- name: validate filament subtype check for BBL profiles
|
||||
id: validate_filament_subtypes
|
||||
@@ -166,7 +175,7 @@ jobs:
|
||||
echo "${{ github.event.pull_request.number }}" > ${{ runner.temp }}/profile-check-results/pr_number.txt
|
||||
|
||||
- name: Prepare comment artifact
|
||||
if: ${{ always() && github.event_name == 'pull_request' && (steps.extra_json_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
if: ${{ always() && github.event_name == 'pull_request' && (steps.extra_json_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_slice.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
run: |
|
||||
{
|
||||
# Marker matched by check_profiles_comment.yml to delete prior comments.
|
||||
@@ -192,6 +201,15 @@ jobs:
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "${{ steps.validate_slice.outcome }}" = "failure" ]; then
|
||||
echo "### Slice Validation Failed (custom g-code expansion)"
|
||||
echo ""
|
||||
echo '```'
|
||||
head -c 30000 ${{ runner.temp }}/validate_slice.log || echo "No output captured"
|
||||
echo '```'
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "${{ steps.validate_filament_subtypes.outcome }}" = "failure" ]; then
|
||||
echo "### BBL Filament Subtype Validation Failed"
|
||||
echo ""
|
||||
@@ -223,7 +241,7 @@ jobs:
|
||||
retention-days: 1
|
||||
|
||||
- name: Fail if any check failed
|
||||
if: ${{ always() && (steps.extra_json_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
if: ${{ always() && (steps.extra_json_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_slice.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
run: |
|
||||
echo "One or more profile checks failed. See above for details."
|
||||
exit 1
|
||||
|
||||
6
.github/workflows/unit_tests.yml
vendored
6
.github/workflows/unit_tests.yml
vendored
@@ -28,11 +28,15 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
# tests/data is referenced by absolute path (TEST_DATA_DIR).
|
||||
# Tests reach outside tests/ at runtime: tests/data (TEST_DATA_DIR) and
|
||||
# resources/profiles (PROFILES_DIR) by baked-in absolute path, plus
|
||||
# resources/info (nozzle data) via resources_dir() during a real slice.
|
||||
# Check out all of resources/ so no test hits a missing-file path.
|
||||
sparse-checkout: |
|
||||
.github
|
||||
scripts
|
||||
tests
|
||||
resources
|
||||
- name: Apt-Install Dependencies
|
||||
if: runner.os == 'Linux' && !vars.SELF_HOSTED
|
||||
uses: ./.github/actions/apt-install-deps
|
||||
|
||||
@@ -1230,6 +1230,10 @@
|
||||
"name": "0.40mm Standard @Creality K1C",
|
||||
"sub_path": "process/0.40mm Standard @Creality K1C 0.8 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "0.40mm Standard @Creality K1 SE 0.8 nozzle",
|
||||
"sub_path": "process/0.40mm Standard @Creality K1 SE 0.8 nozzle.json"
|
||||
},
|
||||
{
|
||||
"name": "0.40mm Standard @Creality K1Max (0.8 nozzle)",
|
||||
"sub_path": "process/0.40mm Standard @Creality K1Max (0.8 nozzle).json"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"Creality Generic PLA"
|
||||
],
|
||||
"printer_variant": "0.2",
|
||||
"default_print_profile": "0.16mm Opitmal @Creality CR-6 0.2",
|
||||
"default_print_profile": "0.16mm Optimal @Creality CR-6 0.2",
|
||||
"nozzle_diameter": [
|
||||
"0.2"
|
||||
],
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"Creality Generic PLA"
|
||||
],
|
||||
"printer_variant": "0.2",
|
||||
"default_print_profile": "0.16mm Opitmal @Creality CR-6 0.2",
|
||||
"default_print_profile": "0.16mm Optimal @Creality CR-6 0.2",
|
||||
"nozzle_diameter": [
|
||||
"0.2"
|
||||
],
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
"support_on_build_plate_only": "0",
|
||||
"support_top_z_distance": "0.15",
|
||||
"support_filament": "0",
|
||||
"support_line_width": "0.18",
|
||||
"support_line_width": "0.22",
|
||||
"support_interface_loop_pattern": "0",
|
||||
"support_interface_filament": "0",
|
||||
"support_interface_top_layers": "3",
|
||||
@@ -85,7 +85,7 @@
|
||||
"tree_support_wall_count": "0",
|
||||
"detect_thin_wall": "1",
|
||||
"top_surface_pattern": "monotonicline",
|
||||
"top_surface_line_width": "0.2",
|
||||
"top_surface_line_width": "0.25",
|
||||
"top_shell_layers": "5",
|
||||
"top_shell_thickness": "0.8",
|
||||
"initial_layer_speed": "35%",
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
"support_on_build_plate_only": "0",
|
||||
"support_top_z_distance": "0.15",
|
||||
"support_filament": "0",
|
||||
"support_line_width": "0.18",
|
||||
"support_line_width": "0.22",
|
||||
"support_interface_loop_pattern": "0",
|
||||
"support_interface_filament": "0",
|
||||
"support_interface_top_layers": "3",
|
||||
@@ -85,7 +85,7 @@
|
||||
"tree_support_wall_count": "0",
|
||||
"detect_thin_wall": "1",
|
||||
"top_surface_pattern": "monotonicline",
|
||||
"top_surface_line_width": "0.2",
|
||||
"top_surface_line_width": "0.25",
|
||||
"top_shell_layers": "5",
|
||||
"top_shell_thickness": "0.8",
|
||||
"initial_layer_speed": "35%",
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
"skirt_height": "2",
|
||||
"skirt_loops": "2",
|
||||
"minimum_sparse_infill_area": "10",
|
||||
"internal_solid_infill_line_width": "0.2",
|
||||
"internal_solid_infill_line_width": "0.25",
|
||||
"spiral_mode": "0",
|
||||
"standby_temperature_delta": "-5",
|
||||
"enable_support": "0",
|
||||
@@ -69,7 +69,7 @@
|
||||
"support_on_build_plate_only": "0",
|
||||
"support_top_z_distance": "0.15",
|
||||
"support_filament": "0",
|
||||
"support_line_width": "0.18",
|
||||
"support_line_width": "0.22",
|
||||
"support_interface_loop_pattern": "0",
|
||||
"support_interface_filament": "0",
|
||||
"support_interface_top_layers": "3",
|
||||
@@ -85,7 +85,7 @@
|
||||
"tree_support_wall_count": "0",
|
||||
"detect_thin_wall": "1",
|
||||
"top_surface_pattern": "monotonicline",
|
||||
"top_surface_line_width": "0.2",
|
||||
"top_surface_line_width": "0.25",
|
||||
"top_shell_layers": "7",
|
||||
"top_shell_thickness": "0.8",
|
||||
"initial_layer_speed": "35%",
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
"support_on_build_plate_only": "0",
|
||||
"support_top_z_distance": "0.15",
|
||||
"support_filament": "0",
|
||||
"support_line_width": "0.18",
|
||||
"support_line_width": "0.22",
|
||||
"support_interface_loop_pattern": "0",
|
||||
"support_interface_filament": "0",
|
||||
"support_interface_top_layers": "2",
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.40mm Standard @Creality K1 SE 0.8 nozzle",
|
||||
"inherits": "fdm_process_creality_common",
|
||||
"from": "system",
|
||||
"setting_id": "caYmVSsFmtESzLNF",
|
||||
"instantiation": "true",
|
||||
"reduce_crossing_wall": "0",
|
||||
"max_travel_detour_distance": "0",
|
||||
"bottom_surface_pattern": "monotonic",
|
||||
"bottom_shell_layers": "3",
|
||||
"bottom_shell_thickness": "0",
|
||||
"bridge_flow": "0.8",
|
||||
"bridge_speed": "10",
|
||||
"brim_width": "5",
|
||||
"brim_object_gap": "0.1",
|
||||
"print_sequence": "by layer",
|
||||
"default_acceleration": "10000",
|
||||
"bridge_no_support": "0",
|
||||
"draft_shield": "disabled",
|
||||
"elefant_foot_compensation": "0.15",
|
||||
"outer_wall_line_width": "0.82",
|
||||
"outer_wall_speed": "100",
|
||||
"outer_wall_acceleration": "2000",
|
||||
"inner_wall_acceleration": "2000",
|
||||
"line_width": "0.82",
|
||||
"infill_direction": "45",
|
||||
"sparse_infill_density": "15%",
|
||||
"sparse_infill_pattern": "grid",
|
||||
"initial_layer_acceleration": "500",
|
||||
"initial_layer_line_width": "0.82",
|
||||
"initial_layer_print_height": "0.4",
|
||||
"initial_layer_speed": "40",
|
||||
"gap_infill_speed": "50",
|
||||
"infill_combination": "0",
|
||||
"sparse_infill_line_width": "0.82",
|
||||
"infill_wall_overlap": "30",
|
||||
"sparse_infill_speed": "150",
|
||||
"interface_shells": "0",
|
||||
"ironing_flow": "10%",
|
||||
"ironing_spacing": "0.15",
|
||||
"ironing_speed": "30",
|
||||
"ironing_type": "no ironing",
|
||||
"layer_height": "0.4",
|
||||
"reduce_infill_retraction": "1",
|
||||
"filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode",
|
||||
"detect_overhang_wall": "1",
|
||||
"overhang_1_4_speed": "50",
|
||||
"overhang_2_4_speed": "35",
|
||||
"overhang_3_4_speed": "20",
|
||||
"overhang_4_4_speed": "10",
|
||||
"only_one_wall_top": "1",
|
||||
"inner_wall_line_width": "0.82",
|
||||
"inner_wall_speed": "150",
|
||||
"wall_loops": "2",
|
||||
"raft_layers": "0",
|
||||
"seam_position": "aligned",
|
||||
"seam_slope_conditional": "0",
|
||||
"seam_slope_inner_walls": "0",
|
||||
"seam_slope_entire_loop": "0",
|
||||
"skirt_distance": "2",
|
||||
"skirt_height": "1",
|
||||
"skirt_loops": "0",
|
||||
"minimum_sparse_infill_area": "15",
|
||||
"internal_solid_infill_line_width": "0.82",
|
||||
"internal_solid_infill_speed": "150",
|
||||
"spiral_mode": "0",
|
||||
"initial_layer_infill_speed": "60",
|
||||
"standby_temperature_delta": "-5",
|
||||
"enable_support": "0",
|
||||
"resolution": "0.012",
|
||||
"support_type": "normal(auto)",
|
||||
"support_style": "default",
|
||||
"support_on_build_plate_only": "0",
|
||||
"support_top_z_distance": "0.2",
|
||||
"support_bottom_z_distance": "0.2",
|
||||
"support_filament": "0",
|
||||
"support_line_width": "0.82",
|
||||
"support_interface_loop_pattern": "0",
|
||||
"support_interface_filament": "0",
|
||||
"support_interface_top_layers": "2",
|
||||
"support_interface_bottom_layers": "2",
|
||||
"support_interface_spacing": "0.5",
|
||||
"support_expansion": "0",
|
||||
"support_interface_speed": "80",
|
||||
"support_base_pattern": "rectilinear",
|
||||
"support_base_pattern_spacing": "2.5",
|
||||
"support_speed": "150",
|
||||
"support_threshold_angle": "30",
|
||||
"support_object_xy_distance": "0.35",
|
||||
"tree_support_branch_diameter": "2",
|
||||
"tree_support_branch_angle": "45",
|
||||
"tree_support_wall_count": "0",
|
||||
"detect_thin_wall": "0",
|
||||
"top_surface_pattern": "monotonicline",
|
||||
"top_surface_line_width": "0.82",
|
||||
"top_surface_acceleration": "2000",
|
||||
"top_surface_speed": "100",
|
||||
"top_shell_layers": "3",
|
||||
"top_shell_thickness": "0.8",
|
||||
"travel_acceleration": "10000",
|
||||
"travel_speed": "500",
|
||||
"enable_prime_tower": "0",
|
||||
"wipe_tower_no_sparse_layers": "0",
|
||||
"prime_tower_width": "60",
|
||||
"xy_hole_compensation": "0",
|
||||
"xy_contour_compensation": "0",
|
||||
"gcode_label_objects": "0",
|
||||
"compatible_printers": [
|
||||
"Creality K1 SE 0.8 nozzle"
|
||||
],
|
||||
"accel_to_decel_enable": "1",
|
||||
"accel_to_decel_factor": "50",
|
||||
"acceleration_limit_mess_enable": "0",
|
||||
"ai_infill": "0",
|
||||
"alternate_extra_wall": "0",
|
||||
"bottom_solid_infill_flow_ratio": "1",
|
||||
"bridge_acceleration": "50%",
|
||||
"bridge_angle": "0",
|
||||
"bridge_density": "100%",
|
||||
"brim_ears_detection_length": "1",
|
||||
"brim_ears_max_angle": "125",
|
||||
"brim_type": "auto_brim",
|
||||
"counterbore_hole_bridging": "none",
|
||||
"default_jerk": "6",
|
||||
"detect_narrow_internal_solid_infill": "1",
|
||||
"dont_filter_internal_bridges": "disabled",
|
||||
"elefant_foot_compensation_layers": "1",
|
||||
"enable_arc_fitting": "1",
|
||||
"enable_overhang_speed": "1",
|
||||
"enforce_support_layers": "0",
|
||||
"ensure_vertical_shell_thickness": "ensure_all",
|
||||
"exclude_object": "1",
|
||||
"extra_perimeters_on_overhangs": "0",
|
||||
"filter_out_gap_fill": "0",
|
||||
"flush_into_infill": "0",
|
||||
"flush_into_objects": "0",
|
||||
"flush_into_support": "1",
|
||||
"fuzzy_skin": "none",
|
||||
"fuzzy_skin_first_layer": "0",
|
||||
"fuzzy_skin_point_distance": "0.8",
|
||||
"fuzzy_skin_thickness": "0.3",
|
||||
"gap_fill_target": "everywhere",
|
||||
"gcode_add_line_number": "0",
|
||||
"gcode_comments": "0",
|
||||
"hole_to_polyhole": "0",
|
||||
"hole_to_polyhole_threshold": "0.01",
|
||||
"hole_to_polyhole_twisted": "1",
|
||||
"independent_support_layer_height": "1",
|
||||
"infill_anchor": "400%",
|
||||
"infill_anchor_max": "20",
|
||||
"infill_jerk": "6",
|
||||
"initial_layer_jerk": "6",
|
||||
"initial_layer_min_bead_width": "85%",
|
||||
"initial_layer_travel_speed": "100%",
|
||||
"inner_wall_jerk": "6",
|
||||
"internal_bridge_flow": "1",
|
||||
"internal_bridge_speed": "70",
|
||||
"internal_solid_infill_acceleration": "100%",
|
||||
"internal_solid_infill_pattern": "zig-zag",
|
||||
"ironing_angle": "90",
|
||||
"ironing_pattern": "zig-zag",
|
||||
"ironing_support_layer": "0",
|
||||
"is_infill_first": "0",
|
||||
"make_overhang_printable": "0",
|
||||
"make_overhang_printable_angle": "55",
|
||||
"make_overhang_printable_hole_size": "0",
|
||||
"max_bridge_length": "10",
|
||||
"max_volumetric_extrusion_rate_slope": "0",
|
||||
"max_volumetric_extrusion_rate_slope_segment_length": "3",
|
||||
"min_bead_width": "85%",
|
||||
"min_feature_size": "25%",
|
||||
"min_length_factor": "0.5",
|
||||
"min_width_top_surface": "300%",
|
||||
"minimum_support_area": "5",
|
||||
"mmu_segmented_region_interlocking_depth": "0",
|
||||
"mmu_segmented_region_max_width": "0",
|
||||
"only_one_wall_first_layer": "0",
|
||||
"ooze_prevention": "0",
|
||||
"outer_wall_jerk": "6",
|
||||
"overhang_reverse": "0",
|
||||
"overhang_reverse_internal_only": "0",
|
||||
"overhang_reverse_threshold": "50%",
|
||||
"overhang_speed_classic": "0",
|
||||
"precise_outer_wall": "0",
|
||||
"prime_tower_brim_width": "3",
|
||||
"prime_tower_enhance_type": "chamfer",
|
||||
"prime_volume": "45",
|
||||
"print_flow_ratio": "1",
|
||||
"print_order": "default",
|
||||
"raft_contact_distance": "0.1",
|
||||
"raft_expansion": "1.5",
|
||||
"raft_first_layer_density": "90%",
|
||||
"raft_first_layer_expansion": "2",
|
||||
"role_based_wipe_speed": "1",
|
||||
"scarf_angle_threshold": "155",
|
||||
"scarf_joint_flow_ratio": "1",
|
||||
"scarf_joint_speed": "100%",
|
||||
"scarf_overhang_threshold": "40%",
|
||||
"seam_gap": "10%",
|
||||
"seam_slope_min_length": "20",
|
||||
"seam_slope_start_height": "0",
|
||||
"seam_slope_steps": "10",
|
||||
"seam_slope_type": "none",
|
||||
"single_extruder_multi_material_priming": "0",
|
||||
"skirt_speed": "50",
|
||||
"slice_closing_radius": "0.049",
|
||||
"slicing_mode": "regular",
|
||||
"slow_down_layers": "0",
|
||||
"slowdown_for_curled_perimeters": "0",
|
||||
"small_area_infill_flow_compensation": "0",
|
||||
"small_area_infill_flow_compensation_model": "0,0;\n0.2,0.4444;\n0.4,0.6145;\n0.6,0.7059;\n0.8,0.7619;\n1.5,0.8571;\n2,0.8889;\n3,0.9231;\n5,0.9520;\n10,1",
|
||||
"small_perimeter_speed": "30%",
|
||||
"small_perimeter_threshold": "20",
|
||||
"solid_infill_filament": "1",
|
||||
"sparse_infill_acceleration": "100%",
|
||||
"sparse_infill_filament": "1",
|
||||
"speed_limit_to_height_enable": "0",
|
||||
"spiral_mode_max_xy_smoothing": "200%",
|
||||
"spiral_mode_smooth": "0",
|
||||
"staggered_inner_seams": "1",
|
||||
"support_angle": "0",
|
||||
"support_bottom_interface_spacing": "0.5",
|
||||
"support_critical_regions_only": "0",
|
||||
"support_interface_not_for_body": "1",
|
||||
"support_interface_pattern": "auto",
|
||||
"support_remove_small_overhang": "1",
|
||||
"support_xy_overrides_z": "xy_overrides_z",
|
||||
"thick_bridges": "0",
|
||||
"thick_internal_bridges": "0",
|
||||
"timelapse_type": "0",
|
||||
"top_solid_infill_flow_ratio": "1",
|
||||
"top_surface_jerk": "6",
|
||||
"travel_jerk": "6",
|
||||
"travel_speed_z": "0",
|
||||
"tree_support_adaptive_layer_height": "1",
|
||||
"tree_support_angle_slow": "25",
|
||||
"tree_support_auto_brim": "1",
|
||||
"tree_support_branch_angle_organic": "40",
|
||||
"tree_support_branch_diameter_angle": "5",
|
||||
"tree_support_branch_diameter_double_wall": "3",
|
||||
"tree_support_branch_diameter_organic": "2",
|
||||
"tree_support_branch_distance": "5",
|
||||
"tree_support_branch_distance_organic": "1",
|
||||
"tree_support_brim_width": "3",
|
||||
"tree_support_tip_diameter": "0.82",
|
||||
"tree_support_top_rate": "30%",
|
||||
"wall_direction": "auto",
|
||||
"wall_distribution_count": "1",
|
||||
"wall_filament": "1",
|
||||
"wall_generator": "classic",
|
||||
"wall_sequence": "inner wall/outer wall",
|
||||
"wall_transition_angle": "10",
|
||||
"wall_transition_filter_deviation": "25%",
|
||||
"wall_transition_length": "100%",
|
||||
"wipe_before_external_loop": "0",
|
||||
"wipe_on_loops": "0",
|
||||
"wipe_speed": "80%",
|
||||
"wipe_tower_bridging": "10",
|
||||
"wipe_tower_cone_angle": "0",
|
||||
"wipe_tower_extra_spacing": "100%",
|
||||
"wipe_tower_rotation_angle": "0",
|
||||
"wiping_volumes_extruders": "70,70,70,70,70,70,70,70,70,70"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "FLSun",
|
||||
"version": "02.04.00.01",
|
||||
"version": "02.04.00.02",
|
||||
"force_update": "0",
|
||||
"description": "FLSun configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
"default_filament_profile": [
|
||||
"FLSun Generic PLA"
|
||||
],
|
||||
"machine_start_gcode": ";STARTGCODE\nM117 Initializing\n; Set coordinate modes\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; Reset speed and extrusion rates\nM200 D0 ; disable volumetric E\nM220 S100 ; reset speed\n; Set initial warmup temps\nM117 Nozzle preheat\nM104 S100 ; preheat extruder to no ooze temp\nM140 S[bed_temperature_initial_layer_single] ; set bed temp\nM190 S[bed_temperature_initial_layer_single] ; wait for bed final temp\nM300 S40 P10 ; Bip\n; Home\nM117 Homing\nG28 ; home all with default mesh bed level\n; For ABL users put G29 for a leveling request\n; Final warmup routine\nM117 Final warmup\nM104 S[nozzle_temperature_initial_layer] ; set extruder final temp\nM109 S[nozzle_temperature_initial_layer] ; wait for extruder final temp\nM190 S[bed_temperature_initial_layer_single] ; wait for bed final temp\nM300 S440 P200; 1st beep for printer ready and allow some time to clean nozzle\nM300 S0 P250; wait between dual beep\nM300 S440 P200; 2nd beep for printer ready\nG4 S10; wait to clean the nozzle\nM300 S440 P200; 3rd beep for ready to start printing\n; Prime line routine\nM117 Printing prime line\n;M900 K0; Disable Linear Advance (Marlin) for prime line\nG92 E0.0; reset extrusion distance\nG1 X-54.672 Y-95.203 Z0.3 F4000; go outside print area\nG92 E0.0; reset extrusion distance\nG1 E2 F1000 ; de-retract and push ooze\nG3 X38.904 Y-102.668 I54.672 J95.105 E20.999\nG3 X54.671 Y-95.203 I-38.815 J102.373 E5.45800\nG92 E0.0\nG1 E-5 F3000 ; retract 5mm\nG1 X52.931 Y-96.185 F1000 ; wipe\nG1 X50.985 Y-97.231 F1000 ; wipe\nG1 X49.018 Y-98.238 F1000 ; wipe\nG1 X0 Y-109.798 F1000\nG1 E4.8 F1500; de-retract\nG92 E0.0 ; reset extrusion distance\n; Final print adjustments\nM117 Preparing to print\n;M82 ; extruder absolute mode\nM221 S{if layer_height<0.075}100{else}95{endif}\nM300 S40 P10 ; chirp\nM117 Print [output_filename_format]; Display: Printing started...",
|
||||
"machine_start_gcode": ";STARTGCODE\nM117 Initializing\n; Set coordinate modes\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n; Reset speed and extrusion rates\nM200 D0 ; disable volumetric E\nM220 S100 ; reset speed\n; Set initial warmup temps\nM117 Nozzle preheat\nM104 S100 ; preheat extruder to no ooze temp\nM140 S[bed_temperature_initial_layer_single] ; set bed temp\nM190 S[bed_temperature_initial_layer_single] ; wait for bed final temp\nM300 S40 P10 ; Bip\n; Home\nM117 Homing\nG28 ; home all with default mesh bed level\n; For ABL users put G29 for a leveling request\n; Final warmup routine\nM117 Final warmup\nM104 S[nozzle_temperature_initial_layer] ; set extruder final temp\nM109 S[nozzle_temperature_initial_layer] ; wait for extruder final temp\nM190 S[bed_temperature_initial_layer_single] ; wait for bed final temp\nM300 S440 P200; 1st beep for printer ready and allow some time to clean nozzle\nM300 S0 P250; wait between dual beep\nM300 S440 P200; 2nd beep for printer ready\nG4 S10; wait to clean the nozzle\nM300 S440 P200; 3rd beep for ready to start printing\n; Prime line routine\nM117 Printing prime line\n;M900 K0; Disable Linear Advance (Marlin) for prime line\nG92 E0.0; reset extrusion distance\nG1 X-54.672 Y-95.203 Z0.3 F4000; go outside print area\nG92 E0.0; reset extrusion distance\nG1 E2 F1000 ; de-retract and push ooze\nG3 X38.904 Y-102.668 I54.672 J95.105 E20.999\nG3 X54.671 Y-95.203 I-38.815 J102.373 E5.45800\nG92 E0.0\nG1 E-5 F3000 ; retract 5mm\nG1 X52.931 Y-96.185 F1000 ; wipe\nG1 X50.985 Y-97.231 F1000 ; wipe\nG1 X49.018 Y-98.238 F1000 ; wipe\nG1 X0 Y-109.798 F1000\nG1 E4.8 F1500; de-retract\nG92 E0.0 ; reset extrusion distance\n; Final print adjustments\nM117 Preparing to print\n;M82 ; extruder absolute mode\nM221 S{if layer_height<0.075}100{else}95{endif}\nM300 S40 P10 ; chirp\nM117 Print [input_filename_base]; Display: Printing started...",
|
||||
"machine_end_gcode": "; printing object ENDGCODE\nG92 E0.0 ; prepare to retract\nG1 E-6 F3000; retract to avoid stringing\n; Anti-stringing end wiggle\n{if layer_z < max_print_height}G1 Z{min(layer_z+100, max_print_height)}{endif} F4000 ; Move print head up\nG1 X0 Y120 F3000 ; present print\n; Reset print setting overrides\nG92 E0\nM200 D0 ; disable volumetric e\nM220 S100 ; reset speed factor to 100%\nM221 S100 ; reset extruder factor to 100%\n;M900 K0 ; reset linear acceleration(Marlin)\n; Shut down printer\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM18 S180 ;disable motors after 180s\nM300 S40 P10 ; Bip\nM117 Print finish.",
|
||||
"scan_first_layer": "0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Ginger Additive",
|
||||
"version": "02.04.00.02",
|
||||
"version": "02.04.00.03",
|
||||
"force_update": "1",
|
||||
"description": "Ginger configuration",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"enable_pressure_advance": [
|
||||
"1"
|
||||
],
|
||||
"extruder_rotation_volume": "624",
|
||||
"fan_cooling_layer_time": [
|
||||
"100"
|
||||
],
|
||||
@@ -94,13 +93,6 @@
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"75"
|
||||
],
|
||||
"mixing_stepper_rotation_volume": "8000",
|
||||
"multi_zone_1_initial_layer": "240",
|
||||
"multi_zone_1_temperature": "240",
|
||||
"multi_zone_2_initial_layer": "240",
|
||||
"multi_zone_2_temperature": "240",
|
||||
"multi_zone_3_initial_layer": "220",
|
||||
"multi_zone_3_temperature": "220",
|
||||
"nozzle_temperature_range_high": [
|
||||
"260"
|
||||
],
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"enable_pressure_advance": [
|
||||
"1"
|
||||
],
|
||||
"extruder_rotation_volume": "456",
|
||||
"fan_cooling_layer_time": [
|
||||
"100"
|
||||
],
|
||||
@@ -94,13 +93,6 @@
|
||||
"hot_plate_temp_initial_layer": [
|
||||
"50"
|
||||
],
|
||||
"mixing_stepper_rotation_volume": "8000",
|
||||
"multi_zone_1_initial_layer": "200",
|
||||
"multi_zone_1_temperature": "200",
|
||||
"multi_zone_2_initial_layer": "200",
|
||||
"multi_zone_2_temperature": "200",
|
||||
"multi_zone_3_initial_layer": "200",
|
||||
"multi_zone_3_temperature": "200",
|
||||
"nozzle_temperature_range_high": [
|
||||
"220"
|
||||
],
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"machine_start_gcode": "START_PRINT BED_TEMPERATURE=[bed_temperature_initial_layer] KAMP_LEVELING=1 EXTRUDER_ROTATION_VOLUME={extruder_rotation_volume[0]} MIXING_STEPPER_ROTATION_VOLUME={mixing_stepper_rotation_volume[0]} PURGE_LAYER_HEIGHT=2 PURGE_PARKING_SPEED=10000 PURGE_LENGHT=500 PURGE_SPEED=500 PURGE_MATERIAL_QUANTITY=10000 EXTRUDER_TEMPERATURE=[nozzle_temperature] EXTRUDER_TEMPERATURE_INITIAL_LAYER=[nozzle_temperature_initial_layer] PRESSURE_ADVANCE=0.2 PRESSURE_ADVANCE_SMOOTH_TIME=0.5 ZONE_1_TEMPERATURE={multi_zone_1_initial_layer[0]} ZONE_2_TEMPERATURE={multi_zone_2_initial_layer[0]} ZONE_3_TEMPERATURE={multi_zone_3_initial_layer[0]}",
|
||||
"machine_start_gcode": "START_PRINT BED_TEMPERATURE=[bed_temperature_initial_layer] KAMP_LEVELING=1 PURGE_LAYER_HEIGHT=2 PURGE_PARKING_SPEED=10000 PURGE_LENGHT=500 PURGE_SPEED=500 PURGE_MATERIAL_QUANTITY=10000 EXTRUDER_TEMPERATURE=[nozzle_temperature] EXTRUDER_TEMPERATURE_INITIAL_LAYER=[nozzle_temperature_initial_layer] PRESSURE_ADVANCE=0.2 PRESSURE_ADVANCE_SMOOTH_TIME=0.5",
|
||||
"print_host": "G1OS.local",
|
||||
"printer_model": "Ginger G1",
|
||||
"retract_before_wipe": [
|
||||
@@ -98,12 +98,5 @@
|
||||
"z_hop_types": [
|
||||
"Normal Lift"
|
||||
],
|
||||
"pellet_modded_printer": "1",
|
||||
"use_extruder_rotation_volume": "1",
|
||||
"use_active_pellet_feeding": "1",
|
||||
"multi_zone": "1",
|
||||
"multi_zone_number": "3",
|
||||
"active_feeder_motor_name": [
|
||||
"mixing_stepper"
|
||||
]
|
||||
"pellet_modded_printer": "1"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Qidi",
|
||||
"version": "02.04.00.06",
|
||||
"version": "02.04.00.07",
|
||||
"force_update": "0",
|
||||
"description": "Qidi configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
"locked_skin_infill_pattern": "crosszag",
|
||||
"locked_skeleton_infill_pattern": "zigzag",
|
||||
"max_travel_detour_distance": "0",
|
||||
"machine_prepare_compensation_time": "260",
|
||||
"minimum_sparse_infill_area": "15",
|
||||
"only_one_wall_top": "1",
|
||||
"outer_wall_acceleration": [
|
||||
|
||||
@@ -206,6 +206,10 @@
|
||||
"name": "0.30mm Big @RatRig V-Core 4 0.6",
|
||||
"sub_path": "process/0.30mm Big @RatRig V-Core 4 0.6.json"
|
||||
},
|
||||
{
|
||||
"name": "0.30mm Big @RatRig V-Core 4 0.8",
|
||||
"sub_path": "process/0.30mm Big @RatRig V-Core 4 0.8.json"
|
||||
},
|
||||
{
|
||||
"name": "0.30mm Big @RatRig V-Core 4 HYBRID 0.6",
|
||||
"sub_path": "process/0.30mm Big @RatRig V-Core 4 HYBRID 0.6.json"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"type": "machine",
|
||||
"name": "RatRig V-Core 4 300 0.8 nozzle",
|
||||
"inherits": "fdm_klipper_common",
|
||||
"default_print_profile": "0.30mm Big @RatRig V-Core 4 0.8",
|
||||
"from": "system",
|
||||
"setting_id": "feTeGuFkLzWFFSC4",
|
||||
"instantiation": "true",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"type": "machine",
|
||||
"name": "RatRig V-Core 4 400 0.8 nozzle",
|
||||
"inherits": "fdm_klipper_common",
|
||||
"default_print_profile": "0.30mm Big @RatRig V-Core 4 0.8",
|
||||
"from": "system",
|
||||
"setting_id": "DQ7Lzsuk87A4qtav",
|
||||
"instantiation": "true",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"type": "machine",
|
||||
"name": "RatRig V-Core 4 500 0.8 nozzle",
|
||||
"inherits": "fdm_klipper_common",
|
||||
"default_print_profile": "0.30mm Big @RatRig V-Core 4 0.8",
|
||||
"from": "system",
|
||||
"setting_id": "VMKIyofeEpPvUvkY",
|
||||
"instantiation": "true",
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.30mm Big @RatRig V-Core 4 0.8",
|
||||
"inherits": "fdm_process_ratrig_common",
|
||||
"from": "system",
|
||||
"setting_id": "7FOG8fkUbrLknvuz",
|
||||
"instantiation": "true",
|
||||
"layer_height": "0.3",
|
||||
"inital_layer_height": "0.35",
|
||||
"wall_count": "3",
|
||||
"top_shell_layers": "4",
|
||||
"bottom_shell_layers": "3",
|
||||
"top_shell_thickness": "0",
|
||||
"sparse_infill_density": "25%",
|
||||
"infill_anchor": "600%",
|
||||
"infill_anchor_max": "5",
|
||||
"infill_combination": "1",
|
||||
"skirt_loops": "2",
|
||||
"skirt_distance": "10",
|
||||
"support_threshold_angle": "65",
|
||||
"support_bottom_z_distance": "0.2",
|
||||
"support_on_build_plate_only": "1",
|
||||
"support_object_xy_distance": "60%",
|
||||
"inner_wall_speed": "300",
|
||||
"small_perimeter_speed": "250",
|
||||
"outer_wall_speed": "250",
|
||||
"sparse_infill_speed": "400",
|
||||
"internal_solid_infill_speed": "100%",
|
||||
"top_surface_speed": "100%",
|
||||
"support_speed": "50",
|
||||
"support_interface_speed": "100%",
|
||||
"bridge_speed": "50",
|
||||
"gap_infill_speed": "200",
|
||||
"travel_speed": "600",
|
||||
"initial_layer_speed": "80",
|
||||
"enable_overhang_speed": "1",
|
||||
"overhang_1_4_speed": "20",
|
||||
"overhang_2_4_speed": "45",
|
||||
"overhang_3_4_speed": "80",
|
||||
"overhang_4_4_speed": "100",
|
||||
"outer_wall_acceleration": "8000",
|
||||
"inner_wall_acceleration": "10000",
|
||||
"top_surface_acceleration": "0",
|
||||
"internal_solid_infill_acceleration": "0",
|
||||
"sparse_infill_acceleration": "15000",
|
||||
"bridge_acceleration": "5000",
|
||||
"initial_layer_acceleration": "2500",
|
||||
"travel_acceleration": "15000",
|
||||
"default_acceleration": "15000",
|
||||
"line_width": "0.75",
|
||||
"initial_layer_line_width": "1.1",
|
||||
"inner_wall_line_width": "0.75",
|
||||
"outer_wall_line_width": "0.70",
|
||||
"sparse_infill_line_width": "0.75",
|
||||
"internal_solid_infill_line_width": "0.75",
|
||||
"top_surface_line_width": "0.75",
|
||||
"support_line_width": "0.75",
|
||||
"infill_wall_overlap": "18%",
|
||||
"bridge_flow": "0.85",
|
||||
"resolution": "0.0125",
|
||||
"elefant_foot_compensation": "0.1",
|
||||
"compatible_printers": [
|
||||
"RatRig V-Core 4 300 0.8 nozzle",
|
||||
"RatRig V-Core 4 400 0.8 nozzle",
|
||||
"RatRig V-Core 4 500 0.8 nozzle"
|
||||
]
|
||||
}
|
||||
@@ -75,6 +75,30 @@
|
||||
{
|
||||
"name": "0.20mm Standard @iQ TiQ8 P1 - ABS Natur Material4Print (0.4 Nozzle)",
|
||||
"sub_path": "process/0.20mm Standard @iQ TiQ8 P1 - ABS Natur Material4Print (0.4 Nozzle).json"
|
||||
},
|
||||
{
|
||||
"name": "0.15mm Standard @iQ TiQ2 (0.25 Nozzle)",
|
||||
"sub_path": "process/0.15mm Standard @iQ TiQ2 (0.25 Nozzle).json"
|
||||
},
|
||||
{
|
||||
"name": "0.30mm Standard @iQ TiQ2 (0.6 Nozzle)",
|
||||
"sub_path": "process/0.30mm Standard @iQ TiQ2 (0.6 Nozzle).json"
|
||||
},
|
||||
{
|
||||
"name": "0.40mm Standard @iQ TiQ2 (0.8 Nozzle)",
|
||||
"sub_path": "process/0.40mm Standard @iQ TiQ2 (0.8 Nozzle).json"
|
||||
},
|
||||
{
|
||||
"name": "0.15mm Standard @iQ TiQ8 (0.25 Nozzle)",
|
||||
"sub_path": "process/0.15mm Standard @iQ TiQ8 (0.25 Nozzle).json"
|
||||
},
|
||||
{
|
||||
"name": "0.30mm Standard @iQ TiQ8 (0.6 Nozzle)",
|
||||
"sub_path": "process/0.30mm Standard @iQ TiQ8 (0.6 Nozzle).json"
|
||||
},
|
||||
{
|
||||
"name": "0.40mm Standard @iQ TiQ8 (0.8 Nozzle)",
|
||||
"sub_path": "process/0.40mm Standard @iQ TiQ8 (0.8 Nozzle).json"
|
||||
}
|
||||
],
|
||||
"filament_list": [
|
||||
|
||||
@@ -1,134 +1,135 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "iQ TiQ2 0.25 Nozzle",
|
||||
"inherits": "fdm_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "cIJ59rG6rulmYsqA",
|
||||
"instantiation": "true",
|
||||
"printer_settings_id": "iQ TiQ2 0.25 Nozzle",
|
||||
"printer_model": "TiQ2",
|
||||
"printer_variant": "0.25",
|
||||
"printer_notes": "Machine file version 1.0 20251106",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\nG1 X32 Y3 F3000\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing\n",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"disable_m73": "1",
|
||||
"emit_machine_limits_to_gcode": "0",
|
||||
"enable_filament_ramming": "0",
|
||||
"extruder_colour": [
|
||||
"#FCE94F",
|
||||
"#FCE94F"
|
||||
],
|
||||
"extruder_offset": [
|
||||
"0x0",
|
||||
"0x0"
|
||||
],
|
||||
"gcode_flavor": "marlin",
|
||||
"host_type": "simplyprint",
|
||||
"long_retractions_when_cut": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"machine_end_gcode": "G1 X-19 F3000 ; home X axis\nG1 Y1 F3000 ; home Y axis\nM104 S0 T0 ; turn off extruder\nM104 S0 T1 ; turn off extruder\nM104 S0 T2 ; turn off extruder\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM806 S0 ; turn of housing fan\nM84 ; disable motor\n",
|
||||
"machine_max_speed_z": [
|
||||
"15",
|
||||
"12"
|
||||
],
|
||||
"machine_pause_gcode": "M10710 S0",
|
||||
"machine_start_gcode": "T[initial_extruder]\nM109 S{nozzle_temperature_initial_layer[current_extruder]}\nG1 Z15 F900\nG1 X-19 Y1 F9000\nG1 X-19 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 X0",
|
||||
"max_layer_height": [
|
||||
"0.2",
|
||||
"0.2"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.08",
|
||||
"0.08"
|
||||
],
|
||||
"nozzle_diameter": [
|
||||
"0.25",
|
||||
"0.25"
|
||||
],
|
||||
"print_host": "https://simplyprint.io/panel",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"330x0",
|
||||
"330x330",
|
||||
"0x330"
|
||||
],
|
||||
"printable_height": "300",
|
||||
"retract_before_wipe": [
|
||||
"70%",
|
||||
"70%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10",
|
||||
"12"
|
||||
],
|
||||
"retract_lift_above": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_below": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_enforce": [
|
||||
"All Surfaces",
|
||||
"All Surfaces"
|
||||
],
|
||||
"retract_on_top_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retract_restart_extra": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_restart_extra_toolchange": [
|
||||
"-0.2",
|
||||
"-0.2"
|
||||
],
|
||||
"retract_when_changing_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_distances_when_cut": [
|
||||
"18",
|
||||
"18"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.8",
|
||||
"0.9"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"thumbnails": "",
|
||||
"travel_slope": [
|
||||
"3",
|
||||
"3"
|
||||
],
|
||||
"wipe": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"wipe_distance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"z_hop": [
|
||||
"0.25",
|
||||
"0.25"
|
||||
],
|
||||
"z_hop_types": [
|
||||
"Normal Lift",
|
||||
"Normal Lift"
|
||||
]
|
||||
}
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "iQ TiQ2 0.25 Nozzle",
|
||||
"inherits": "fdm_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "cIJ59rG6rulmYsqA",
|
||||
"instantiation": "true",
|
||||
"printer_settings_id": "iQ TiQ2 0.25 Nozzle",
|
||||
"printer_model": "TiQ2",
|
||||
"printer_variant": "0.25",
|
||||
"default_print_profile": "0.15mm Standard @iQ TiQ2 (0.25 Nozzle)",
|
||||
"printer_notes": "Machine file version 1.0 20251106",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\nG1 X32 Y3 F3000\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing\n",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"disable_m73": "1",
|
||||
"emit_machine_limits_to_gcode": "0",
|
||||
"enable_filament_ramming": "0",
|
||||
"extruder_colour": [
|
||||
"#FCE94F",
|
||||
"#FCE94F"
|
||||
],
|
||||
"extruder_offset": [
|
||||
"0x0",
|
||||
"0x0"
|
||||
],
|
||||
"gcode_flavor": "marlin",
|
||||
"host_type": "simplyprint",
|
||||
"long_retractions_when_cut": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"machine_end_gcode": "G1 X-19 F3000 ; home X axis\nG1 Y1 F3000 ; home Y axis\nM104 S0 T0 ; turn off extruder\nM104 S0 T1 ; turn off extruder\nM104 S0 T2 ; turn off extruder\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM806 S0 ; turn of housing fan\nM84 ; disable motor\n",
|
||||
"machine_max_speed_z": [
|
||||
"15",
|
||||
"12"
|
||||
],
|
||||
"machine_pause_gcode": "M10710 S0",
|
||||
"machine_start_gcode": "T[initial_extruder]\nM109 S{nozzle_temperature_initial_layer[current_extruder]}\nG1 Z15 F900\nG1 X-19 Y1 F9000\nG1 X-19 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 X0",
|
||||
"max_layer_height": [
|
||||
"0.2",
|
||||
"0.2"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.08",
|
||||
"0.08"
|
||||
],
|
||||
"nozzle_diameter": [
|
||||
"0.25",
|
||||
"0.25"
|
||||
],
|
||||
"print_host": "https://simplyprint.io/panel",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"330x0",
|
||||
"330x330",
|
||||
"0x330"
|
||||
],
|
||||
"printable_height": "300",
|
||||
"retract_before_wipe": [
|
||||
"70%",
|
||||
"70%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10",
|
||||
"12"
|
||||
],
|
||||
"retract_lift_above": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_below": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_enforce": [
|
||||
"All Surfaces",
|
||||
"All Surfaces"
|
||||
],
|
||||
"retract_on_top_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retract_restart_extra": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_restart_extra_toolchange": [
|
||||
"-0.2",
|
||||
"-0.2"
|
||||
],
|
||||
"retract_when_changing_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_distances_when_cut": [
|
||||
"18",
|
||||
"18"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.8",
|
||||
"0.9"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"thumbnails": "",
|
||||
"travel_slope": [
|
||||
"3",
|
||||
"3"
|
||||
],
|
||||
"wipe": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"wipe_distance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"z_hop": [
|
||||
"0.25",
|
||||
"0.25"
|
||||
],
|
||||
"z_hop_types": [
|
||||
"Normal Lift",
|
||||
"Normal Lift"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,134 +1,135 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "iQ TiQ2 0.6 Nozzle",
|
||||
"inherits": "fdm_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "U5GboRipEfd1fsBm",
|
||||
"instantiation": "true",
|
||||
"printer_settings_id": "iQ TiQ2 0.6 Nozzle",
|
||||
"printer_model": "TiQ2",
|
||||
"printer_variant": "0.6",
|
||||
"printer_notes": "Machine file version 1.0 20251106",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\nG1 X32 Y3 F3000\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing\n",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"disable_m73": "1",
|
||||
"emit_machine_limits_to_gcode": "0",
|
||||
"enable_filament_ramming": "0",
|
||||
"extruder_colour": [
|
||||
"#FCE94F",
|
||||
"#FCE94F"
|
||||
],
|
||||
"extruder_offset": [
|
||||
"0x0",
|
||||
"0x0"
|
||||
],
|
||||
"gcode_flavor": "marlin",
|
||||
"host_type": "simplyprint",
|
||||
"long_retractions_when_cut": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"machine_end_gcode": "G1 X-19 F3000 ; home X axis\nG1 Y1 F3000 ; home Y axis\nM104 S0 T0 ; turn off extruder\nM104 S0 T1 ; turn off extruder\nM104 S0 T2 ; turn off extruder\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM806 S0 ; turn of housing fan\nM84 ; disable motor\n",
|
||||
"machine_max_speed_z": [
|
||||
"15",
|
||||
"12"
|
||||
],
|
||||
"machine_pause_gcode": "M10710 S0",
|
||||
"machine_start_gcode": "T[initial_extruder]\nM109 S{nozzle_temperature_initial_layer[current_extruder]}\nG1 Z15 F900\nG1 X-19 Y1 F9000\nG1 X-19 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 X0",
|
||||
"max_layer_height": [
|
||||
"0.6",
|
||||
"0.6"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.08",
|
||||
"0.08"
|
||||
],
|
||||
"nozzle_diameter": [
|
||||
"0.6",
|
||||
"0.6"
|
||||
],
|
||||
"print_host": "https://simplyprint.io/panel",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"330x0",
|
||||
"330x330",
|
||||
"0x330"
|
||||
],
|
||||
"printable_height": "300",
|
||||
"retract_before_wipe": [
|
||||
"70%",
|
||||
"70%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10",
|
||||
"12"
|
||||
],
|
||||
"retract_lift_above": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_below": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_enforce": [
|
||||
"All Surfaces",
|
||||
"All Surfaces"
|
||||
],
|
||||
"retract_on_top_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retract_restart_extra": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_restart_extra_toolchange": [
|
||||
"-0.2",
|
||||
"-0.2"
|
||||
],
|
||||
"retract_when_changing_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_distances_when_cut": [
|
||||
"18",
|
||||
"18"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.8",
|
||||
"0.9"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"thumbnails": "",
|
||||
"travel_slope": [
|
||||
"3",
|
||||
"3"
|
||||
],
|
||||
"wipe": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"wipe_distance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"z_hop": [
|
||||
"0.6",
|
||||
"0.6"
|
||||
],
|
||||
"z_hop_types": [
|
||||
"Normal Lift",
|
||||
"Normal Lift"
|
||||
]
|
||||
}
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "iQ TiQ2 0.6 Nozzle",
|
||||
"inherits": "fdm_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "U5GboRipEfd1fsBm",
|
||||
"instantiation": "true",
|
||||
"printer_settings_id": "iQ TiQ2 0.6 Nozzle",
|
||||
"printer_model": "TiQ2",
|
||||
"printer_variant": "0.6",
|
||||
"default_print_profile": "0.30mm Standard @iQ TiQ2 (0.6 Nozzle)",
|
||||
"printer_notes": "Machine file version 1.0 20251106",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\nG1 X32 Y3 F3000\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing\n",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"disable_m73": "1",
|
||||
"emit_machine_limits_to_gcode": "0",
|
||||
"enable_filament_ramming": "0",
|
||||
"extruder_colour": [
|
||||
"#FCE94F",
|
||||
"#FCE94F"
|
||||
],
|
||||
"extruder_offset": [
|
||||
"0x0",
|
||||
"0x0"
|
||||
],
|
||||
"gcode_flavor": "marlin",
|
||||
"host_type": "simplyprint",
|
||||
"long_retractions_when_cut": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"machine_end_gcode": "G1 X-19 F3000 ; home X axis\nG1 Y1 F3000 ; home Y axis\nM104 S0 T0 ; turn off extruder\nM104 S0 T1 ; turn off extruder\nM104 S0 T2 ; turn off extruder\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM806 S0 ; turn of housing fan\nM84 ; disable motor\n",
|
||||
"machine_max_speed_z": [
|
||||
"15",
|
||||
"12"
|
||||
],
|
||||
"machine_pause_gcode": "M10710 S0",
|
||||
"machine_start_gcode": "T[initial_extruder]\nM109 S{nozzle_temperature_initial_layer[current_extruder]}\nG1 Z15 F900\nG1 X-19 Y1 F9000\nG1 X-19 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 X0",
|
||||
"max_layer_height": [
|
||||
"0.6",
|
||||
"0.6"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.08",
|
||||
"0.08"
|
||||
],
|
||||
"nozzle_diameter": [
|
||||
"0.6",
|
||||
"0.6"
|
||||
],
|
||||
"print_host": "https://simplyprint.io/panel",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"330x0",
|
||||
"330x330",
|
||||
"0x330"
|
||||
],
|
||||
"printable_height": "300",
|
||||
"retract_before_wipe": [
|
||||
"70%",
|
||||
"70%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10",
|
||||
"12"
|
||||
],
|
||||
"retract_lift_above": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_below": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_enforce": [
|
||||
"All Surfaces",
|
||||
"All Surfaces"
|
||||
],
|
||||
"retract_on_top_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retract_restart_extra": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_restart_extra_toolchange": [
|
||||
"-0.2",
|
||||
"-0.2"
|
||||
],
|
||||
"retract_when_changing_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_distances_when_cut": [
|
||||
"18",
|
||||
"18"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.8",
|
||||
"0.9"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"thumbnails": "",
|
||||
"travel_slope": [
|
||||
"3",
|
||||
"3"
|
||||
],
|
||||
"wipe": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"wipe_distance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"z_hop": [
|
||||
"0.6",
|
||||
"0.6"
|
||||
],
|
||||
"z_hop_types": [
|
||||
"Normal Lift",
|
||||
"Normal Lift"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,134 +1,135 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "iQ TiQ2 0.8 Nozzle",
|
||||
"inherits": "fdm_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "Hnv1OfrxjIFdQTpK",
|
||||
"instantiation": "true",
|
||||
"printer_settings_id": "iQ TiQ2 0.8 Nozzle",
|
||||
"printer_model": "TiQ2",
|
||||
"printer_variant": "0.8",
|
||||
"printer_notes": "Machine file version 1.0 20251106",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\nG1 X32 Y3 F3000\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing\n",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"disable_m73": "1",
|
||||
"emit_machine_limits_to_gcode": "0",
|
||||
"enable_filament_ramming": "0",
|
||||
"extruder_colour": [
|
||||
"#FCE94F",
|
||||
"#FCE94F"
|
||||
],
|
||||
"extruder_offset": [
|
||||
"0x0",
|
||||
"0x0"
|
||||
],
|
||||
"gcode_flavor": "marlin",
|
||||
"host_type": "simplyprint",
|
||||
"long_retractions_when_cut": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"machine_end_gcode": "G1 X-19 F3000 ; home X axis\nG1 Y1 F3000 ; home Y axis\nM104 S0 T0 ; turn off extruder\nM104 S0 T1 ; turn off extruder\nM104 S0 T2 ; turn off extruder\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM806 S0 ; turn of housing fan\nM84 ; disable motor\n",
|
||||
"machine_max_speed_z": [
|
||||
"15",
|
||||
"12"
|
||||
],
|
||||
"machine_pause_gcode": "M10710 S0",
|
||||
"machine_start_gcode": "T[initial_extruder]\nM109 S{nozzle_temperature_initial_layer[current_extruder]}\nG1 Z15 F900\nG1 X-19 Y1 F9000\nG1 X-19 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 X0",
|
||||
"max_layer_height": [
|
||||
"0.8",
|
||||
"0.8"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.08",
|
||||
"0.08"
|
||||
],
|
||||
"nozzle_diameter": [
|
||||
"0.8",
|
||||
"0.8"
|
||||
],
|
||||
"print_host": "https://simplyprint.io/panel",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"330x0",
|
||||
"330x330",
|
||||
"0x330"
|
||||
],
|
||||
"printable_height": "300",
|
||||
"retract_before_wipe": [
|
||||
"70%",
|
||||
"70%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10",
|
||||
"12"
|
||||
],
|
||||
"retract_lift_above": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_below": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_enforce": [
|
||||
"All Surfaces",
|
||||
"All Surfaces"
|
||||
],
|
||||
"retract_on_top_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retract_restart_extra": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_restart_extra_toolchange": [
|
||||
"-0.2",
|
||||
"-0.2"
|
||||
],
|
||||
"retract_when_changing_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_distances_when_cut": [
|
||||
"18",
|
||||
"18"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.8",
|
||||
"0.9"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"thumbnails": "",
|
||||
"travel_slope": [
|
||||
"3",
|
||||
"3"
|
||||
],
|
||||
"wipe": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"wipe_distance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"z_hop": [
|
||||
"0.8",
|
||||
"0.8"
|
||||
],
|
||||
"z_hop_types": [
|
||||
"Normal Lift",
|
||||
"Normal Lift"
|
||||
]
|
||||
}
|
||||
{
|
||||
"type": "machine",
|
||||
"name": "iQ TiQ2 0.8 Nozzle",
|
||||
"inherits": "fdm_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "Hnv1OfrxjIFdQTpK",
|
||||
"instantiation": "true",
|
||||
"printer_settings_id": "iQ TiQ2 0.8 Nozzle",
|
||||
"printer_model": "TiQ2",
|
||||
"printer_variant": "0.8",
|
||||
"default_print_profile": "0.40mm Standard @iQ TiQ2 (0.8 Nozzle)",
|
||||
"printer_notes": "Machine file version 1.0 20251106",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\nG1 X32 Y3 F3000\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing\n",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"disable_m73": "1",
|
||||
"emit_machine_limits_to_gcode": "0",
|
||||
"enable_filament_ramming": "0",
|
||||
"extruder_colour": [
|
||||
"#FCE94F",
|
||||
"#FCE94F"
|
||||
],
|
||||
"extruder_offset": [
|
||||
"0x0",
|
||||
"0x0"
|
||||
],
|
||||
"gcode_flavor": "marlin",
|
||||
"host_type": "simplyprint",
|
||||
"long_retractions_when_cut": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"machine_end_gcode": "G1 X-19 F3000 ; home X axis\nG1 Y1 F3000 ; home Y axis\nM104 S0 T0 ; turn off extruder\nM104 S0 T1 ; turn off extruder\nM104 S0 T2 ; turn off extruder\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM806 S0 ; turn of housing fan\nM84 ; disable motor\n",
|
||||
"machine_max_speed_z": [
|
||||
"15",
|
||||
"12"
|
||||
],
|
||||
"machine_pause_gcode": "M10710 S0",
|
||||
"machine_start_gcode": "T[initial_extruder]\nM109 S{nozzle_temperature_initial_layer[current_extruder]}\nG1 Z15 F900\nG1 X-19 Y1 F9000\nG1 X-19 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\nG1 X0",
|
||||
"max_layer_height": [
|
||||
"0.8",
|
||||
"0.8"
|
||||
],
|
||||
"min_layer_height": [
|
||||
"0.08",
|
||||
"0.08"
|
||||
],
|
||||
"nozzle_diameter": [
|
||||
"0.8",
|
||||
"0.8"
|
||||
],
|
||||
"print_host": "https://simplyprint.io/panel",
|
||||
"printable_area": [
|
||||
"0x0",
|
||||
"330x0",
|
||||
"330x330",
|
||||
"0x330"
|
||||
],
|
||||
"printable_height": "300",
|
||||
"retract_before_wipe": [
|
||||
"70%",
|
||||
"70%"
|
||||
],
|
||||
"retract_length_toolchange": [
|
||||
"10",
|
||||
"12"
|
||||
],
|
||||
"retract_lift_above": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_below": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_lift_enforce": [
|
||||
"All Surfaces",
|
||||
"All Surfaces"
|
||||
],
|
||||
"retract_on_top_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retract_restart_extra": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"retract_restart_extra_toolchange": [
|
||||
"-0.2",
|
||||
"-0.2"
|
||||
],
|
||||
"retract_when_changing_layer": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_distances_when_cut": [
|
||||
"18",
|
||||
"18"
|
||||
],
|
||||
"retraction_length": [
|
||||
"0.8",
|
||||
"0.9"
|
||||
],
|
||||
"retraction_minimum_travel": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"retraction_speed": [
|
||||
"30",
|
||||
"30"
|
||||
],
|
||||
"thumbnails": "",
|
||||
"travel_slope": [
|
||||
"3",
|
||||
"3"
|
||||
],
|
||||
"wipe": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"wipe_distance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"z_hop": [
|
||||
"0.8",
|
||||
"0.8"
|
||||
],
|
||||
"z_hop_types": [
|
||||
"Normal Lift",
|
||||
"Normal Lift"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"printer_settings_id": "iQ TiQ8 0.25 Nozzle",
|
||||
"printer_model": "TiQ8",
|
||||
"printer_variant": "0.25",
|
||||
"default_print_profile": "0.15mm Standard @iQ TiQ8 (0.25 Nozzle)",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\n{if next_extruder==0}G1 X30 Y-12 F9000{endif}\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"printer_settings_id": "iQ TiQ8 0.4 Nozzle",
|
||||
"printer_model": "TiQ8",
|
||||
"printer_variant": "0.4",
|
||||
"default_print_profile": "0.20mm Standard @iQ TiQ8 P1 - ABS Natur Material4Print (0.4 Nozzle)",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\n{if next_extruder==0}G1 X30 Y-12 F9000{endif}\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"printer_settings_id": "iQ TiQ8 0.6 Nozzle",
|
||||
"printer_model": "TiQ8",
|
||||
"printer_variant": "0.6",
|
||||
"default_print_profile": "0.30mm Standard @iQ TiQ8 (0.6 Nozzle)",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\n{if next_extruder==0}G1 X30 Y-12 F9000{endif}\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"printer_settings_id": "iQ TiQ8 0.8 Nozzle",
|
||||
"printer_model": "TiQ8",
|
||||
"printer_variant": "0.8",
|
||||
"default_print_profile": "0.40mm Standard @iQ TiQ8 (0.8 Nozzle)",
|
||||
"change_filament_gcode": "G1 Z{layer_z+2} F900 ; safe distance while tool change\n{if next_extruder==0}G1 X30 Y-12 F9000{endif}\nM109 S{nozzle_temperature[next_extruder]} T[next_extruder] ; set new tool temperature so it can start heating while changing",
|
||||
"deretraction_speed": [
|
||||
"30",
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.15mm Standard @iQ TiQ2 (0.25 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ2 0.25 Nozzle"
|
||||
],
|
||||
"layer_height": "0.15",
|
||||
"line_width": "0.25",
|
||||
"outer_wall_line_width": "0.25",
|
||||
"inner_wall_line_width": "0.25",
|
||||
"sparse_infill_line_width": "0.25",
|
||||
"internal_solid_infill_line_width": "0.25",
|
||||
"top_surface_line_width": "0.25",
|
||||
"inner_wall_speed": "150",
|
||||
"internal_solid_infill_speed": "150",
|
||||
"sparse_infill_speed": "100",
|
||||
"gap_infill_speed": "50",
|
||||
"initial_layer_speed": "35",
|
||||
"initial_layer_infill_speed": "55",
|
||||
"bridge_speed": "30",
|
||||
"print_settings_id": "0.15mm Standard @iQ TiQ2 (0.25 Nozzle)"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.15mm Standard @iQ TiQ8 (0.25 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ8 0.25 Nozzle"
|
||||
],
|
||||
"layer_height": "0.15",
|
||||
"line_width": "0.25",
|
||||
"outer_wall_line_width": "0.25",
|
||||
"inner_wall_line_width": "0.25",
|
||||
"sparse_infill_line_width": "0.25",
|
||||
"internal_solid_infill_line_width": "0.25",
|
||||
"top_surface_line_width": "0.25",
|
||||
"inner_wall_speed": "150",
|
||||
"internal_solid_infill_speed": "150",
|
||||
"sparse_infill_speed": "100",
|
||||
"gap_infill_speed": "50",
|
||||
"initial_layer_speed": "35",
|
||||
"initial_layer_infill_speed": "55",
|
||||
"bridge_speed": "30",
|
||||
"print_settings_id": "0.15mm Standard @iQ TiQ8 (0.25 Nozzle)"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.30mm Standard @iQ TiQ2 (0.6 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ2 0.6 Nozzle"
|
||||
],
|
||||
"layer_height": "0.3",
|
||||
"initial_layer_print_height": "0.3",
|
||||
"line_width": "0.6",
|
||||
"outer_wall_line_width": "0.6",
|
||||
"inner_wall_line_width": "0.6",
|
||||
"sparse_infill_line_width": "0.6",
|
||||
"internal_solid_infill_line_width": "0.6",
|
||||
"top_surface_line_width": "0.6",
|
||||
"wall_loops": "2",
|
||||
"inner_wall_speed": "150",
|
||||
"internal_solid_infill_speed": "150",
|
||||
"sparse_infill_speed": "100",
|
||||
"gap_infill_speed": "50",
|
||||
"initial_layer_speed": "35",
|
||||
"initial_layer_infill_speed": "55",
|
||||
"bridge_speed": "30",
|
||||
"print_settings_id": "0.30mm Standard @iQ TiQ2 (0.6 Nozzle)"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.30mm Standard @iQ TiQ8 (0.6 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ8 0.6 Nozzle"
|
||||
],
|
||||
"layer_height": "0.3",
|
||||
"initial_layer_print_height": "0.3",
|
||||
"line_width": "0.6",
|
||||
"outer_wall_line_width": "0.6",
|
||||
"inner_wall_line_width": "0.6",
|
||||
"sparse_infill_line_width": "0.6",
|
||||
"internal_solid_infill_line_width": "0.6",
|
||||
"top_surface_line_width": "0.6",
|
||||
"wall_loops": "2",
|
||||
"inner_wall_speed": "150",
|
||||
"internal_solid_infill_speed": "150",
|
||||
"sparse_infill_speed": "100",
|
||||
"gap_infill_speed": "50",
|
||||
"initial_layer_speed": "35",
|
||||
"initial_layer_infill_speed": "55",
|
||||
"bridge_speed": "30",
|
||||
"print_settings_id": "0.30mm Standard @iQ TiQ8 (0.6 Nozzle)"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.40mm Standard @iQ TiQ2 (0.8 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ2 0.8 Nozzle"
|
||||
],
|
||||
"layer_height": "0.4",
|
||||
"initial_layer_print_height": "0.4",
|
||||
"line_width": "0.8",
|
||||
"outer_wall_line_width": "0.8",
|
||||
"inner_wall_line_width": "0.8",
|
||||
"sparse_infill_line_width": "0.8",
|
||||
"internal_solid_infill_line_width": "0.8",
|
||||
"top_surface_line_width": "0.8",
|
||||
"wall_loops": "2",
|
||||
"inner_wall_speed": "150",
|
||||
"internal_solid_infill_speed": "150",
|
||||
"sparse_infill_speed": "100",
|
||||
"gap_infill_speed": "50",
|
||||
"initial_layer_speed": "35",
|
||||
"initial_layer_infill_speed": "55",
|
||||
"bridge_speed": "30",
|
||||
"print_settings_id": "0.40mm Standard @iQ TiQ2 (0.8 Nozzle)"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"type": "process",
|
||||
"name": "0.40mm Standard @iQ TiQ8 (0.8 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ8 0.8 Nozzle"
|
||||
],
|
||||
"layer_height": "0.4",
|
||||
"initial_layer_print_height": "0.4",
|
||||
"line_width": "0.8",
|
||||
"outer_wall_line_width": "0.8",
|
||||
"inner_wall_line_width": "0.8",
|
||||
"sparse_infill_line_width": "0.8",
|
||||
"internal_solid_infill_line_width": "0.8",
|
||||
"top_surface_line_width": "0.8",
|
||||
"wall_loops": "2",
|
||||
"inner_wall_speed": "150",
|
||||
"internal_solid_infill_speed": "150",
|
||||
"sparse_infill_speed": "100",
|
||||
"gap_infill_speed": "50",
|
||||
"initial_layer_speed": "35",
|
||||
"initial_layer_infill_speed": "55",
|
||||
"bridge_speed": "30",
|
||||
"print_settings_id": "0.40mm Standard @iQ TiQ8 (0.8 Nozzle)"
|
||||
}
|
||||
@@ -1,12 +1,32 @@
|
||||
// This single-TU executable links libslic3r, whose SVG/emboss objects (pulled in by the slice mode
|
||||
// below) reference the header-only nanosvg implementation. Provide it here BEFORE any libslic3r header:
|
||||
// several of them transitively include nanosvg.h without the implementation macro, and its include
|
||||
// guard would then suppress the implementation if the macro were defined afterwards. Same pattern as
|
||||
// the test mains.
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#include "nanosvg/nanosvg.h"
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include "nanosvg/nanosvgrast.h"
|
||||
|
||||
#include "libslic3r/GCode.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/core.hpp>
|
||||
#include <boost/log/expressions.hpp>
|
||||
#include <boost/log/sinks/sync_frontend.hpp>
|
||||
#include <boost/log/sinks/text_ostream_backend.hpp>
|
||||
#include <boost/core/null_deleter.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@@ -83,6 +103,254 @@ void generate_custom_presets(PresetBundle* preset_bundle, AppConfig& app_config)
|
||||
|
||||
std::cout << "Custom presets generated successfully" << std::endl;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Vec2d printable_area_center(const DynamicPrintConfig &cfg)
|
||||
{
|
||||
const auto *opt = cfg.option<ConfigOptionPoints>("printable_area");
|
||||
if (opt == nullptr || opt->values.empty())
|
||||
return Vec2d(100., 100.);
|
||||
Vec2d lo = opt->values.front(), hi = opt->values.front();
|
||||
for (const Vec2d &p : opt->values) { lo = lo.cwiseMin(p); hi = hi.cwiseMax(p); }
|
||||
return 0.5 * (lo + hi);
|
||||
}
|
||||
|
||||
// Slice one centered cube that switches from filament 1 to filament 2 partway up, so exactly one
|
||||
// filament change fires, then export. The change drives the printer's own change_filament_gcode: on a
|
||||
// single-nozzle machine it rides the AMS prime tower (append_tcr), on a multi-nozzle machine it routes
|
||||
// through the nozzle swap (set_extruder / append_tcr2) - the engine picks the path from the printer's
|
||||
// topology, so one model covers both. An undefined placeholder in any shipped custom g-code throws
|
||||
// Slic3r::PlaceholderParserError from export.
|
||||
std::string slice_two_color_cube_and_export(const DynamicPrintConfig &cfg, bool is_bbl)
|
||||
{
|
||||
const Vec2d center = printable_area_center(cfg);
|
||||
TriangleMesh m = make_cube(10, 10, 10);
|
||||
m.translate(float(center.x() - 5.), float(center.y() - 5.), 0.f);
|
||||
|
||||
Model model;
|
||||
Print print;
|
||||
ModelObject *obj = model.add_object();
|
||||
obj->name = "cube"; // populates [input_filename_base] the way a loaded model does
|
||||
obj->add_volume(m);
|
||||
obj->add_instance();
|
||||
// Filament 2 is used only above z=4, so the upper layers carry a single filament change.
|
||||
DynamicPrintConfig range_config;
|
||||
range_config.set_key_value("extruder", new ConfigOptionInt(2));
|
||||
// Every range must carry a layer_height; use the process's own so a fine nozzle (e.g. 0.15 mm
|
||||
// printing ~0.1 mm layers) isn't forced to a height its extrusion width can't support - that
|
||||
// trips Flow::with_spacing.
|
||||
range_config.set_key_value("layer_height", new ConfigOptionFloat(cfg.opt_float("layer_height")));
|
||||
obj->layer_config_ranges[{4.0, 10.0}].assign_config(std::move(range_config));
|
||||
|
||||
print.is_BBL_printer() = is_bbl;
|
||||
obj->ensure_on_bed();
|
||||
print.auto_assign_extruders(obj);
|
||||
print.apply(model, cfg);
|
||||
print.validate();
|
||||
|
||||
// Process + export to a temp file, then read it back (the app's own export path is where the
|
||||
// custom *_gcode placeholders expand).
|
||||
print.set_status_silent();
|
||||
print.process();
|
||||
const fs::path tmp = fs::temp_directory_path() / fs::unique_path("orca-validate-%%%%-%%%%.gcode");
|
||||
print.export_gcode(tmp.string(), nullptr, nullptr);
|
||||
std::ifstream in(tmp.string());
|
||||
std::string out((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
|
||||
in.close();
|
||||
boost::system::error_code ec;
|
||||
fs::remove(tmp, ec);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Select the printer's OWN default process + filament (as the app does on a printer change) so we
|
||||
// slice with settings the printer actually ships, not the generic "Default Setting" that stays
|
||||
// selected because it is compatible with every printer.
|
||||
void select_printer_default_presets(PresetBundle &bundle)
|
||||
{
|
||||
const Preset &printer_preset = bundle.printers.get_selected_preset();
|
||||
const std::string def_print = printer_preset.config.opt_string("default_print_profile");
|
||||
if (!def_print.empty())
|
||||
bundle.prints.select_preset_by_name(def_print, /*force=*/true);
|
||||
if (const auto *def_fil = printer_preset.config.option<ConfigOptionStrings>("default_filament_profile");
|
||||
def_fil != nullptr && !def_fil->values.empty())
|
||||
bundle.filaments.select_preset_by_name(def_fil->values.front(), /*force=*/true);
|
||||
}
|
||||
|
||||
// The vendor/printer currently being sliced, stamped onto every engine log record by the sink below so
|
||||
// the interleaved [error] lines can be attributed to a profile. Updated once per loop iteration; safe as
|
||||
// a plain global because the sweep is single-threaded and synchronous (see slice_all_printers).
|
||||
static std::string g_slice_context;
|
||||
|
||||
// Route Boost.Log through a sink that prefixes every record with g_slice_context. Without this the
|
||||
// engine's [error] lines (emitted deep inside process()/export_gcode()) carry no printer context, so a
|
||||
// failing profile cannot be told apart from the ~1000 others in the sweep. Drops the default trivial
|
||||
// sink's timestamp/thread columns - noise here - in favour of the vendor/printer tag.
|
||||
void install_slice_context_log_sink()
|
||||
{
|
||||
namespace logging = boost::log;
|
||||
namespace sinks = boost::log::sinks;
|
||||
namespace expr = boost::log::expressions;
|
||||
|
||||
auto backend = boost::make_shared<sinks::text_ostream_backend>();
|
||||
backend->add_stream(boost::shared_ptr<std::ostream>(&std::clog, boost::null_deleter()));
|
||||
backend->auto_flush(true);
|
||||
|
||||
auto sink = boost::make_shared<sinks::synchronous_sink<sinks::text_ostream_backend>>(backend);
|
||||
sink->set_formatter([](const logging::record_view &rec, logging::formatting_ostream &strm) {
|
||||
strm << "[" << rec[logging::trivial::severity] << "]";
|
||||
if (!g_slice_context.empty())
|
||||
strm << " [" << g_slice_context << "]";
|
||||
strm << " " << rec[expr::smessage];
|
||||
});
|
||||
|
||||
logging::core::get()->remove_all_sinks(); // drop the default trivial sink so lines are not doubled
|
||||
logging::core::get()->add_sink(sink);
|
||||
}
|
||||
|
||||
// Slice-and-export a two-colour cube through every shipped printer (optionally scoped to one vendor via
|
||||
// -v). Unlike the static reference/placeholder checks, this expands every custom *_gcode - including
|
||||
// change_filament_gcode at the one filament change - against the printer's fully-resolved config, so
|
||||
// undefined-placeholder / invalid-flow bugs surface here. Reports every offending printer and returns 1
|
||||
// if any failed, 0 otherwise. The sweep is SEQUENTIAL by necessity: Print::process() keeps
|
||||
// process-global state, so slicing printers concurrently in one process races even with per-slice
|
||||
// Model+Print. Load in validation mode so the vendors are read straight from the -p profiles dir
|
||||
// (no data_dir/system tree) and -v scoping is honoured for free.
|
||||
int slice_all_printers(const std::string &vendor)
|
||||
{
|
||||
install_slice_context_log_sink();
|
||||
|
||||
PresetBundle bundle;
|
||||
bundle.set_is_validation_mode(true);
|
||||
bundle.set_vendor_to_validate(vendor); // empty == all vendors
|
||||
AppConfig app_config;
|
||||
app_config.set("preset_folder", "default");
|
||||
try {
|
||||
bundle.load_presets(app_config, ForwardCompatibilitySubstitutionRule::Disable);
|
||||
} catch (const std::exception &ex) {
|
||||
BOOST_LOG_TRIVIAL(error) << ex.what();
|
||||
std::cout << "Validation failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Enable every instantiable model/variant in AppConfig - system printers are hidden until enabled;
|
||||
// without this select_preset_by_name silently falls back to the "Default Printer".
|
||||
std::vector<std::pair<std::string, std::string>> printers; // (vendor name, preset name)
|
||||
for (const Preset &p : bundle.printers.get_presets()) {
|
||||
if (p.vendor == nullptr) continue; // skips the Default Printer
|
||||
const std::string model = p.config.opt_string("printer_model");
|
||||
const std::string variant = p.config.opt_string("printer_variant");
|
||||
if (model.empty() || variant.empty()) continue; // skip non-instantiable base/common configs
|
||||
app_config.set_variant(p.vendor->id, model, variant, true);
|
||||
printers.push_back({p.vendor->name, p.name});
|
||||
}
|
||||
bundle.load_installed_printers(app_config);
|
||||
|
||||
if (printers.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "No instantiable printer presets found"
|
||||
<< (vendor.empty() ? "" : " for vendor " + vendor);
|
||||
std::cout << "Validation failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "Slicing " << printers.size() << " printer preset(s)"
|
||||
<< (vendor.empty() ? "" : " for vendor " + vendor) << "..." << std::endl;
|
||||
|
||||
int failures = 0;
|
||||
for (const auto &[vendor_name, printer] : printers) {
|
||||
g_slice_context = vendor_name + " / " + printer; // tag every engine log line from this slice
|
||||
const bool selected = bundle.printers.select_preset_by_name(printer, /*force=*/true);
|
||||
if (!selected || bundle.printers.get_selected_preset_name() != printer) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Printer preset \"" << printer << "\" could not be selected";
|
||||
++failures;
|
||||
continue;
|
||||
}
|
||||
|
||||
select_printer_default_presets(bundle); // slice with the printer's shipped process/filament
|
||||
bundle.update_multi_material_filament_presets(); // size filament_presets to nozzle count
|
||||
bundle.update_compatible(PresetSelectCompatibleType::Always);
|
||||
|
||||
// Never slice with a generic default preset - that would validate stand-in settings, not the
|
||||
// real profile (a legit per-profile error).
|
||||
if (bundle.prints.get_selected_preset().is_default || bundle.filaments.get_selected_preset().is_default) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Printer \"" << printer << "\" fell back to a default preset (process=\""
|
||||
<< bundle.prints.get_selected_preset_name() << "\", filament=\""
|
||||
<< bundle.filaments.get_selected_preset_name() << "\")";
|
||||
++failures;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Grow to a 2nd filament so the cube can change colour; never shrink a multi-nozzle printer
|
||||
// below its nozzle count, or full_config()'s flush-volume matrix no longer matches validate().
|
||||
const size_t nozzles = bundle.printers.get_selected_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->size();
|
||||
bundle.set_num_filaments((unsigned int) std::max<size_t>(2, nozzles));
|
||||
|
||||
// Mirror the app's manual filament->nozzle assignment for a multi-nozzle BBL printer: put each
|
||||
// filament on its own nozzle and pin the map (fmmManual) so full_config() collapses every filament to
|
||||
// the variant of the nozzle it actually prints from, and the engine keeps that assignment instead of
|
||||
// auto-remapping it during process(). Without this the synthetic 2nd filament keeps nozzle 1's variant
|
||||
// while the auto map moves it to nozzle 2 - harmless, but on the one printer whose nozzles differ in
|
||||
// type (Direct Drive + Bowden) the mismatched lookup spams [error] lines. Single-nozzle and non-BBL
|
||||
// printers keep the default map (their toolchange rides the AMS/tool-changer path unchanged).
|
||||
const bool pin_filament_map = bundle.is_bbl_vendor() && nozzles > 1;
|
||||
if (pin_filament_map) {
|
||||
auto &fmap = bundle.project_config.option<ConfigOptionInts>("filament_map", true)->values;
|
||||
for (size_t i = 0; i < fmap.size(); ++i)
|
||||
fmap[i] = int(i % nozzles) + 1;
|
||||
}
|
||||
|
||||
DynamicPrintConfig cfg = bundle.full_config();
|
||||
cfg.set_key_value("enable_prime_tower", new ConfigOptionBool(true)); // force a purge tower so the change is detectable
|
||||
// The map above drives full_config()'s per-filament variant collapse; fmmManual on the sliced config
|
||||
// stops process() from auto-remapping filaments back onto a different nozzle (which would re-introduce
|
||||
// the variant mismatch this pinning avoids).
|
||||
if (pin_filament_map)
|
||||
cfg.set_key_value("filament_map_mode", new ConfigOptionEnum<FilamentMapMode>(fmmManual));
|
||||
|
||||
// full_config() grows filament_extruder_variant to one entry per filament, but because the synthetic
|
||||
// 2nd filament is a duplicate of the first (set_num_filaments copies the same preset), it leaves
|
||||
// filament_self_index at size 1. That makes update_values_to_printer_extruders_for_multiple_filaments
|
||||
// fail to resolve the 2nd filament's variant - a benign fallback that spams [error] lines. A real
|
||||
// 2-colour project ships filament_self_index = 1,2,...; mirror that so the sweep log stays clean. The
|
||||
// slice output is unaffected: the duplicated filament's per-variant values are identical to the first.
|
||||
if (auto *variants = cfg.option<ConfigOptionStrings>("filament_extruder_variant")) {
|
||||
auto &self_index = cfg.option<ConfigOptionInts>("filament_self_index", true)->values;
|
||||
if (self_index.size() != variants->size()) {
|
||||
self_index.resize(variants->size());
|
||||
for (size_t i = 0; i < self_index.size(); ++i)
|
||||
self_index[i] = int(i) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const std::string out = slice_two_color_cube_and_export(cfg, bundle.is_bbl_vendor());
|
||||
if (out.empty() || out.find("G1") == std::string::npos) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Printer \"" << printer << "\" produced no g-code";
|
||||
++failures;
|
||||
} else if (out.find("CP TOOLCHANGE START") == std::string::npos) {
|
||||
// The filament change never rode the tower, so change_filament_gcode was not exercised.
|
||||
BOOST_LOG_TRIVIAL(error) << "Printer \"" << printer
|
||||
<< "\" sliced but the filament change never fired (no CP TOOLCHANGE START)";
|
||||
++failures;
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Printer \"" << printer << "\" failed to slice: " << ex.what();
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
g_slice_context.clear();
|
||||
|
||||
if (failures > 0) {
|
||||
std::cout << failures << " of " << printers.size() << " printer preset(s) failed to slice" << std::endl;
|
||||
std::cout << "Validation failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "All " << printers.size() << " printer preset(s) sliced successfully" << std::endl;
|
||||
std::cout << "Validation completed successfully" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
po::options_description desc("Orca Profile Validator\nUsage");
|
||||
@@ -95,6 +363,7 @@ int main(int argc, char* argv[])
|
||||
#endif
|
||||
("vendor,v", po::value<std::string>()->default_value(""), "Vendor name. Optional, all profiles present in the folder will be validated if not specified")
|
||||
("generate_presets,g", po::value<bool>()->default_value(false), "Generate user presets for mock test")
|
||||
("slice,s", po::bool_switch()->default_value(false), "Slice a two-colour cube through every printer to expand all custom g-code (catches placeholder/flow errors that static checks miss). Off unless this flag is present.")
|
||||
("check_filament_subtypes,f", po::bool_switch()->default_value(false), "Also flag printers with duplicate (ambiguous) filament subtypes. Off unless this flag is present.")
|
||||
("log_level,l", po::value<int>()->default_value(2), "Log level. Optional, default is 2 (warning). Higher values produce more detailed logs.");
|
||||
// clang-format on
|
||||
@@ -119,6 +388,7 @@ int main(int argc, char* argv[])
|
||||
std::string vendor = vm["vendor"].as<std::string>();
|
||||
int log_level = vm["log_level"].as<int>();
|
||||
bool generate_user_preset = vm["generate_presets"].as<bool>();
|
||||
bool slice_mode = vm["slice"].as<bool>();
|
||||
bool check_filament_subtypes = vm["check_filament_subtypes"].as<bool>();
|
||||
|
||||
// check if path is valid, and return error if not
|
||||
@@ -132,6 +402,12 @@ int main(int argc, char* argv[])
|
||||
// std::cout<<"log_level: "<<log_level<<std::endl;
|
||||
|
||||
set_data_dir(path);
|
||||
// Orca: the profiles folder lives at <resources>/profiles, so point resources_dir() at that
|
||||
// <resources> parent. Without this, resources_dir() is empty and slice mode's HRC lookup
|
||||
// (info/nozzle_info.json) resolves to a non-existent relative path and falls back to a
|
||||
// built-in table (logging a spurious parse error and dropping the E3D entry).
|
||||
if (fs::exists(fs::path(path).parent_path() / "info"))
|
||||
set_resources_dir(fs::path(path).parent_path().string());
|
||||
|
||||
auto user_dir = fs::path(Slic3r::data_dir()) / PRESET_USER_DIR;
|
||||
user_dir.make_preferred();
|
||||
@@ -139,6 +415,12 @@ int main(int argc, char* argv[])
|
||||
fs::create_directory(user_dir);
|
||||
|
||||
set_logging_level(log_level);
|
||||
|
||||
// Slice mode expands every printer's custom g-code by actually slicing (see slice_all_printers).
|
||||
// A distinct opt-in mode so the default static checks stay fast for every profile PR.
|
||||
if (slice_mode)
|
||||
return slice_all_printers(vendor);
|
||||
|
||||
auto preset_bundle = new PresetBundle();
|
||||
// preset_bundle->setup_directories();
|
||||
preset_bundle->set_is_validation_mode(true);
|
||||
|
||||
@@ -6551,8 +6551,11 @@ void GCodeProcessor::process_T(const std::string_view command, int nozzle_id)
|
||||
if (command.length() > 1) {
|
||||
if (eid < 0 || eid > 254) {
|
||||
//BBS: T255, T1000 and T1100 is used as special command for BBL machine and does not cost time. return directly
|
||||
// Orca: T1001 (hotend-type detection) and T65535/T65279 (AMS unload virtual-tool selects, paired with
|
||||
// M620/M621 S65535/S65279) are firmware opcodes emitted verbatim by BBL machine start/end g-code, not
|
||||
// real tool changes - whitelist them so the time estimator stops flagging these valid lines.
|
||||
if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) && (command == "Tx" || command == "Tc" || command == "T?" ||
|
||||
eid == 1000 || eid == 1100 || eid == 255))
|
||||
eid == 1000 || eid == 1100 || eid == 255 || eid == 1001 || eid == 65279 || eid == 65535))
|
||||
return;
|
||||
|
||||
// T-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools)
|
||||
|
||||
@@ -3677,6 +3677,8 @@ int Print::get_filament_config_indx(int filament_id, int layer_id)
|
||||
|
||||
void Print::update_filament_self_index_cache()
|
||||
{
|
||||
m_missing_nozzle_group_logged.clear(); // reset the per-slice get_config_index log dedupe
|
||||
|
||||
std::vector<int> values;
|
||||
if (m_full_print_config.has("filament_self_index")) {
|
||||
values = m_full_print_config.option<ConfigOptionInts>("filament_self_index")->values;
|
||||
@@ -3722,9 +3724,12 @@ int Print::get_config_index(int filament_id, int layer_id, const std::vector<std
|
||||
return filament_id;
|
||||
auto nozzle_info = group_result->get_nozzle_for_filament(filament_id, layer_id);
|
||||
if (!nozzle_info.has_value()) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
|
||||
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3%") % __LINE__ % filament_id %
|
||||
layer_id;
|
||||
// Orca: this fallback runs per-filament/per-layer in the g-code hot path — log once per filament
|
||||
// (reset each slice) instead of flooding thousands of identical lines that bury the real error.
|
||||
if (m_missing_nozzle_group_logged.insert(filament_id).second)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
|
||||
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3% (further occurrences for this filament suppressed)") % __LINE__ % filament_id %
|
||||
layer_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3751,9 +3756,12 @@ int Print::get_config_index(int filament_id, int layer_id, const std::vector<std
|
||||
return (int)get_extruder_id(filament_id);
|
||||
auto nozzle_info = group_result->get_nozzle_for_filament(filament_id, layer_id);
|
||||
if (!nozzle_info.has_value()) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
|
||||
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3%") % __LINE__ % filament_id %
|
||||
layer_id;
|
||||
// Orca: this fallback runs per-filament/per-layer in the g-code hot path — log once per filament
|
||||
// (reset each slice) instead of flooding thousands of identical lines that bury the real error.
|
||||
if (m_missing_nozzle_group_logged.insert(filament_id).second)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
|
||||
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3% (further occurrences for this filament suppressed)") % __LINE__ % filament_id %
|
||||
layer_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1303,6 +1303,10 @@ private:
|
||||
FilamentIndexMap m_filament_index_map;
|
||||
// Used to cache printer and process parameter information
|
||||
PrintIndexMap m_nozzle_index_map;
|
||||
// Orca: filament ids already reported as missing a nozzle-group entry this slice. get_config_index()
|
||||
// falls back per-filament/per-layer in the g-code hot path, so this dedupes its log to once per
|
||||
// filament instead of flooding thousands of identical error lines. Cleared with the caches each slice.
|
||||
std::set<int> m_missing_nozzle_group_logged;
|
||||
// save the config value of "filament_self_index"
|
||||
std::vector<int> m_filament_self_index;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ struct Params
|
||||
: /*max_acceleration(max_acceleration), */raft_layers_count(raft_layers_count), brim_type(brim_type), brim_width(brim_width)
|
||||
{
|
||||
if (filament_types.size() > 1) {
|
||||
BOOST_LOG_TRIVIAL(warning)
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< "SupportSpotsGenerator does not currently handle different materials properly, only first will be used";
|
||||
}
|
||||
if (filament_types.empty() || filament_types[0].empty()) {
|
||||
|
||||
@@ -13,13 +13,17 @@ endif()
|
||||
set(TEST_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data)
|
||||
file(TO_NATIVE_PATH "${TEST_DATA_DIR}" TEST_DATA_DIR)
|
||||
|
||||
# Shipped vendor profiles, so tests can exercise the real machine/filament gcode.
|
||||
set(PROFILES_DIR ${CMAKE_SOURCE_DIR}/resources/profiles)
|
||||
file(TO_NATIVE_PATH "${PROFILES_DIR}" PROFILES_DIR)
|
||||
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
|
||||
set(CATCH_EXTRA_ARGS "" CACHE STRING "Extra arguments for catch2 test suites.") # Unknown if this still works and/or should be replaced with something else.
|
||||
|
||||
add_library(test_common INTERFACE)
|
||||
target_compile_definitions(test_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)" CATCH_CONFIG_FAST_COMPILE)
|
||||
target_compile_definitions(test_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)" PROFILES_DIR=R"\(${PROFILES_DIR}\)" CATCH_CONFIG_FAST_COMPILE)
|
||||
target_include_directories(test_common INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
if (APPLE)
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/ModelArrange.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
@@ -680,3 +682,141 @@ SCENARIO("Prime-tower visits without a filament change do not advance the toolch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Real-profile toolchange coverage, targeted. The all-vendors sweep in test_profile_slicing.cpp now
|
||||
// slices a two-colour cube per printer, so it already expands every shipped change_filament_gcode with
|
||||
// each printer's DEFAULT extruder variants (both the single-nozzle append_tcr and dual-nozzle set_extruder
|
||||
// paths). What that sweep can't reach is a variant-conditional branch the defaults never select — H2D's
|
||||
// change gcode has an `== "Direct Drive TPU High Flow"` block. This scenario forces that branch by handing
|
||||
// the extruders distinct kits, so an unregistered placeholder inside it still throws "Variable does not
|
||||
// exist" here instead of only in the field.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Two 20mm cubes on separate extruders of a BBL machine, printed by object so exactly
|
||||
// one real toolchange fires and drives the change_filament_gcode. Returns the g-code.
|
||||
static std::string slice_two_object_bbl(DynamicPrintConfig &config)
|
||||
{
|
||||
config.set_key_value("print_sequence", new ConfigOptionEnum<PrintSequence>(PrintSequence::ByObject));
|
||||
|
||||
Model model;
|
||||
auto *obj1 = model.add_object();
|
||||
obj1->add_volume(cube(20));
|
||||
obj1->add_instance();
|
||||
auto *obj2 = model.add_object();
|
||||
obj2->add_volume(cube(20));
|
||||
obj2->add_instance();
|
||||
obj2->config.set_key_value("extruder", new ConfigOptionInt(2));
|
||||
|
||||
Print print;
|
||||
print.is_BBL_printer() = true;
|
||||
arrange_objects_on_test_bed(model, config);
|
||||
for (auto *mo : model.objects) {
|
||||
mo->ensure_on_bed();
|
||||
print.auto_assign_extruders(mo);
|
||||
}
|
||||
print.apply(model, config);
|
||||
print.validate();
|
||||
print.set_status_silent();
|
||||
print.process();
|
||||
return Slic3r::Test::gcode(print);
|
||||
}
|
||||
|
||||
// The real change_filament_gcode of a shipped "<printer> 0.4 nozzle" machine profile.
|
||||
static std::string shipped_change_filament_gcode(const std::string &printer)
|
||||
{
|
||||
const std::string path = std::string(PROFILES_DIR) + "/BBL/machine/Bambu Lab " + printer + " 0.4 nozzle.json";
|
||||
// PROFILES_DIR is an absolute path baked in at build time; a sparse test checkout
|
||||
// without resources/ leaves it missing. Skip rather than dereference a config that
|
||||
// never loaded - this is the only fff_print test that reads a shipped profile.
|
||||
if (!boost::filesystem::exists(path))
|
||||
SKIP("shipped profile not present in this checkout: " << path);
|
||||
DynamicPrintConfig config;
|
||||
std::map<std::string, std::string> key_values;
|
||||
std::string reason;
|
||||
config.load_from_json(path, ForwardCompatibilitySubstitutionRule::Enable, key_values, reason);
|
||||
// Fail loudly on a malformed/renamed profile instead of null-dereferencing in opt_string.
|
||||
INFO("profile: " << path << (reason.empty() ? "" : (" load reason: " + reason)));
|
||||
REQUIRE(config.has("change_filament_gcode"));
|
||||
return config.opt_string("change_filament_gcode");
|
||||
}
|
||||
|
||||
SCENARIO("Toolchange gcode resolves old/new_extruder_variant from printer_extruder_variant", "[GCodeWriter][H2C]")
|
||||
{
|
||||
GIVEN("a BBL dual-extruder print whose change gcode reads the extruder-variant placeholders") {
|
||||
DynamicPrintConfig config = dual_extruder_toolchange_config();
|
||||
// A distinctive variant that can only reach the g-code through printer_extruder_variant.
|
||||
// Both entries carry it so the assertion is independent of which physical extruder the
|
||||
// emitted change routes through.
|
||||
config.set_key_value("printer_extruder_variant",
|
||||
new ConfigOptionStrings({"Direct Drive TPU High Flow", "Direct Drive TPU High Flow"}));
|
||||
config.set_key_value("change_filament_gcode", new ConfigOptionString(
|
||||
"; VARIANT old={old_extruder_variant} new={new_extruder_variant}\nT[next_filament_id]\n"));
|
||||
|
||||
WHEN("the print is sliced") {
|
||||
const std::string gcode = slice_two_object_bbl(config);
|
||||
THEN("both placeholders resolve to the printer_extruder_variant value") {
|
||||
// The resolved line is the proof: an unresolved token or a parser throw would
|
||||
// prevent this exact line from being emitted. (A negative "{token}" check is
|
||||
// unreliable — the g-code's trailing config dump echoes the raw template.)
|
||||
REQUIRE_THAT(gcode, Catch::Matchers::ContainsSubstring(
|
||||
"; VARIANT old=Direct Drive TPU High Flow new=Direct Drive TPU High Flow"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("Global current-tool placeholders resolve in a context with no local injection", "[GCodeWriter][H2C]")
|
||||
{
|
||||
GIVEN("a BBL dual-extruder print whose before_layer_change_gcode reads the current-tool placeholders") {
|
||||
DynamicPrintConfig config = dual_extruder_toolchange_config();
|
||||
// before_layer_change is one of the contexts that inject NO current_* into their local config
|
||||
// (unlike change_filament / machine_end / layer_change), so these placeholders can only resolve
|
||||
// through the GLOBAL parser vars published at each toolchange (and at the initial set_extruder).
|
||||
// Pre-fix current_filament_id / current_extruder_id / current_nozzle_id were undefined here and the
|
||||
// whole slice threw a PlaceholderParserError — the same failure mode X2D's layer_change hit.
|
||||
config.set_key_value("before_layer_change_gcode", new ConfigOptionString(
|
||||
"; GVAR fid={current_filament_id} eid={current_extruder_id} nid={current_nozzle_id}\n"));
|
||||
|
||||
WHEN("the print is sliced (obj1 on filament 0, obj2 on filament 1)") {
|
||||
std::string gcode;
|
||||
REQUIRE_NOTHROW(gcode = slice_two_object_bbl(config));
|
||||
THEN("all three globals resolve to the CORRECT active-tool values on both sides of the change") {
|
||||
// Assert the FULL resolved marker, not just no-throw: obj1 prints on filament 0 (extruder 0,
|
||||
// nozzle 0) and obj2 on filament 1 (extruder 1, nozzle 1). Locking every field means a
|
||||
// stale or wrong global (e.g. obj2 still reading fid=0, or a mismatched extruder/nozzle id)
|
||||
// fails here — this is the value guard that replaces the old "throws on undefined" canary.
|
||||
// Only the emitted before_layer_change lines carry resolved values; the trailing config dump
|
||||
// keeps the raw "{current_filament_id}" template, so these are unambiguous.
|
||||
REQUIRE_THAT(gcode, Catch::Matchers::ContainsSubstring("; GVAR fid=0 eid=0 nid=0"));
|
||||
REQUIRE_THAT(gcode, Catch::Matchers::ContainsSubstring("; GVAR fid=1 eid=1 nid=1"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("Shipped dual-nozzle change_filament_gcode resolves during a real slice", "[GCodeWriter][H2C][Profiles]")
|
||||
{
|
||||
const std::string printer = GENERATE(std::string("H2C"), std::string("H2D"), std::string("H2D Pro"), std::string("X2D"));
|
||||
|
||||
GIVEN("the real " + printer + " change_filament_gcode driving a BBL dual-extruder slice") {
|
||||
DynamicPrintConfig config = dual_extruder_toolchange_config();
|
||||
config.set_key_value("change_filament_gcode", new ConfigOptionString(shipped_change_filament_gcode(printer)));
|
||||
// H2D's gcode branches on the extruder variant; give the extruders distinct kits so the
|
||||
// "Direct Drive TPU High Flow" branch is reachable.
|
||||
config.set_key_value("printer_extruder_variant",
|
||||
new ConfigOptionStrings({"Direct Drive Standard", "Direct Drive TPU High Flow"}));
|
||||
// Extruder-indexed machine rates the stock gcode divides by (default size 1); size to 2 extruders.
|
||||
config.set_key_value("hotend_cooling_rate", new ConfigOptionFloatsNullable({2.0, 2.0}));
|
||||
config.set_key_value("hotend_heating_rate", new ConfigOptionFloatsNullable({2.0, 2.0}));
|
||||
|
||||
THEN("every placeholder resolves (no undefined-variable throw) and the change block runs") {
|
||||
std::string gcode;
|
||||
REQUIRE_NOTHROW(gcode = slice_two_object_bbl(config));
|
||||
// A resolved marker only the emitted change block produces (the trailing config
|
||||
// dump keeps the raw "{filament_type[...]}" template), so this confirms the real
|
||||
// change_filament_gcode was expanded, not merely echoed.
|
||||
REQUIRE_THAT(gcode, Catch::Matchers::ContainsSubstring("set_filament_type:PLA"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user