Skip to content
Open
Show file tree
Hide file tree
Changes from 92 commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
ecc2593
Update xodr_parser.py
ethan10mak Apr 16, 2025
a81d32e
Added parse_elevation_profile code
ethan10mak Apr 17, 2025
c725df9
elevationProfile and lateralProfile parsing implementation
ethan10mak Apr 17, 2025
440190f
Changed cur_p to have three dimensions
ethan10mak Apr 17, 2025
72a31f2
Formatted xodr_parser.py
ethan10mak Apr 17, 2025
b97d800
Revert "Formatted xodr_parser.py"
ethan10mak Apr 17, 2025
2726f2a
Updated formatting of xodr_parser.py
ethan10mak Apr 17, 2025
565534f
Added get_super_elevation_at function
ethan10mak Apr 21, 2025
926a04d
Update xodr_parser.py
ethan10mak Apr 23, 2025
fb9be18
Updated parser, regions, and geometry to account for elevation
ethan10mak Apr 25, 2025
4110851
Updating xodr_parser
ethan10mak Apr 30, 2025
c800655
Modifying xodr_parser to accept 3D and create trimeshes
ethan10mak Apr 30, 2025
d3def9b
Updating calculate_geometry and toScenicRoad to 3D
ethan10mak May 2, 2025
3e1e2ae
Visualized working meshes
ethan10mak May 16, 2025
d0c5bcb
Updated NetworkElement to Region
ethan10mak May 19, 2025
6e8fa25
3D meshes outputs properly
ethan10mak Jun 11, 2025
ddb093b
Updated roads.py
ethan10mak Jul 2, 2025
727cca7
Updated findPointIn Function
ethan10mak Jul 4, 2025
65206ae
updated global param use2DMap
ethan10mak Jul 7, 2025
203df0a
Updating use2DMap param
ethan10mak Jul 9, 2025
c62dbf1
Updated abstract function and orientation
ethan10mak Jul 11, 2025
affc938
Updated abstract classes
ethan10mak Jul 17, 2025
80261cc
Driving Orientation Fixed and 2D Compatibility
ethan10mak Jul 21, 2025
d0361d3
Updated 2D Compatibility
ethan10mak Jul 23, 2025
91ab3a3
Updated documentation
ethan10mak Jul 30, 2025
54a9695
Added __getitem__ to PathRegion
ethan10mak Aug 1, 2025
8b725c8
Updated behaviors.py for 3d concatenateCenterlines
ethan10mak Aug 4, 2025
1a883ed
Updated xodr_parser.py
ethan10mak Aug 4, 2025
630e41e
Updated behavior.scenic
ethan10mak Aug 5, 2025
5b2db24
Added signedDistanceTo() to PathRegion
ethan10mak Aug 5, 2025
c743be1
Updated curbRegion
ethan10mak Aug 5, 2025
f06e7f0
Updated for optimized region usage.
ethan10mak Aug 12, 2025
c62004f
Intersection are generated correctly
ethan10mak Aug 14, 2025
c2ed809
Fixed problems with orientation
ethan10mak Aug 15, 2025
ce75a75
Updated Test
ethan10mak Aug 21, 2025
024e684
Squashed commit of the following:
ethan10mak Aug 21, 2025
e83ca26
Cleaned up example files
ethan10mak Aug 21, 2025
a24d283
Elements are no longer ignored when in between other elements
ethan10mak Aug 25, 2025
96e793b
Update xodr_parser.py
ethan10mak Aug 25, 2025
98db427
Updated carla\simulator.py
ethan10mak Aug 26, 2025
9c5839c
Updated carla simulator code
ethan10mak Aug 27, 2025
6de7b17
Formatted files
ethan10mak Aug 28, 2025
15f51b3
Update roads.py
ethan10mak Aug 28, 2025
4284ef5
Update roads.py
ethan10mak Aug 28, 2025
f5f916d
Updated Carla simulator
ethan10mak Aug 28, 2025
51dd121
Update xodr_parser.py
ethan10mak Aug 28, 2025
1ed86ad
Update xodr_parser.py
ethan10mak Sep 3, 2025
80cd8aa
Update test_driving.py
ethan10mak Sep 4, 2025
4b5b863
Cleaned comments
ethan10mak Sep 4, 2025
50b0372
Cleaned files
ethan10mak Sep 4, 2025
4b4fded
Cleaned files
ethan10mak Sep 4, 2025
25869e3
Updated requirements.py
ethan10mak Sep 5, 2025
c5b2619
Update requirements.py
ethan10mak Sep 5, 2025
0b5cda5
Updated requirements.py
ethan10mak Sep 5, 2025
63df5fc
Modified 2d tests
ethan10mak Sep 5, 2025
598a16c
Cleaned file
ethan10mak Sep 5, 2025
dbfd5de
Updated tests
ethan10mak Sep 5, 2025
f207259
Formatted file
ethan10mak Sep 5, 2025
35a3946
Revert "Squashed commit of the following:"
ethan10mak Sep 10, 2025
84280fa
Merge branch 'main' into 3d-driving
ethan10mak Sep 10, 2025
42e390b
Updated Test Cases, Network Element, and Network
ethan10mak Sep 10, 2025
1a8c5be
Formatted Files
ethan10mak Sep 10, 2025
92519a9
Reverted test files and updated roads with asserts
ethan10mak Sep 11, 2025
e40b2fc
Updated xodr_parser.py with orientation fix to curbs
ethan10mak Sep 11, 2025
4e64db1
Updated normal vector calculation in xodr_parser
ethan10mak Sep 11, 2025
f57424b
Updated asserts
ethan10mak Sep 11, 2025
6491e1d
Formatted roads.py
ethan10mak Sep 11, 2025
a55edc1
Reverted UnionRegion containsObject
ethan10mak Sep 11, 2025
66da7a0
Formatted files
ethan10mak Sep 11, 2025
35fb40f
Added union for MeshSurfaceRegion
ethan10mak Sep 16, 2025
65d4a31
Updated Assertions for roads.py
ethan10mak Sep 16, 2025
360d179
Added assertions to roads.py
ethan10mak Sep 16, 2025
9e7407b
Updated asserts and changed conftest.py to use fixture module
ethan10mak Sep 17, 2025
b9b7bf6
Created boundingPolygon for PolygonalRegion
ethan10mak Sep 18, 2025
2a2385c
Updated Assertions for roads.py
ethan10mak Sep 19, 2025
1304d95
Added intersects function to PathRegion
ethan10mak Sep 20, 2025
5e95b4f
Added fix to NetworkElement intersects and added fix to test_show2D
ethan10mak Sep 20, 2025
000cabc
Reverted conftest from session to module
ethan10mak Sep 20, 2025
7d10e0a
Updated Tests
ethan10mak Sep 20, 2025
5b031b4
Updated 3D tests, MeshSurfaceRegion, and asserts in roads.py
ethan10mak Sep 26, 2025
b8f9cb1
Formatted Files
ethan10mak Sep 27, 2025
6dde3f5
Updated findElementWithin
ethan10mak Sep 27, 2025
1193d4b
Fixed issue with not returning the correct maneuvers for intersections
ethan10mak Sep 30, 2025
46cbc7b
Fixed formatting issue
ethan10mak Sep 30, 2025
3eb2381
Updated containRegionInner for MeshSurfaceRegions
ethan10mak Oct 3, 2025
c97b7f6
Updated default tolerance
ethan10mak Oct 3, 2025
df19049
Updated tolerance for test_element_tolerance
ethan10mak Oct 3, 2025
f6c2c05
Created new tests specific to 3D elements
ethan10mak Oct 9, 2025
fc5043a
Formatted test_driving.py
ethan10mak Oct 9, 2025
bc32686
Update roads.py
ethan10mak Oct 9, 2025
8906ebc
Updated tests
ethan10mak Oct 14, 2025
6fb8419
Formatted test_network.py
ethan10mak Oct 14, 2025
fb6ac3b
Update src/scenic/core/regions.py
ethan10mak Oct 23, 2025
ae22d3a
Removed unnecessary parameters from tests
ethan10mak Oct 23, 2025
494eece
Merge branch '3d-driving' of https://github.com/BerkeleyLearnVerify/S…
ethan10mak Oct 23, 2025
c47a2dd
Updated test_driving.py
ethan10mak Oct 23, 2025
9e779a4
Update model.scenic
ethan10mak Nov 22, 2025
440c883
Update test_basic.py
ethan10mak Dec 3, 2025
2bbd534
Update test_basic.py
ethan10mak Dec 3, 2025
868e10a
Formatted files
ethan10mak Dec 4, 2025
06e9da5
Updated carla tests with 3D tests
ethan10mak Dec 9, 2025
d3a9d09
Formatted files
ethan10mak Dec 10, 2025
e343921
Update 3D driving CARLA tests
ethan10mak Dec 12, 2025
30d26d9
Changed test_brake back to Town01
ethan10mak Dec 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/driving/car.scenic
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ param map = localPath('../../assets/maps/CARLA/Town01.xodr')

