tiered bbox
This commit is contained in:
parent
c36bce9978
commit
9fac436c50
5 changed files with 45 additions and 15 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 65 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 40 KiB |
|
|
@ -64,7 +64,7 @@ class ComponentResult:
|
||||||
self.length = length
|
self.length = length
|
||||||
# Vectorized bounds calculation
|
# Vectorized bounds calculation
|
||||||
self.bounds = shapely.bounds(geometry)
|
self.bounds = shapely.bounds(geometry)
|
||||||
self.dilated_bounds = shapely.bounds(dilated_geometry) if dilated_geometry else None
|
self.dilated_bounds = shapely.bounds(dilated_geometry) if dilated_geometry is not None else None
|
||||||
|
|
||||||
def translate(self, dx: float, dy: float) -> ComponentResult:
|
def translate(self, dx: float, dy: float) -> ComponentResult:
|
||||||
"""
|
"""
|
||||||
|
|
@ -72,15 +72,16 @@ class ComponentResult:
|
||||||
"""
|
"""
|
||||||
# Vectorized translation if possible, else list comp
|
# Vectorized translation if possible, else list comp
|
||||||
# Shapely 2.x affinity functions still work on single geometries efficiently
|
# Shapely 2.x affinity functions still work on single geometries efficiently
|
||||||
geoms = self.geometry
|
geoms = list(self.geometry)
|
||||||
if self.dilated_geometry:
|
num_geom = len(self.geometry)
|
||||||
geoms = geoms + self.dilated_geometry
|
if self.dilated_geometry is not None:
|
||||||
|
geoms.extend(self.dilated_geometry)
|
||||||
|
|
||||||
from shapely.affinity import translate
|
from shapely.affinity import translate
|
||||||
translated = [translate(p, dx, dy) for p in geoms]
|
translated = [translate(p, dx, dy) for p in geoms]
|
||||||
|
|
||||||
new_geom = translated[:len(self.geometry)]
|
new_geom = translated[:num_geom]
|
||||||
new_dil = translated[len(self.geometry):] if self.dilated_geometry else None
|
new_dil = translated[num_geom:] if self.dilated_geometry is not None else None
|
||||||
|
|
||||||
new_port = Port(self.end_port.x + dx, self.end_port.y + dy, self.end_port.orientation)
|
new_port = Port(self.end_port.x + dx, self.end_port.y + dy, self.end_port.orientation)
|
||||||
return ComponentResult(new_geom, new_port, self.length, new_dil)
|
return ComponentResult(new_geom, new_port, self.length, new_dil)
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,7 @@ class AStarRouter:
|
||||||
target: Port,
|
target: Port,
|
||||||
net_width: float,
|
net_width: float,
|
||||||
net_id: str = 'default',
|
net_id: str = 'default',
|
||||||
|
bend_collision_type: Literal['arc', 'bbox', 'clipped_bbox'] | None = None,
|
||||||
) -> list[ComponentResult] | None:
|
) -> list[ComponentResult] | None:
|
||||||
"""
|
"""
|
||||||
Route a single net using A*.
|
Route a single net using A*.
|
||||||
|
|
@ -203,10 +204,14 @@ class AStarRouter:
|
||||||
target: Target port.
|
target: Target port.
|
||||||
net_width: Waveguide width (um).
|
net_width: Waveguide width (um).
|
||||||
net_id: Optional net identifier.
|
net_id: Optional net identifier.
|
||||||
|
bend_collision_type: Override collision model for this route.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of moves forming the path, or None if failed.
|
List of moves forming the path, or None if failed.
|
||||||
"""
|
"""
|
||||||
|
if bend_collision_type is not None:
|
||||||
|
self.config.bend_collision_type = bend_collision_type
|
||||||
|
|
||||||
self._collision_cache.clear()
|
self._collision_cache.clear()
|
||||||
open_set: list[AStarNode] = []
|
open_set: list[AStarNode] = []
|
||||||
# Key: (x, y, orientation) rounded to 1nm
|
# Key: (x, y, orientation) rounded to 1nm
|
||||||
|
|
@ -311,7 +316,9 @@ class AStarRouter:
|
||||||
res = self._move_cache[abs_key]
|
res = self._move_cache[abs_key]
|
||||||
else:
|
else:
|
||||||
# Level 2: Relative cache (orientation only)
|
# Level 2: Relative cache (orientation only)
|
||||||
rel_key = (base_ori, 'S', length, net_width, self._self_dilation)
|
# Dilation is now 0.0 for caching to save translation time.
|
||||||
|
# It will be calculated lazily in _add_node if needed.
|
||||||
|
rel_key = (base_ori, 'S', length, net_width, 0.0)
|
||||||
if rel_key in self._move_cache:
|
if rel_key in self._move_cache:
|
||||||
res_rel = self._move_cache[rel_key]
|
res_rel = self._move_cache[rel_key]
|
||||||
# Check closed set before translating
|
# Check closed set before translating
|
||||||
|
|
@ -322,7 +329,7 @@ class AStarRouter:
|
||||||
continue
|
continue
|
||||||
res = res_rel.translate(cp.x, cp.y)
|
res = res_rel.translate(cp.x, cp.y)
|
||||||
else:
|
else:
|
||||||
res_rel = Straight.generate(Port(0, 0, base_ori), length, net_width, dilation=self._self_dilation)
|
res_rel = Straight.generate(Port(0, 0, base_ori), length, net_width, dilation=0.0)
|
||||||
self._move_cache[rel_key] = res_rel
|
self._move_cache[rel_key] = res_rel
|
||||||
res = res_rel.translate(cp.x, cp.y)
|
res = res_rel.translate(cp.x, cp.y)
|
||||||
self._move_cache[abs_key] = res
|
self._move_cache[abs_key] = res
|
||||||
|
|
@ -335,7 +342,7 @@ class AStarRouter:
|
||||||
if abs_key in self._move_cache:
|
if abs_key in self._move_cache:
|
||||||
res = self._move_cache[abs_key]
|
res = self._move_cache[abs_key]
|
||||||
else:
|
else:
|
||||||
rel_key = (base_ori, 'B', radius, direction, net_width, self.config.bend_collision_type, self._self_dilation)
|
rel_key = (base_ori, 'B', radius, direction, net_width, self.config.bend_collision_type, 0.0)
|
||||||
if rel_key in self._move_cache:
|
if rel_key in self._move_cache:
|
||||||
res_rel = self._move_cache[rel_key]
|
res_rel = self._move_cache[rel_key]
|
||||||
# Check closed set before translating
|
# Check closed set before translating
|
||||||
|
|
@ -353,7 +360,7 @@ class AStarRouter:
|
||||||
direction,
|
direction,
|
||||||
collision_type=self.config.bend_collision_type,
|
collision_type=self.config.bend_collision_type,
|
||||||
clip_margin=self.config.bend_clip_margin,
|
clip_margin=self.config.bend_clip_margin,
|
||||||
dilation=self._self_dilation
|
dilation=0.0
|
||||||
)
|
)
|
||||||
self._move_cache[rel_key] = res_rel
|
self._move_cache[rel_key] = res_rel
|
||||||
res = res_rel.translate(cp.x, cp.y)
|
res = res_rel.translate(cp.x, cp.y)
|
||||||
|
|
@ -367,7 +374,7 @@ class AStarRouter:
|
||||||
if abs_key in self._move_cache:
|
if abs_key in self._move_cache:
|
||||||
res = self._move_cache[abs_key]
|
res = self._move_cache[abs_key]
|
||||||
else:
|
else:
|
||||||
rel_key = (base_ori, 'SB', offset, radius, net_width, self.config.bend_collision_type, self._self_dilation)
|
rel_key = (base_ori, 'SB', offset, radius, net_width, self.config.bend_collision_type, 0.0)
|
||||||
if rel_key in self._move_cache:
|
if rel_key in self._move_cache:
|
||||||
res_rel = self._move_cache[rel_key]
|
res_rel = self._move_cache[rel_key]
|
||||||
# Check closed set before translating
|
# Check closed set before translating
|
||||||
|
|
@ -386,7 +393,7 @@ class AStarRouter:
|
||||||
width=net_width,
|
width=net_width,
|
||||||
collision_type=self.config.bend_collision_type,
|
collision_type=self.config.bend_collision_type,
|
||||||
clip_margin=self.config.bend_clip_margin,
|
clip_margin=self.config.bend_clip_margin,
|
||||||
dilation=self._self_dilation
|
dilation=0.0
|
||||||
)
|
)
|
||||||
self._move_cache[rel_key] = res_rel
|
self._move_cache[rel_key] = res_rel
|
||||||
res = res_rel.translate(cp.x, cp.y)
|
res = res_rel.translate(cp.x, cp.y)
|
||||||
|
|
@ -424,9 +431,20 @@ class AStarRouter:
|
||||||
if self._collision_cache[cache_key]:
|
if self._collision_cache[cache_key]:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
# Lazy Dilation: compute dilated polygons only if we need a collision check
|
||||||
|
if result.dilated_geometry is None:
|
||||||
|
# We need to update the ComponentResult with dilated geometry
|
||||||
|
# For simplicity, we'll just buffer the polygons here.
|
||||||
|
# In a more optimized version, ComponentResult might have a .dilate() method.
|
||||||
|
dilated = [p.buffer(self._self_dilation) for p in result.geometry]
|
||||||
|
result.dilated_geometry = dilated
|
||||||
|
# Re-calculate dilated bounds
|
||||||
|
import shapely
|
||||||
|
result.dilated_bounds = shapely.bounds(dilated)
|
||||||
|
|
||||||
hard_coll = False
|
hard_coll = False
|
||||||
for i, poly in enumerate(result.geometry):
|
for i, poly in enumerate(result.geometry):
|
||||||
dil_poly = result.dilated_geometry[i] if result.dilated_geometry else None
|
dil_poly = result.dilated_geometry[i]
|
||||||
if self.cost_evaluator.collision_engine.check_collision(
|
if self.cost_evaluator.collision_engine.check_collision(
|
||||||
poly, net_id, buffer_mode='static', start_port=parent.port, end_port=result.end_port,
|
poly, net_id, buffer_mode='static', start_port=parent.port, end_port=result.end_port,
|
||||||
dilated_geometry=dil_poly
|
dilated_geometry=dil_poly
|
||||||
|
|
@ -437,6 +455,13 @@ class AStarRouter:
|
||||||
if hard_coll:
|
if hard_coll:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Lazy Dilation for self-intersection and cost evaluation
|
||||||
|
if result.dilated_geometry is None:
|
||||||
|
dilated = [p.buffer(self._self_dilation) for p in result.geometry]
|
||||||
|
result.dilated_geometry = dilated
|
||||||
|
import shapely
|
||||||
|
result.dilated_bounds = shapely.bounds(dilated)
|
||||||
|
|
||||||
# 3. Check for Self-Intersection (Limited to last 100 segments for performance)
|
# 3. Check for Self-Intersection (Limited to last 100 segments for performance)
|
||||||
if result.dilated_geometry:
|
if result.dilated_geometry:
|
||||||
# Union of current move's bounds for fast path-wide pruning
|
# Union of current move's bounds for fast path-wide pruning
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,13 @@ class PathFinder:
|
||||||
self.cost_evaluator.collision_engine.remove_path(net_id)
|
self.cost_evaluator.collision_engine.remove_path(net_id)
|
||||||
|
|
||||||
# 2. Reroute with current congestion info
|
# 2. Reroute with current congestion info
|
||||||
|
# Tiered Strategy: use clipped_bbox for Iteration 0 for speed.
|
||||||
|
# Switch to arc for higher iterations if collisions persist.
|
||||||
|
coll_model = "clipped_bbox" if iteration == 0 else "arc"
|
||||||
|
|
||||||
net_start = time.monotonic()
|
net_start = time.monotonic()
|
||||||
path = self.router.route(start, target, width, net_id=net_id)
|
path = self.router.route(start, target, width, net_id=net_id, bend_collision_type=coll_model)
|
||||||
logger.debug(f' Net {net_id} routed in {time.monotonic() - net_start:.4f}s')
|
logger.debug(f' Net {net_id} routed in {time.monotonic() - net_start:.4f}s using {coll_model}')
|
||||||
|
|
||||||
if path:
|
if path:
|
||||||
# 3. Add to index
|
# 3. Add to index
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue