@@ -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+
107157def 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