model scenic.domains.driving.model

ego = new Car
ego = new Car
5 changes: 4 additions & 1 deletion src/scenic/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,10 @@ def runSimulation(scene, sceneCount):
successCount += 1
else:
successCount += 1
if mode2D:
use2DMap = getattr(
getattr(scene.workspace, "network", None), "use2DMap", False
)
if use2DMap:
if delay is None:
scene.show2D(zoom=args.zoom)
else:
Expand Down
92 changes: 80 additions & 12 deletions src/scenic/core/regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ def evaluateInner(self, context):
def containsPoint(self, point):
return any(region.containsPoint(point) for region in self.footprint.regions)

# TODO: Need to implement this
def containsObject(self, obj):
raise NotImplementedError

Expand Down Expand Up @@ -2041,6 +2042,33 @@ def intersects(self, other, triedReversed=False):

return super().intersects(other, triedReversed)

def union(self, other, triedReversed=False):
"""Get a `Region` representing the union of this region with another.

This function handles union computation for `MeshSurfaceRegion` with:
- `MeshSurfaceRegion`
"""
# If one of the regions isn't fixed, fall back on default behavior
if isLazy(self) or isLazy(other):
return super().union(other, triedReversed)

# If other region is represented by a mesh, we can extract the mesh to
# perform boolean operations on it
if isinstance(other, MeshSurfaceRegion):
other_mesh = other.mesh

