Spaces:
Running
Running
| from __future__ import annotations | |
| import zipfile | |
| import numpy as np | |
| from PIL import Image | |
| from tiff_to_gcode import ( | |
| RASTER_PATTERN_SAME_DIRECTION, | |
| RASTER_PATTERN_WOODPILE, | |
| RASTER_PATTERN_Y_DIRECTION, | |
| _build_contour_layers, | |
| _trace_mask_contours, | |
| generate_snake_path_gcode, | |
| ) | |
| def _move_signature(gcode_text: str) -> list[tuple[float | None, float | None, float | None]]: | |
| signature: list[tuple[float | None, float | None, float | None]] = [] | |
| for line in gcode_text.splitlines(): | |
| if not line.startswith(("G0", "G1")): | |
| continue | |
| axes: dict[str, float] = {} | |
| for token in line.split(): | |
| if token[:1] in {"X", "Y", "Z"}: | |
| axes[token[0]] = float(token[1:]) | |
| signature.append((axes.get("X"), axes.get("Y"), axes.get("Z"))) | |
| return signature | |
| def _move_endpoints_for_color(gcode_text: str, color: int) -> list[tuple[float, float]]: | |
| x = y = 0.0 | |
| endpoints: list[tuple[float, float]] = [] | |
| for line in gcode_text.splitlines(): | |
| if not line.startswith(("G0", "G1")): | |
| continue | |
| start = (x, y) | |
| for token in line.split(): | |
| if token.startswith("X"): | |
| x += float(token[1:]) | |
| if token.startswith("Y"): | |
| y += float(token[1:]) | |
| if f"; Color {color}" in line: | |
| endpoints.extend([start, (x, y)]) | |
| return endpoints | |
| def _moves_with_colors(gcode_text: str) -> list[dict]: | |
| x = y = z = 0.0 | |
| moves: list[dict] = [] | |
| for line in gcode_text.splitlines(): | |
| if not line.startswith(("G0", "G1")): | |
| continue | |
| start = (x, y, z) | |
| for token in line.split(): | |
| if token.startswith("X"): | |
| x += float(token[1:]) | |
| if token.startswith("Y"): | |
| y += float(token[1:]) | |
| if token.startswith("Z"): | |
| z += float(token[1:]) | |
| color = None | |
| if "; Color " in line: | |
| color = int(line.rsplit("; Color ", 1)[1]) | |
| moves.append({"start": start, "end": (x, y, z), "color": color}) | |
| return moves | |
| def test_trace_mask_contours_uses_tiff_pixel_border_edges() -> None: | |
| contours = _trace_mask_contours( | |
| np.array( | |
| [ | |
| [True, True], | |
| [True, True], | |
| ], | |
| dtype=bool, | |
| ), | |
| pixel_size=1.0, | |
| ) | |
| assert contours == [[(0.0, 0.0), (2.0, 0.0), (2.0, 2.0), (0.0, 2.0), (0.0, 0.0)]] | |
| def test_contour_tracing_aligns_default_raster_border_pixel_frame(tmp_path) -> None: | |
| raster_tiff = tmp_path / "raster_slice_0000.tif" | |
| raster_image = Image.new("L", (7, 6), 255) | |
| raster_image.putpixel((4, 3), 0) | |
| raster_image.save(raster_tiff) | |
| raster_zip = tmp_path / "raster_slices.zip" | |
| with zipfile.ZipFile(raster_zip, mode="w") as archive: | |
| archive.write(raster_tiff, arcname=raster_tiff.name) | |
| contour_tiff = tmp_path / "contour_slice_0000.tif" | |
| contour_image = Image.new("L", (7, 6), 255) | |
| contour_image.putpixel((4, 3), 0) | |
| contour_image.save(contour_tiff) | |
| gcode_path = generate_snake_path_gcode( | |
| raster_zip, | |
| shape_name="aligned_contour", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| fil_width=1.0, | |
| all_g1=True, | |
| contour_tiff_sets=[{"owner_idx": 1, "tiff_paths": [str(contour_tiff)]}], | |
| active_contour_owner=1, | |
| ) | |
| points = _move_endpoints_for_color(gcode_path.read_text(), 255) | |
| xs = [point[0] for point in points] | |
| ys = [point[1] for point in points] | |
| assert (min(xs), max(xs)) == (1.0, 2.0) | |
| assert (min(ys), max(ys)) == (-0.5, 0.5) | |
| def test_contour_tracing_travels_to_nearest_border_after_infill(tmp_path) -> None: | |
| tiff_path = tmp_path / "slice_0000.tif" | |
| image = Image.new("L", (7, 6), 255) | |
| image.putpixel((4, 3), 0) | |
| image.save(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| gcode_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="nearest_border_contour", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| fil_width=1.0, | |
| all_g1=True, | |
| contour_tiff_sets=[{"owner_idx": 1, "tiff_paths": [str(tiff_path)]}], | |
| active_contour_owner=1, | |
| ) | |
| moves = _moves_with_colors(gcode_path.read_text()) | |
| assert moves[1] == { | |
| "start": (1.0, 0.0, 0.0), | |
| "end": (2.0, 0.0, 0.0), | |
| "color": 255, | |
| } | |
| assert moves[2]["color"] == 255 | |
| assert moves[2]["start"] == (2.0, 0.0, 0.0) | |
| def test_contour_tracing_anchors_to_expanding_raster_frame(tmp_path) -> None: | |
| tiff_path = tmp_path / "slice_0000.tif" | |
| image = Image.new("L", (7, 5), 255) | |
| for col in [3]: | |
| image.putpixel((col, 0), 0) | |
| for col in range(2, 5): | |
| image.putpixel((col, 1), 0) | |
| for col in range(1, 6): | |
| image.putpixel((col, 2), 0) | |
| image.save(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| gcode_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="expanding_contour", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| fil_width=1.0, | |
| all_g1=True, | |
| contour_tiff_sets=[{"owner_idx": 1, "tiff_paths": [str(tiff_path)]}], | |
| active_contour_owner=1, | |
| ) | |
| print_moves = [ | |
| move for move in _moves_with_colors(gcode_path.read_text()) if move["color"] == 255 | |
| ] | |
| contour_points = [ | |
| point | |
| for move in print_moves[3:] | |
| for point in (move["start"], move["end"]) | |
| ] | |
| xs = [point[0] for point in contour_points] | |
| ys = [point[1] for point in contour_points] | |
| assert print_moves[:3] == [ | |
| {"start": (1.0, 0.0, 0.0), "end": (2.0, 0.0, 0.0), "color": 255}, | |
| {"start": (3.0, 1.0, 0.0), "end": (0.0, 1.0, 0.0), "color": 255}, | |
| {"start": (-1.0, 2.0, 0.0), "end": (4.0, 2.0, 0.0), "color": 255}, | |
| ] | |
| assert print_moves[3]["start"] == (4.0, 2.0, 0.0) | |
| assert (min(xs), max(xs)) == (-1.0, 4.0) | |
| assert (min(ys), max(ys)) == (-0.5, 2.5) | |
| def test_contour_tracing_uses_shifted_layer_raster_frame(tmp_path) -> None: | |
| tiff_paths = [] | |
| for index, pixel in enumerate([(4, 3), (5, 4)]): | |
| tiff_path = tmp_path / f"slice_{index:04d}.tif" | |
| image = Image.new("L", (8, 7), 255) | |
| image.putpixel(pixel, 0) | |
| image.save(tiff_path) | |
| tiff_paths.append(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| for tiff_path in tiff_paths: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| gcode_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="shifted_layer_contour", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| fil_width=1.0, | |
| layer_height=1.0, | |
| all_g1=True, | |
| contour_tiff_sets=[{"owner_idx": 1, "tiff_paths": [str(p) for p in tiff_paths]}], | |
| active_contour_owner=1, | |
| ) | |
| layer_one_prints = [ | |
| move | |
| for move in _moves_with_colors(gcode_path.read_text()) | |
| if move["color"] == 255 | |
| and move["start"][2] == 1.0 | |
| and move["end"][2] == 1.0 | |
| ] | |
| assert layer_one_prints[0] == { | |
| "start": (3.0, 1.0, 1.0), | |
| "end": (2.0, 1.0, 1.0), | |
| "color": 255, | |
| } | |
| contour_points = [ | |
| point | |
| for move in layer_one_prints[1:] | |
| for point in (move["start"], move["end"]) | |
| ] | |
| xs = [point[0] for point in contour_points] | |
| ys = [point[1] for point in contour_points] | |
| assert layer_one_prints[1]["start"] == (2.0, 1.0, 1.0) | |
| assert layer_one_prints[1]["end"] == (2.0, 0.5, 1.0) | |
| assert (min(xs), max(xs)) == (2.0, 3.0) | |
| assert (min(ys), max(ys)) == (0.5, 1.5) | |
| def test_contour_tracing_mirrors_odd_layer_y_frame(tmp_path) -> None: | |
| tiff_paths = [] | |
| for index in range(2): | |
| tiff_path = tmp_path / f"slice_{index:04d}.tif" | |
| image = Image.new("L", (8, 7), 255) | |
| image.putpixel((4, 3), 0) | |
| image.putpixel((4, 4), 0) | |
| image.putpixel((5, 4), 0) | |
| image.save(tiff_path) | |
| tiff_paths.append(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| for tiff_path in tiff_paths: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| gcode_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="odd_layer_y_contour", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| fil_width=1.0, | |
| layer_height=1.0, | |
| all_g1=True, | |
| contour_tiff_sets=[{"owner_idx": 1, "tiff_paths": [str(p) for p in tiff_paths]}], | |
| active_contour_owner=1, | |
| ) | |
| layer_one_prints = [ | |
| move | |
| for move in _moves_with_colors(gcode_path.read_text()) | |
| if move["color"] == 255 | |
| and move["start"][2] == 1.0 | |
| and move["end"][2] == 1.0 | |
| ] | |
| contour_points = [ | |
| point | |
| for move in layer_one_prints[2:] | |
| for point in (move["start"], move["end"]) | |
| ] | |
| xs = [point[0] for point in contour_points] | |
| ys = [point[1] for point in contour_points] | |
| assert layer_one_prints[:2] == [ | |
| {"start": (1.0, 1.0, 1.0), "end": (3.0, 1.0, 1.0), "color": 255}, | |
| {"start": (2.0, 0.0, 1.0), "end": (1.0, 0.0, 1.0), "color": 255}, | |
| ] | |
| assert layer_one_prints[2]["start"] == (1.0, 0.0, 1.0) | |
| assert layer_one_prints[2]["end"] == (1.0, -0.5, 1.0) | |
| assert (min(xs), max(xs)) == (1.0, 3.0) | |
| assert (min(ys), max(ys)) == (-0.5, 1.5) | |
| def test_contour_tracing_closes_loop_and_restores_raster_endpoint(tmp_path) -> None: | |
| tiff_paths = [] | |
| for index in range(4): | |
| tiff_path = tmp_path / f"slice_{index:04d}.tif" | |
| image = Image.new("L", (8, 8), 255) | |
| image.putpixel((4, 2), 0) | |
| image.putpixel((4, 3), 0) | |
| image.putpixel((5, 4), 0) | |
| image.save(tiff_path) | |
| tiff_paths.append(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| for tiff_path in tiff_paths: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| gcode_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="odd_layer_last_infill_anchor", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| fil_width=1.0, | |
| layer_height=1.0, | |
| all_g1=True, | |
| contour_tiff_sets=[{"owner_idx": 1, "tiff_paths": [str(p) for p in tiff_paths]}], | |
| active_contour_owner=1, | |
| ) | |
| all_moves = _moves_with_colors(gcode_path.read_text()) | |
| for layer_z in (1.0, 3.0): | |
| layer_moves = [ | |
| move | |
| for move in all_moves | |
| if move["start"][2] == layer_z | |
| and move["end"][2] == layer_z | |
| ] | |
| layer_prints = [ | |
| move | |
| for move in layer_moves | |
| if move["color"] == 255 | |
| ] | |
| assert layer_prints[:3] == [ | |
| {"start": (3.0, 2.0, layer_z), "end": (2.0, 2.0, layer_z), "color": 255}, | |
| {"start": (1.0, 1.0, layer_z), "end": (2.0, 1.0, layer_z), "color": 255}, | |
| {"start": (2.0, 0.0, layer_z), "end": (1.0, 0.0, layer_z), "color": 255}, | |
| ] | |
| contour_start = layer_prints[2]["end"] | |
| assert layer_prints[3]["start"] == contour_start | |
| assert layer_prints[-1]["end"] == contour_start | |
| last_print_index = max( | |
| idx for idx, move in enumerate(layer_moves) if move["color"] == 255 | |
| ) | |
| assert layer_moves[last_print_index + 1] == { | |
| "start": contour_start, | |
| "end": (0.0, 0.0, layer_z), | |
| "color": 0, | |
| } | |
| def test_contour_tracing_follows_default_raster_layer_flip(tmp_path) -> None: | |
| tiff_paths = [] | |
| motion_img = np.zeros((7, 8), dtype=np.uint8) | |
| motion_img[3, 4] = 255 | |
| motion_img[4, 4] = 255 | |
| motion_img[4, 5] = 255 | |
| for index in range(2): | |
| tiff_path = tmp_path / f"l_shape_{index:04d}.tif" | |
| image = Image.new("L", (8, 7), 255) | |
| image.putpixel((4, 3), 0) | |
| image.putpixel((4, 4), 0) | |
| image.putpixel((5, 4), 0) | |
| image.save(tiff_path) | |
| tiff_paths.append(str(tiff_path)) | |
| contour_layers = _build_contour_layers( | |
| [{"owner_idx": 1, "tiff_paths": tiff_paths}], | |
| [motion_img, motion_img], | |
| pixel_size=1.0, | |
| invert=True, | |
| off_color=0, | |
| work_dir=tmp_path, | |
| raster_pattern=RASTER_PATTERN_SAME_DIRECTION, | |
| ) | |
| assert contour_layers[0][0]["contours"][0] == [ | |
| (1.0, -0.5), | |
| (2.0, -0.5), | |
| (2.0, 0.5), | |
| (3.0, 0.5), | |
| (3.0, 1.5), | |
| (1.0, 1.5), | |
| (1.0, -0.5), | |
| ] | |
| assert contour_layers[1][0]["contours"][0] == [ | |
| (1.0, -0.5), | |
| (3.0, -0.5), | |
| (3.0, 0.5), | |
| (2.0, 0.5), | |
| (2.0, 1.5), | |
| (1.0, 1.5), | |
| (1.0, -0.5), | |
| ] | |
| def test_gcode_header_writes_presets_before_initial_aux_commands(tmp_path) -> None: | |
| tiff_path = tmp_path / "slice_0000.tif" | |
| Image.new("L", (1, 1), 0).save(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| gcode_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="header_order", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| ) | |
| lines = [ | |
| line.strip() | |
| for line in gcode_path.read_text().splitlines() | |
| if line.strip() | |
| ] | |
| assert lines[0] == "G91" | |
| assert lines[1].startswith("{preset}serialPort3.write(") | |
| assert lines[2].startswith("{preset}serialPort3.write(") | |
| assert lines[3].startswith("{aux_command}WAGO_ValveCommands(") | |
| assert lines[4].startswith("{aux_command}WAGO_ValveCommands(") | |
| def test_gcode_uses_g1_for_print_and_g0_for_travel(tmp_path) -> None: | |
| tiff_path = tmp_path / "slice_0000.tif" | |
| Image.new("L", (1, 1), 0).save(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| gcode_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="move_types", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| ) | |
| move_lines = [ | |
| line.strip() | |
| for line in gcode_path.read_text().splitlines() | |
| if line.startswith(("G0", "G1")) | |
| ] | |
| assert any(line.startswith("G1") and "; Color 255" in line for line in move_lines) | |
| assert all(not line.startswith("G0") for line in move_lines if "; Color 255" in line) | |
| assert all(not line.startswith("G1") for line in move_lines if "; Color 0" in line) | |
| def test_woodpile_raster_switches_print_axis_between_layers(tmp_path) -> None: | |
| tiff_paths = [] | |
| for index in range(4): | |
| tiff_path = tmp_path / f"slice_{index:04d}.tif" | |
| Image.new("L", (3, 2), 0).save(tiff_path) | |
| tiff_paths.append(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| for tiff_path in tiff_paths: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| gcode_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="woodpile", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| raster_pattern=RASTER_PATTERN_WOODPILE, | |
| ) | |
| move_lines = [ | |
| line.strip() | |
| for line in gcode_path.read_text().splitlines() | |
| if line.startswith(("G0", "G1")) | |
| ] | |
| z_move_index = next(i for i, line in enumerate(move_lines) if " Z" in line) | |
| first_layer_prints = [line for line in move_lines[:z_move_index] if line.startswith("G1") and "; Color 255" in line] | |
| second_layer_prints = [line for line in move_lines[z_move_index + 1 :] if line.startswith("G1") and "; Color 255" in line] | |
| assert any("X" in line and "Y0" in line for line in first_layer_prints) | |
| assert any("X0" in line and "Y" in line for line in second_layer_prints) | |
| x = y = 0.0 | |
| x_positions = [x] | |
| y_positions = [y] | |
| for line in move_lines: | |
| for token in line.split(): | |
| if token.startswith("X"): | |
| x += float(token[1:]) | |
| if token.startswith("Y"): | |
| y += float(token[1:]) | |
| x_positions.append(x) | |
| y_positions.append(y) | |
| assert min(x_positions) >= 0.0 | |
| assert max(x_positions) <= 3.0 | |
| assert min(y_positions) >= 0.0 | |
| assert max(y_positions) <= 2.0 | |
| def test_y_direction_raster_prints_each_layer_along_y_axis(tmp_path) -> None: | |
| tiff_paths = [] | |
| for index in range(2): | |
| tiff_path = tmp_path / f"slice_{index:04d}.tif" | |
| Image.new("L", (3, 2), 0).save(tiff_path) | |
| tiff_paths.append(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| for tiff_path in tiff_paths: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| gcode_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="y_direction", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| raster_pattern=RASTER_PATTERN_Y_DIRECTION, | |
| ) | |
| move_lines = [ | |
| line.strip() | |
| for line in gcode_path.read_text().splitlines() | |
| if line.startswith(("G0", "G1")) | |
| ] | |
| print_lines = [ | |
| line | |
| for line in move_lines | |
| if line.startswith("G1") and "; Color 255" in line | |
| ] | |
| assert print_lines | |
| assert all("X0" in line and "Y0" not in line for line in print_lines) | |
| x = y = 0.0 | |
| x_positions = [x] | |
| y_positions = [y] | |
| for line in move_lines: | |
| for token in line.split(): | |
| if token.startswith("X"): | |
| x += float(token[1:]) | |
| if token.startswith("Y"): | |
| y += float(token[1:]) | |
| x_positions.append(x) | |
| y_positions.append(y) | |
| assert min(x_positions) >= 0.0 | |
| assert max(x_positions) <= 3.0 | |
| assert min(y_positions) >= 0.0 | |
| assert max(y_positions) <= 2.0 | |
| def test_contour_tracing_skips_inactive_nozzle_outline(tmp_path) -> None: | |
| blank_tiff = tmp_path / "blank_slice_0000.tif" | |
| Image.new("L", (1, 1), 255).save(blank_tiff) | |
| blank_zip = tmp_path / "blank_slices.zip" | |
| with zipfile.ZipFile(blank_zip, mode="w") as archive: | |
| archive.write(blank_tiff, arcname=blank_tiff.name) | |
| contour_tiff = tmp_path / "contour_slice_0000.tif" | |
| Image.new("L", (1, 1), 0).save(contour_tiff) | |
| contour_sources = [{"owner_idx": 1, "tiff_paths": [str(contour_tiff)]}] | |
| active_path = generate_snake_path_gcode( | |
| blank_zip, | |
| shape_name="active_contour", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| all_g1=True, | |
| contour_tiff_sets=contour_sources, | |
| active_contour_owner=1, | |
| ) | |
| inactive_path = generate_snake_path_gcode( | |
| blank_zip, | |
| shape_name="inactive_contour", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| all_g1=True, | |
| contour_tiff_sets=contour_sources, | |
| active_contour_owner=2, | |
| ) | |
| active_text = active_path.read_text() | |
| inactive_text = inactive_path.read_text() | |
| assert _move_signature(active_text) | |
| assert _move_signature(inactive_text) == [] | |
| assert any( | |
| line.startswith("G1") and "; Color 255" in line | |
| for line in active_text.splitlines() | |
| ) | |
| assert not any("; Color 255" in line for line in inactive_text.splitlines()) | |
| def test_inactive_contour_tracing_preserves_original_raster_moves(tmp_path) -> None: | |
| tiff_paths = [] | |
| for index in range(2): | |
| tiff_path = tmp_path / f"slice_{index:04d}.tif" | |
| image = Image.new("L", (4, 3), 255) | |
| image.putpixel((1, 1), 0) | |
| image.putpixel((2, 1), 0) | |
| image.save(tiff_path) | |
| tiff_paths.append(tiff_path) | |
| zip_path = tmp_path / "slices.zip" | |
| with zipfile.ZipFile(zip_path, mode="w") as archive: | |
| for tiff_path in tiff_paths: | |
| archive.write(tiff_path, arcname=tiff_path.name) | |
| original_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="original_raster", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| all_g1=True, | |
| ) | |
| inactive_path = generate_snake_path_gcode( | |
| zip_path, | |
| shape_name="inactive_contour_raster", | |
| pressure=25, | |
| valve=7, | |
| port=3, | |
| all_g1=True, | |
| contour_tiff_sets=[{"owner_idx": 2, "tiff_paths": [str(p) for p in tiff_paths]}], | |
| active_contour_owner=1, | |
| ) | |
| assert _move_signature(inactive_path.read_text()) == _move_signature( | |
| original_path.read_text() | |
| ) | |