Skip to content

Commit

Permalink
Merge pull request #194 from BerkeleyLearnVerify/fix-drivableRegion
Browse files Browse the repository at this point in the history
Fix drivable region
  • Loading branch information
dfremont authored Oct 9, 2023
2 parents 5337150 + 05b3589 commit 4bd4eb7
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 15 deletions.
15 changes: 10 additions & 5 deletions src/scenic/core/regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2643,10 +2643,14 @@ def difference(self, other):
@distributionFunction
def unionAll(regions, buf=0):
regions = tuple(regions)
if not all([r.z == regions[0].z for r in regions]):
raise ValueError(
"union of PolygonalRegions with different z values is undefined."
)
z = None
for reg in regions:
if z is not None and isinstance(reg, PolygonalRegion) and reg.z != z:
raise ValueError(
"union of PolygonalRegions with different z values is undefined."
)
if isinstance(reg, PolygonalRegion) and z is None:
z = reg.z

regs, polys = [], []
for reg in regions:
Expand All @@ -2659,7 +2663,8 @@ def unionAll(regions, buf=0):
raise TypeError(f"cannot take union of regions {regions}")
union = polygonUnion(polys, buf=buf)
orientation = VectorField.forUnionOf(regs, tolerance=buf)
return PolygonalRegion(polygon=union, orientation=orientation)
z = 0 if z is None else z
return PolygonalRegion(polygon=union, orientation=orientation, z=z)

@property
@distributionFunction
Expand Down
13 changes: 11 additions & 2 deletions src/scenic/domains/driving/roads.py
Original file line number Diff line number Diff line change
Expand Up @@ -923,10 +923,19 @@ def __attrs_post_init__(self):
self.shoulderRegion = PolygonalRegion.unionAll(self.shoulders)

if self.drivableRegion is None:
self.drivableRegion = self.laneRegion.union(self.intersectionRegion)
self.drivableRegion = PolygonalRegion.unionAll(
(
self.laneRegion,
self.roadRegion, # can contain points slightly outside laneRegion
self.intersectionRegion,
)
)
assert self.drivableRegion.containsRegion(
self.laneRegion, tolerance=self.tolerance
)
assert self.drivableRegion.containsRegion(
self.roadRegion, tolerance=self.tolerance
)
assert self.drivableRegion.containsRegion(
self.intersectionRegion, tolerance=self.tolerance
)
Expand Down Expand Up @@ -980,7 +989,7 @@ def _currentFormatVersion(cls):
:meta private:
"""
return 31
return 32

class DigestMismatchError(Exception):
"""Exception raised when loading a cached map not matching the original file."""
Expand Down
18 changes: 18 additions & 0 deletions tests/core/test_regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,24 @@ def test_polygon_region():
)


def test_polygon_unionAll():
poly1 = PolygonalRegion([(1, 0), (1, 1), (2, 1), (2, 0)], z=2)
poly2 = PolygonalRegion([(-1, 0), (-1, 1), (0, 1), (0, 0)], z=2)
union = PolygonalRegion.unionAll((poly1, nowhere, poly2))
assert isinstance(union, PolygonalRegion)
assert union.z == 2
assert union.containsPoint((1.5, 0.5))
assert union.containsPoint((-0.5, 0.5))
assert not union.containsPoint((0.5, 0.5))

poly3 = PolygonalRegion([(0, 0), (1, 1), (1, 0)], z=1)
with pytest.raises(ValueError):
PolygonalRegion.unionAll((poly1, poly3))

with pytest.raises(TypeError):
PolygonalRegion.unionAll((poly1, everywhere))


def test_polygon_sampling():
p = shapely.geometry.Polygon(
[(0, 0), (0, 3), (3, 3), (3, 0)], holes=[[(1, 1), (1, 2), (2, 2), (2, 1)]]
Expand Down
18 changes: 10 additions & 8 deletions tests/domains/driving/test_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,22 @@ def test_element_tolerance(cached_maps, pytestconfig):
tol = 0.05
network = Network.fromFile(path, tolerance=tol)
drivable = network.drivableRegion
toofar = drivable.buffer(2 * tol).difference(drivable.buffer(1.5 * tol))
toofar_noint = toofar.difference(network.intersectionRegion)
road = network.roads[0]
nearby = road.buffer(tol).difference(road)
rounds = 1 if pytestconfig.getoption("--fast") else 20
rounds = 30 if pytestconfig.getoption("--fast") else 300
for i in range(rounds):
pt = None
while not pt or pt in drivable:
pt = nearby.uniformPointInner()
assert network.elementAt(pt) is not None
assert network.roadAt(pt) is not None
toofar = drivable.buffer(2 * tol).difference(drivable.buffer(1.5 * tol))
pt = toofar.uniformPointInner()
assert network.roadAt(pt) is None
with pytest.raises(RejectionException):
network.roadAt(pt, reject=True)
toofar = toofar.difference(network.intersectionRegion)
pt = toofar.uniformPointInner()
pt = toofar_noint.uniformPointInner()
assert network.elementAt(pt) is None
assert not network.nominalDirectionsAt(pt)

Expand Down Expand Up @@ -137,8 +137,9 @@ def checkGroup(group):
assert section.group is group
assert section.road is road
assert section.isForward == (group is road.forwardLanes)
pt = section.uniformPointInner()
assert lane.sectionAt(pt) is section
for i in range(30):
pt = section.uniformPointInner()
assert lane.sectionAt(pt) is section
fastSlow = (section._fasterLane, section._slowerLane)
leftRight = (section._laneToLeft, section._laneToRight)
if section._fasterLane:
Expand Down Expand Up @@ -179,8 +180,9 @@ def checkGroup(group):
section.laneToRight
for maneuver in lane.maneuvers:
assert maneuver.startLane is lane
pt = lane.uniformPointInner()
assert group.laneAt(pt) is lane
for i in range(30):
pt = lane.uniformPointInner()
assert group.laneAt(pt) is lane

if road.forwardLanes:
checkGroup(road.forwardLanes)
Expand Down

0 comments on commit 4bd4eb7

Please sign in to comment.