# Compute union using Trimesh
new_mesh = trimesh.util.concatenate(self.mesh, other_mesh)

return MeshSurfaceRegion(
new_mesh,
tolerance=min(self.tolerance, other.tolerance),
centerMesh=False,
)

# Don't know how to compute this union, fall back to default behavior.
return super().union(other, triedReversed)

@distributionFunction
def containsPoint(self, point):
"""Check if this region's surface contains a point."""
Expand All @@ -2052,18 +2080,18 @@ def containsPoint(self, point):

def containsObject(self, obj):
# A surface cannot contain an object, which must have a volume.
return False
# Use footprint
return self.boundingPolygon.containsObject(obj)

def containsRegionInner(self, reg, tolerance):
if tolerance != 0:
warnings.warn(
"Nonzero tolerances are ignored for containsRegionInner on MeshSurfaceRegion"
)

if isinstance(reg, MeshSurfaceRegion):
diff_region = reg.difference(self)

return isinstance(diff_region, EmptyRegion)
if self.mesh.is_empty:
return False
elif reg.mesh.is_empty:
return True
return self.boundingPolygon.polygons.buffer(tolerance).contains(
reg.boundingPolygon.polygons
)

raise NotImplementedError

Expand All @@ -2076,9 +2104,7 @@ def distanceTo(self, point):
point = toVector(point, f"Could not convert {point} to vector.")

