back to working after bend-aware straights
This commit is contained in:
parent
064aed31a6
commit
51d8ddca51
3 changed files with 88 additions and 29 deletions
|
|
@ -30,7 +30,7 @@ def main() -> None:
|
|||
evaluator = CostEvaluator(engine, danger_map, greedy_h_weight=2.0, unit_length_cost=0.1, bend_penalty=100.0, sbend_penalty=400.0, congestion_penalty=20.0)
|
||||
|
||||
router = AStarRouter(evaluator, node_limit=2000000, snap_size=5.0, bend_radii=[50.0], sbend_radii=[50.0], use_analytical_sbends=False)
|
||||
pf = PathFinder(router, evaluator, max_iterations=50, base_congestion_penalty=20.0, congestion_multiplier=1.2)
|
||||
pf = PathFinder(router, evaluator, max_iterations=15, base_congestion_penalty=20.0, congestion_multiplier=1.2)
|
||||
|
||||
# 2. Define Netlist
|
||||
netlist = {}
|
||||
|
|
@ -103,7 +103,8 @@ def main() -> None:
|
|||
})
|
||||
|
||||
# Save plots only for certain iterations to save time
|
||||
if idx % 20 == 0 or idx == pf.max_iterations - 1:
|
||||
#if idx % 20 == 0 or idx == pf.max_iterations - 1:
|
||||
if True:
|
||||
# Save a plot of this iteration's result
|
||||
fig, ax = plot_routing_results(current_results, obstacles, bounds, netlist=netlist)
|
||||
plot_danger_map(danger_map, ax=ax)
|
||||
|
|
|
|||
|
|
@ -269,25 +269,26 @@ def _clip_bbox(
|
|||
# Define vertices in local space (center at 0,0, symmetry axis along +X)
|
||||
# 1. Start Inner
|
||||
# 2. Start Outer
|
||||
# 3. Peak Outer (intersection of tangents at start/end)
|
||||
# 4. End Outer
|
||||
# 5. End Inner
|
||||
# 6. Peak Inner (ensures convexity and inner clipping)
|
||||
# 3. Peak Outer Start (tangent intersection approximation)
|
||||
# 4. Peak Outer End
|
||||
# 5. End Outer
|
||||
# 6. End Inner
|
||||
# 7. Peak Inner (ensures convexity and inner clipping)
|
||||
|
||||
# Outer tangent intersection point
|
||||
# Tangent at -hs: x*cos(hs) - y*sin(hs) = r_out
|
||||
# Tangent at +hs: x*cos(hs) + y*sin(hs) = r_out
|
||||
# Intersection: y=0, x = r_out / cos(hs)
|
||||
# To clip the outer corner, we use two peak vertices that follow the arc tighter.
|
||||
cos_hs = numpy.cos(half_sweep)
|
||||
if cos_hs < 1e-3: # Sweep near 180 deg
|
||||
peak_out_x = r_out * 2.0 # Fallback
|
||||
else:
|
||||
peak_out_x = r_out / cos_hs
|
||||
|
||||
cos_hs2 = numpy.cos(half_sweep / 2.0)
|
||||
tan_hs2 = numpy.tan(half_sweep / 2.0)
|
||||
|
||||
# Distance to peak from center: r_out / cos(hs/2)
|
||||
# At angles +/- hs/2
|
||||
peak_r = r_out / cos_hs2
|
||||
|
||||
local_verts = [
|
||||
[r_in * numpy.cos(-half_sweep), r_in * numpy.sin(-half_sweep)],
|
||||
[r_out * numpy.cos(-half_sweep), r_out * numpy.sin(-half_sweep)],
|
||||
[peak_out_x, 0.0],
|
||||
[peak_r * numpy.cos(-half_sweep/2), peak_r * numpy.sin(-half_sweep/2)],
|
||||
[peak_r * numpy.cos(half_sweep/2), peak_r * numpy.sin(half_sweep/2)],
|
||||
[r_out * numpy.cos(half_sweep), r_out * numpy.sin(half_sweep)],
|
||||
[r_in * numpy.cos(half_sweep), r_in * numpy.sin(half_sweep)],
|
||||
[r_in, 0.0]
|
||||
|
|
|
|||
|
|
@ -192,7 +192,10 @@ class PathFinder:
|
|||
# (Prevents failed paths from blocking others forever)
|
||||
if reached:
|
||||
for res in path:
|
||||
# Use the search geometry (could be proxy or arc) for indexing
|
||||
# to ensure consistency with what other nets use for their search.
|
||||
all_geoms.extend(res.geometry)
|
||||
|
||||
if res.dilated_geometry:
|
||||
all_dilated.extend(res.dilated_geometry)
|
||||
else:
|
||||
|
|
@ -206,12 +209,48 @@ class PathFinder:
|
|||
collision_count = 0
|
||||
# Always check for congestion to decide if more iterations are needed
|
||||
if reached:
|
||||
for i, poly in enumerate(all_geoms):
|
||||
overlaps = self.cost_evaluator.collision_engine.check_congestion(
|
||||
poly, net_id, dilated_geometry=all_dilated[i]
|
||||
)
|
||||
if overlaps > 0:
|
||||
collision_count += overlaps
|
||||
# For FINAL verification of this net's success, we should ideally
|
||||
# use high-fidelity geometry if available, but since Negotiated
|
||||
# Congestion relies on what is IN the index, we check the indexed geoms.
|
||||
# BUT, to fix the "false failed" issue where clipped_bbox overlaps
|
||||
# even if arcs don't, we should verify with actual_geometry.
|
||||
|
||||
verif_geoms = []
|
||||
verif_dilated = []
|
||||
for res in path:
|
||||
is_proxy = (res.actual_geometry is not None)
|
||||
g = res.actual_geometry if is_proxy else res.geometry
|
||||
verif_geoms.extend(g)
|
||||
|
||||
# If we are using actual_geometry as high-fidelity replacement for a proxy,
|
||||
# we MUST ensure we use the high-fidelity dilation too.
|
||||
if is_proxy:
|
||||
# ComponentResult stores dilated_geometry for the 'geometry' (proxy).
|
||||
# It does NOT store it for 'actual_geometry' unless we re-buffer.
|
||||
dilation = self.cost_evaluator.collision_engine.clearance / 2.0
|
||||
verif_dilated.extend([p.buffer(dilation) for p in g])
|
||||
else:
|
||||
# Use existing dilated geometry if it matches the current geom
|
||||
if res.dilated_geometry:
|
||||
verif_dilated.extend(res.dilated_geometry)
|
||||
else:
|
||||
dilation = self.cost_evaluator.collision_engine.clearance / 2.0
|
||||
verif_dilated.extend([p.buffer(dilation) for p in g])
|
||||
|
||||
for i, poly in enumerate(verif_geoms):
|
||||
# IMPORTANT: We check against OTHER nets.
|
||||
# If we just check self.check_congestion(poly, net_id),
|
||||
# it checks against the dynamic index which ALREADY contains this net's
|
||||
# path (added in step 3 above).
|
||||
# To correctly count REAL overlaps with others:
|
||||
self.cost_evaluator.collision_engine._ensure_dynamic_tree()
|
||||
if self.cost_evaluator.collision_engine.dynamic_tree:
|
||||
hits = self.cost_evaluator.collision_engine.dynamic_tree.query(verif_dilated[i], predicate='intersects')
|
||||
for hit_idx in hits:
|
||||
obj_id = self.cost_evaluator.collision_engine.dynamic_obj_ids[hit_idx]
|
||||
other_net_id, _ = self.cost_evaluator.collision_engine.dynamic_geometries[obj_id]
|
||||
if other_net_id != net_id:
|
||||
collision_count += 1
|
||||
|
||||
if collision_count > 0:
|
||||
any_congestion = True
|
||||
|
|
@ -259,14 +298,32 @@ class PathFinder:
|
|||
continue
|
||||
|
||||
collision_count = 0
|
||||
# Use high-fidelity verification against OTHER nets
|
||||
verif_geoms = []
|
||||
verif_dilated = []
|
||||
for comp in res.path:
|
||||
for i, poly in enumerate(comp.geometry):
|
||||
dil_poly = comp.dilated_geometry[i] if comp.dilated_geometry else None
|
||||
overlaps = self.cost_evaluator.collision_engine.check_collision(
|
||||
poly, net_id, buffer_mode='congestion', dilated_geometry=dil_poly
|
||||
)
|
||||
if isinstance(overlaps, int):
|
||||
collision_count += overlaps
|
||||
is_proxy = (comp.actual_geometry is not None)
|
||||
g = comp.actual_geometry if is_proxy else comp.geometry
|
||||
verif_geoms.extend(g)
|
||||
if is_proxy:
|
||||
dilation = self.cost_evaluator.collision_engine.clearance / 2.0
|
||||
verif_dilated.extend([p.buffer(dilation) for p in g])
|
||||
else:
|
||||
if comp.dilated_geometry:
|
||||
verif_dilated.extend(comp.dilated_geometry)
|
||||
else:
|
||||
dilation = self.cost_evaluator.collision_engine.clearance / 2.0
|
||||
verif_dilated.extend([p.buffer(dilation) for p in g])
|
||||
|
||||
self.cost_evaluator.collision_engine._ensure_dynamic_tree()
|
||||
if self.cost_evaluator.collision_engine.dynamic_tree:
|
||||
for i, poly in enumerate(verif_geoms):
|
||||
hits = self.cost_evaluator.collision_engine.dynamic_tree.query(verif_dilated[i], predicate='intersects')
|
||||
for hit_idx in hits:
|
||||
obj_id = self.cost_evaluator.collision_engine.dynamic_obj_ids[hit_idx]
|
||||
other_net_id, _ = self.cost_evaluator.collision_engine.dynamic_geometries[obj_id]
|
||||
if other_net_id != net_id:
|
||||
collision_count += 1
|
||||
|
||||
reached = False
|
||||
if res.path:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue