Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 docs/notebooks/tutorial_projections.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
" \"../../example_files/alks_cut-in.osi\", map_path=\"../../example_files/straight_500m.xodr\"\n",
")\n",
"df = r._df\n",
"print(df.select([\"total_nanos\", \"idx\", \"x\", \"y\"]).head())\n"
"print(df.select([\"total_nanos\", \"idx\", \"x\", \"y\"]).head())"
]
},
{
Expand Down
48 changes: 27 additions & 21 deletions omega_prime/maposicenterlinesegmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,12 @@ def init_intersections(self):
self.set_intersection_idx()

if self.do_combine_intersections:
self.create_lane_segment_dict()
self.add_non_intersecting_lanes_to_intersection()
self.combine_intersections()
self.set_intersection_idx()
self.create_intersection_dict()

self.create_intersection_dict()
self.create_lane_segment_dict()
self.find_isolated_connections()
self.create_lane_segment_dict()
Expand Down Expand Up @@ -645,41 +646,46 @@ def find_isolated_connections(self):
isolated_connections (list): A list of lists, where each inner list contains the indices of lanes that are part of an isolated connection.
"""
G = self.create_non_intersecting_lane_graph()
isolated_connections = []
new_connections = []
segment_name_type = type(next(iter(self.lane_segment_dict.values())))

Comment on lines 648 to +651
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

segment_name_type = type(next(iter(self.lane_segment_dict.values()))) will raise StopIteration when lane_segment_dict is empty (e.g., recordings/maps with zero lanes). Consider deriving the SegmentName type without iterating values (e.g., define it once at class/init level and reuse), or guard with an early return when self.lane_segment_dict is empty.

Copilot uses AI. Check for mistakes.
# Classify each component before constructing ConnectionSegment objects.
for component in nx.connected_components(G):
if len(component) > 0:
isolated_connections.append(
ConnectionSegment(
[self.lane_dict[i] for i in component], concave_hull_ratio=self.concave_hull_ratio
)
)
# Check if any of the lanes in the isolated connections are part of an intersection
for connection in isolated_connections:
if not component:
continue

component_ids = list(component)
pre = False
suc = False
for lane_id in connection.lane_ids:
# Check if the lane has a predecessor or successor that is part of an intersection
intersection_idxs = set()

for lane_id in component_ids:
for successor in self.lane_successors_dict[lane_id]:
if successor in self.lane_segment_dict and self.lane_segment_dict[successor].segment is not None:
connection.intersection_idxs.add(self.lane_segment_dict[successor].segment_idx)
intersection_idxs.add(self.lane_segment_dict[successor].segment_idx)
suc = True
for predecessor in self.lane_predecessors_dict[lane_id]:
if (
predecessor in self.lane_segment_dict
and self.lane_segment_dict[predecessor].segment is not None
):
connection.intersection_idxs.add(self.lane_segment_dict[predecessor].segment_idx)
intersection_idxs.add(self.lane_segment_dict[predecessor].segment_idx)
pre = True

if len(connection.intersection_idxs) == 1 and pre and suc:
# There is a predecessor and a successor that are part of an intersection so the connection is part of the intersection:
# Add all the lanes to the intersection:
for lane_id in connection.lane_ids:
self.intersection_dict[list(connection.intersection_idxs)[0]].lanes.append(self.lane_dict[lane_id])
self.intersection_dict[list(connection.intersection_idxs)[0]].lane_ids.append(lane_id)
self.intersection_dict[list(connection.intersection_idxs)[0]].update_polygon()
if len(intersection_idxs) == 1 and pre and suc:
# Single bordering intersection on both ends: absorb the component into it.
inter = self.intersection_dict[list(intersection_idxs)[0]]
for lane_id in component_ids:
inter.lanes.append(self.lane_dict[lane_id])
inter.lane_ids.append(lane_id)
# Keep lane_segment_dict current so subsequent components see these lanes as already assigned.
self.lane_segment_dict[lane_id] = segment_name_type(lane_id, inter.idx, inter)
inter.update_polygon()
else:
connection = ConnectionSegment(
[self.lane_dict[i] for i in component_ids], concave_hull_ratio=self.concave_hull_ratio
)
connection.intersection_idxs = intersection_idxs
new_connections.append(connection)

isolated_connections = new_connections
Expand Down
7 changes: 5 additions & 2 deletions omega_prime/mapsegment.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ def _compute_polygon_key(self):

def _compute_segment_polygon(self):
lane_centerline = [self._get_lane_geometry(lane) for lane in self.lanes]
multilinestring = shapely.MultiLineString(lane_centerline).buffer(0.1)
combined = shapely.unary_union(multilinestring).buffer(0.1)

multi_centerline = shapely.geometry.MultiLineString(lane_centerline)
combined = multi_centerline.buffer(0.1)
combined = combined.simplify(0.1, preserve_topology=True)

try:
hull = shapely.concave_hull(combined, self.concave_hull_ratio)
assert not hull.is_empty
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ dependencies = [
'tqdm_joblib',
'filelock>=3.18.0'
]
version = "0.2.2"
version = "0.3.0"

[project.urls]
Homepage = "https://github.com/ika-rwth-aachen/omega-prime"
Expand Down
Loading
Loading