pq = trimesh.proximity.ProximityQuery(self.mesh)

dist = abs(pq.signed_distance([point.coordinates])[0])

return dist

@property
Expand Down Expand Up @@ -2767,11 +2793,22 @@ def __init__(
numpy.linalg.norm(b - a, axis=1), (len(a), 1)
)

def intersects(self, other, triedReversed=False):
if isinstance(other, PathRegion):
self_polyline = PolylineRegion(points=[(v.x, v.y) for v in self.vertices])
other_polyline = PolylineRegion(points=[(v.x, v.y) for v in other.vertices])
poly = toPolygon(other_polyline)
if poly is not None:
return self_polyline.lineString.intersects(poly)
return self_polyline.intersects(other, triedReversed)
else:
return super().intersects(other, triedReversed)

def containsPoint(self, point):
return self.distanceTo(point) < self.tolerance

def containsObject(self, obj):
return False
raise NotImplementedError

def containsRegionInner(self, reg, tolerance):
raise NotImplementedError
Expand Down Expand Up @@ -2820,6 +2857,27 @@ def AABB(self):
tuple(numpy.amax(self.vertices, axis=0)),
)

@distributionMethod
def signedDistanceTo(self, point) -> float:
"""Compute the signed distance of the PathRegion to a point.

The distance is positive if the point is left of the nearest segment,
and negative otherwise.
"""
dist = self.distanceTo(point)
start, end = self.nearestSegmentTo(point)
rp = point - start
tangent = end - start
return dist if tangent.angleWith(rp) >= 0 else -dist

def __getitem__(self, i) -> Vector:
"""Get the ith point along this path.

If the region consists of multiple polylines, this order is linear
along each polyline but arbitrary across different polylines.
"""
return self.vertices[i]

def uniformPointInner(self):
# Pick an edge, weighted by length, and extract its two points
edge = random.choices(population=self.edges, weights=self.edge_lengths, k=1)[0]
Expand Down Expand Up @@ -3080,6 +3138,16 @@ def unionAll(regions, buf=0):
z = 0 if z is None else z
return PolygonalRegion(polygon=union, orientation=orientation, z=z)

@cached_property
def _boundingPolygon(self):
return self._polygon

@cached_property
@distributionFunction
def boundingPolygon(self):
"""A PolygonalRegion returning self"""
return self

@property
@distributionFunction
def points(self):
Expand Down
1 change: 1 addition & 0 deletions src/scenic/core/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from scenic.core.errors import InvalidScenarioError
from scenic.core.lazy_eval import needsLazyEvaluation
from scenic.core.propositions import Atomic, PropositionNode
from scenic.core.regions import MeshSurfaceRegion, PolygonalRegion
import scenic.syntax.relations as relations


Expand Down
2 changes: 1 addition & 1 deletion src/scenic/domains/driving/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Domain for driving scenarios.

This domain must currently be used in `2D compatibility mode`.
This domain supports both 2D and 3D maps. This can be toggled by setting the `2D Compatibility mode` option.

The :doc:`world model <scenic.domains.driving.model>` defines Scenic classes for cars,
pedestrians, etc., actions for dynamic agents which walk or drive, as well as simple
Expand Down
11 changes: 6 additions & 5 deletions src/scenic/domains/driving/behaviors.scenic
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import scenic.domains.driving.model as _model
from scenic.domains.driving.roads import ManeuverType

def concatenateCenterlines(centerlines=[]):
return PolylineRegion.unionAll(centerlines)
if isinstance(centerlines[0], PathRegion):
return PathRegion(polylines=centerlines)
else:
return PolylineRegion.unionAll(centerlines)

