Skip to content

Commit b66c274

Browse files
committed
expand leaf nodes (tiling) on the generated json solution
1 parent 6e4ac75 commit b66c274

1 file changed

Lines changed: 54 additions & 1 deletion

File tree

src/guillotine/io.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,56 @@ def load_problem_json(filepath):
104104
}
105105

106106

107+
def _expand_sequence(seq, w, h, item_sizes):
108+
"""Recursively expand 'g_X' tiling nodes into explicit X/Y cuts and waste."""
109+
if isinstance(seq, str):
110+
if seq.startswith("g_"):
111+
item_id = int(seq.split("_")[1])
112+
iw = item_sizes[0][item_id]
113+
ih = item_sizes[1][item_id]
114+
115+
nx = w // iw
116+
ny = h // ih
117+
118+
if nx < 1 or ny < 1:
119+
return "empty"
120+
121+
used_w = nx * iw
122+
used_h = ny * ih
123+
124+
# Helper to recursively build the grid
125+
def build_grid(cols, rows):
126+
if cols > 1:
127+
return ("X", iw, build_grid(1, rows), build_grid(cols - 1, rows))
128+
if rows > 1:
129+
return ("Y", ih, f"g_{item_id}", build_grid(cols, rows - 1))
130+
return f"g_{item_id}"
131+
132+
tree = build_grid(nx, ny)
133+
134+
# Trim top waste if the tiling doesn't consume full height
135+
if used_h < h:
136+
tree = ("Y", used_h, tree, "empty")
137+
138+
# Trim right waste if the tiling doesn't consume full width
139+
if used_w < w:
140+
tree = ("X", used_w, tree, "empty")
141+
142+
return tree
143+
return seq
144+
145+
direction, z, left, right = seq
146+
if direction == "X":
147+
return ("X", z,
148+
_expand_sequence(left, z, h, item_sizes),
149+
_expand_sequence(right, w - z, h, item_sizes))
150+
elif direction == "Y":
151+
return ("Y", z,
152+
_expand_sequence(left, w, z, item_sizes),
153+
_expand_sequence(right, w, h - z, item_sizes))
154+
return seq
155+
156+
107157
def save_solution_json(filepath, value, sequence, item_sizes, defect_sizes,
108158
defect_positions, sheet_size, n_items_orig=None):
109159
"""Save solution to JSON file with all metrics and the full problem definition.
@@ -124,6 +174,9 @@ def save_solution_json(filepath, value, sequence, item_sizes, defect_sizes,
124174
defect_loss_pct = (defect_area / total_area) * 100
125175
efficiency_pct = (value / usable_area) * 100 if usable_area > 0 else 0
126176

177+
# Expand the sequence to explicitly map out tiled items and residual waste
178+
expanded_seq = _expand_sequence(sequence, W, H, item_sizes)
179+
127180
output = {
128181
"problem": _build_problem_dict(item_sizes, defect_sizes, defect_positions, sheet_size),
129182
"n_items_orig": n_items_orig if n_items_orig is not None else len(item_sizes[0]),
@@ -135,7 +188,7 @@ def save_solution_json(filepath, value, sequence, item_sizes, defect_sizes,
135188
"utilization": f"{value}/{total_area} ({utilization_pct:.1f}%)",
136189
"defect_loss": f"{defect_area}/{total_area} ({defect_loss_pct:.1f}%)",
137190
"efficiency": f"{value}/{usable_area} ({efficiency_pct:.1f}%)",
138-
"cut_sequence": _serialize_sequence(sequence)
191+
"cut_sequence": _serialize_sequence(expanded_seq)
139192
}
140193
}
141194

0 commit comments

Comments
 (0)