diff --git a/examples/05_orientation_stress.png b/examples/05_orientation_stress.png index f258bed..e7a6c91 100644 Binary files a/examples/05_orientation_stress.png and b/examples/05_orientation_stress.png differ diff --git a/examples/06_bend_collision_models.png b/examples/06_bend_collision_models.png index 64bd8c9..19588aa 100644 Binary files a/examples/06_bend_collision_models.png and b/examples/06_bend_collision_models.png differ diff --git a/examples/08_custom_bend_geometry.png b/examples/08_custom_bend_geometry.png index f1369a6..7f453d7 100644 Binary files a/examples/08_custom_bend_geometry.png and b/examples/08_custom_bend_geometry.png differ diff --git a/examples/08_custom_bend_geometry.py b/examples/08_custom_bend_geometry.py index a5bd0e4..ca4c527 100644 --- a/examples/08_custom_bend_geometry.py +++ b/examples/08_custom_bend_geometry.py @@ -19,7 +19,7 @@ def main() -> None: danger_map.precompute([]) evaluator = CostEvaluator(engine, danger_map, bend_penalty=50.0, sbend_penalty=150.0) - context = AStarContext(evaluator, snap_size=1.0, bend_radii=[10.0]) + context = AStarContext(evaluator, snap_size=1.0, bend_radii=[10.0], sbend_radii=[]) metrics = AStarMetrics() pf = PathFinder(context, metrics) @@ -37,10 +37,10 @@ def main() -> None: # (Just for demonstration - we override the collision model during search) # Define a custom centered 20x20 box custom_poly = Polygon([(-10, -10), (10, -10), (10, 10), (-10, 10)]) - + print("Routing with custom collision model...") # Override bend_collision_type with a literal Polygon - context_custom = AStarContext(evaluator, snap_size=1.0, bend_radii=[10.0], bend_collision_type=custom_poly) + context_custom = AStarContext(evaluator, snap_size=1.0, bend_radii=[10.0], bend_collision_type=custom_poly, sbend_radii=[]) metrics_custom = AStarMetrics() results_custom = PathFinder(context_custom, metrics_custom, use_tiered_strategy=False).route_all( {"custom_model": netlist["custom_bend"]}, {"custom_model": 2.0} diff --git a/inire/router/astar.py b/inire/router/astar.py index 7da5f87..1d4c609 100644 --- a/inire/router/astar.py +++ b/inire/router/astar.py @@ -433,7 +433,10 @@ def process_move( else: gx, gy, go = parent_state - abs_key = (parent_state, move_class, params, net_width, context.config.bend_collision_type, snap_to_grid) + coll_type = context.config.bend_collision_type + coll_key = id(coll_type) if isinstance(coll_type, shapely.geometry.Polygon) else coll_type + + abs_key = (parent_state, move_class, params, net_width, coll_key, snap_to_grid) if abs_key in context.move_cache_abs: res = context.move_cache_abs[abs_key] move_radius = params[0] if move_class == 'B' else (params[1] if move_class == 'SB' else None) @@ -448,8 +451,14 @@ def process_move( # Trigger periodic cache eviction check (only on Absolute cache misses) context.check_cache_eviction() + # Template Cache Key (Relative to Port 0,0,Ori) + # We snap the parameters to ensure template re-use + snapped_params = params + if move_class == 'SB': + snapped_params = (snap_search_grid(params[0], snap), params[1]) + self_dilation = context.cost_evaluator.collision_engine.clearance / 2.0 - rel_key = (base_ori, move_class, params, net_width, context.config.bend_collision_type, self_dilation, snap_to_grid) + rel_key = (base_ori, move_class, snapped_params, net_width, coll_key, self_dilation, snap_to_grid) cache_key = (gx, gy, go, move_type, net_width) if cache_key in context.hard_collision_set: @@ -465,7 +474,7 @@ def process_move( elif move_class == 'B': res_rel = Bend90.generate(p0, params[0], net_width, params[1], collision_type=context.config.bend_collision_type, clip_margin=context.config.bend_clip_margin, dilation=self_dilation, snap_to_grid=snap_to_grid, snap_size=snap) elif move_class == 'SB': - res_rel = SBend.generate(p0, params[0], params[1], net_width, collision_type=context.config.bend_collision_type, clip_margin=context.config.bend_clip_margin, dilation=self_dilation, snap_to_grid=snap_to_grid, snap_size=snap) + res_rel = SBend.generate(p0, snapped_params[0], snapped_params[1], net_width, collision_type=context.config.bend_collision_type, clip_margin=context.config.bend_clip_margin, dilation=self_dilation, snap_to_grid=snap_to_grid, snap_size=snap) else: return context.move_cache_rel[rel_key] = res_rel diff --git a/inire/router/cost.py b/inire/router/cost.py index 446de8e..83a16f1 100644 --- a/inire/router/cost.py +++ b/inire/router/cost.py @@ -151,8 +151,6 @@ class CostEvaluator: penalty += 2 * bp else: # 90 or 270 degree rotation penalty += 1 * bp - - p1 = penalty # 2. Side Check (Entry half-plane) v_dx = tx - current.x @@ -162,8 +160,6 @@ class CostEvaluator: if side_proj < -0.1 or (side_proj < self._min_radius and perp_dist > 0.1): penalty += 2 * bp - - p2 = penalty - p1 # 3. Traveling Away # Optimization: avoid np.radians/cos/sin if current_ori is standard 0,90,180,270 @@ -178,15 +174,11 @@ class CostEvaluator: move_proj = v_dx * c_cos + v_dy * c_sin if move_proj < -0.1: penalty += 2 * bp - - p3 = penalty - p1 - p2 # 4. Jog Alignment if diff < 0.1: if perp_dist > 0.1: penalty += 2 * bp - - p4 = penalty - p1 - p2 - p3 return self.greedy_h_weight * (dist + penalty)