behavior ConstantThrottleBehavior(x):
while True:
Expand Down Expand Up @@ -131,9 +134,7 @@ behavior FollowLaneBehavior(target_speed = 10, laneToFollow=None, is_oppositeTra
target_speed = original_target_speed
_lon_controller, _lat_controller = simulation().getLaneFollowingControllers(self)

nearest_line_points = current_centerline.nearestSegmentTo(self.position)
nearest_line_segment = PolylineRegion(nearest_line_points)
cte = nearest_line_segment.signedDistanceTo(self.position)
cte = current_centerline.signedDistanceTo(self.position)
if is_oppositeTraffic:
cte = -cte

Expand Down Expand Up @@ -213,7 +214,7 @@ behavior TurnBehavior(trajectory, target_speed=6):
it will terminate if the vehicle is outside of an intersection.
"""

if isinstance(trajectory, PolylineRegion):
if isinstance(trajectory, PolylineRegion) or isinstance(trajectory, PathRegion):
trajectory_centerline = trajectory
else:
trajectory_centerline = concatenateCenterlines([traj.centerline for traj in trajectory])
Expand Down
32 changes: 17 additions & 15 deletions src/scenic/domains/driving/model.scenic
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ If you are writing a generic scenario that supports multiple maps, you may leave
``map`` parameter undefined; then running the scenario will produce an error unless the
user uses the :option:`--param` command-line option to specify the map.

The ``use2DMap`` global parameter determines whether or not maps are generated in 2D. Currently
3D maps are not supported, but are under development. By default, this parameter is `False`
(so that future versions of Scenic will automatically use 3D maps), unless
:ref:`2D compatibility mode` is enabled, in which case the default is `True`. The parameter
can be manually set to `True` to ensure 2D maps are used even if the scenario is not compiled
in 2D compatibility mode.
Both 2D and 3D road networkd are now fully supported. The ``use2DMap`` global parameter
determines whether or not maps are generated in 2D or 3D. By default, this parameter is
`False` (so that 3D maps are used by default), unless :ref:`2D compatibility mode` is enabled,
in which case the default is `True`. The parameter can be manually set to `True` to ensure 2D
maps are used even if the scenario is not compiled in 2D compatibility mode.

.. note::

3D road network support is now fully implemented. When ``use2DMap`` is `False`, road
geometry, object placement, and region queries will use full 3D coordinates, including
elevation (Z) values. This allows for more realistic scenarios with varying terrain
heights and complex road structures.


.. note::
Expand Down Expand Up @@ -57,21 +63,16 @@ param use2DMap = True if is2DMode() else False
if is2DMode() and not globalParameters.use2DMap:
raise RuntimeError('in 2D mode, global parameter "use2DMap" must be True')

# Note: The following should be removed when 3D maps are supported
if not globalParameters.use2DMap:
raise RuntimeError('3D maps not supported at this time.'
'(to use 2D maps set global parameter "use2DMap" to True)')

## Load map and set up workspace

if 'map' not in globalParameters:
raise RuntimeError('need to specify map before importing driving model '
'(set the global parameter "map")')
param map_options = {}

options = {**globalParameters.map_options, "use2DMap": globalParameters.use2DMap}
#: The road network being used for the scenario, as a `Network` object.
network : Network = Network.fromFile(globalParameters.map, **globalParameters.map_options)

#network : Network = Network.fromFile(globalParameters.map, **globalParameters.map_options)
network : Network = Network.fromFile(globalParameters.map, **options)
workspace = DrivingWorkspace(network)

## Various useful objects and regions
Expand Down Expand Up @@ -282,13 +283,14 @@ class Vehicle(DrivingObject):
distribution derived from car color popularity statistics; see
:obj:`Color.defaultCarColor`.
"""
regionContainedIn: roadOrShoulder
regionContainedIn: roadOrShoulder.boundingPolygon # Change region to bounding polygon region
position: new Point on road
parentOrientation: (roadDirection at self.position) + self.roadDeviation
roadDeviation: 0
viewAngle: 90 deg
width: 2
length: 4.5
height: 2.5 # default height;
color: Color.defaultCarColor()

@property
Expand Down
Loading
Loading