first sparse steps

This commit is contained in:
Jan Petykiewicz 2026-03-13 20:13:05 -07:00
commit 24ca402f67
6 changed files with 139 additions and 12 deletions

View file

@ -245,3 +245,67 @@ class CollisionEngine:
if other_net_id != net_id and dynamic_prepared[obj_id].intersects(test_poly):
count += 1
return count
def ray_cast(self, origin: Port, angle_deg: float, max_dist: float = 2000.0) -> float:
"""
Cast a ray and find the distance to the nearest static obstacle.
Args:
origin: Starting port (x, y).
angle_deg: Ray direction in degrees.
max_dist: Maximum lookahead distance.
Returns:
Distance to first collision, or max_dist if clear.
"""
import numpy
from shapely.geometry import LineString
rad = numpy.radians(angle_deg)
dx = max_dist * numpy.cos(rad)
dy = max_dist * numpy.sin(rad)
# Ray geometry
ray_line = LineString([(origin.x, origin.y), (origin.x + dx, origin.y + dy)])
# 1. Query R-Tree
candidates = self.static_index.intersection(ray_line.bounds)
min_dist = max_dist
# 2. Check Intersections
# Note: We intersect with DILATED obstacles to account for clearance
for obj_id in candidates:
obstacle = self.static_dilated[obj_id]
# Fast check with prepared geom? intersects() is fast, intersection() gives point
if self.static_prepared[obj_id].intersects(ray_line):
# Calculate exact intersection distance
intersection = ray_line.intersection(obstacle)
if intersection.is_empty:
continue
# Intersection could be MultiLineString or LineString or Point
# We want the point closest to origin
# Helper to get dist
def get_dist(geom):
if hasattr(geom, 'geoms'): # Multi-part
return min(get_dist(g) for g in geom.geoms)
# For line string, the intersection is the segment INSIDE the obstacle.
# The distance is the distance to the start of that segment.
# Or if it's a touch (Point), distance to point.
coords = geom.coords
# Distance to the first point of the intersection geometry
# (Assuming simple overlap, first point is entry)
p1 = coords[0]
return numpy.sqrt((p1[0] - origin.x)**2 + (p1[1] - origin.y)**2)
try:
d = get_dist(intersection)
# Subtract safety margin to be safe? No, let higher level handle margins.
if d < min_dist:
min_dist = d
except Exception:
pass # Robustness
return min_dist