initial pass on examples

This commit is contained in:
Jan Petykiewicz 2026-03-08 14:40:36 -07:00
commit 82aaf066e2
19 changed files with 600 additions and 238 deletions

View file

@ -40,16 +40,9 @@ class CollisionEngine:
self.obstacle_geometries[obj_id] = polygon
self.prepared_obstacles[obj_id] = prep(polygon)
# Index the bounding box of the polygon (dilated for broad prune)
# Spec: "All user-provided obstacles are pre-dilated by (W_max + C)/2"
dilation = (self.max_net_width + self.clearance) / 2.0
dilated_bounds = (
polygon.bounds[0] - dilation,
polygon.bounds[1] - dilation,
polygon.bounds[2] + dilation,
polygon.bounds[3] + dilation,
)
self.static_obstacles.insert(obj_id, dilated_bounds)
# Index the bounding box of the original polygon
# We query with dilated moves, so original bounds are enough
self.static_obstacles.insert(obj_id, polygon.bounds)
def add_path(self, net_id: str, geometry: list[Polygon]) -> None:
"""Add a net's routed path to the dynamic R-Tree."""
@ -119,13 +112,13 @@ class CollisionEngine:
end_port: Port | None = None,
) -> bool:
"""Check if a pre-dilated geometry collides with static obstacles."""
# Broad prune with R-Tree
# Query R-Tree using the bounds of the dilated move
candidates = self.static_obstacles.intersection(dilated_geometry.bounds)
for obj_id in candidates:
# Use prepared geometry for fast intersection
if self.prepared_obstacles[obj_id].intersects(dilated_geometry):
# Check safety zone (2nm = 0.002 um)
# Check safety zone (2nm radius)
if start_port or end_port:
obstacle = self.obstacle_geometries[obj_id]
intersection = dilated_geometry.intersection(obstacle)
@ -133,20 +126,23 @@ class CollisionEngine:
if intersection.is_empty:
continue
# Create safety zone polygons
safety_zones = []
# Precise check: is every point in the intersection close to either port?
ix_minx, ix_miny, ix_maxx, ix_maxy = intersection.bounds
is_near_start = False
if start_port:
safety_zones.append(Point(start_port.x, start_port.y).buffer(0.002))
if (abs(ix_minx - start_port.x) < 0.0021 and abs(ix_maxx - start_port.x) < 0.0021 and
abs(ix_miny - start_port.y) < 0.0021 and abs(ix_maxy - start_port.y) < 0.0021):
is_near_start = True
is_near_end = False
if end_port:
safety_zones.append(Point(end_port.x, end_port.y).buffer(0.002))
if safety_zones:
safe_poly = unary_union(safety_zones)
# Remove safe zones from intersection
remaining_collision = intersection.difference(safe_poly)
if remaining_collision.is_empty or remaining_collision.area < 1e-9:
continue
if (abs(ix_minx - end_port.x) < 0.0021 and abs(ix_maxx - end_port.x) < 0.0021 and
abs(ix_miny - end_port.y) < 0.0021 and abs(ix_maxy - end_port.y) < 0.0021):
is_near_end = True
if is_near_start or is_near_end:
continue
return True
return False