Module scenariogeneration.xodr.lane_def
scenariogeneration https://github.com/pyoscx/scenariogeneration
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
Copyright (c) 2022 The scenariogeneration Authors.
This is a collection methods and classes not related to OpenDRIVE, but relates to automation of lane creations
Functions
def create_lanes_merge_split(right_lane_def,
left_lane_def,
road_length,
center_road_mark,
lane_width,
lane_width_end)-
Expand source code
def create_lanes_merge_split( right_lane_def, left_lane_def, road_length, center_road_mark, lane_width, lane_width_end, ): """create_lanes_merge_split is a generator that will create the Lanes of a road road that can contain one or more lane merges/splits This is a simple implementation and has some constraints: - left and right merges has to be at the same place (or one per lane), TODO: will be fixed with the singleSide attribute later on. - the change will be a 3 degree polynomial with the derivative 0 on both start and end. Please note that the merges/splits are defined in the road direction, NOT the driving direction. Parameters ---------- right_lane_def (list of LaneDef, or an int): a list of the splits/merges that are wanted on the right side of the road, if int constant number of lanes left_lane_def (list of LaneDef, or an int): a list of the splits/merges that are wanted on the left side of the road, if int constant number of lanes. road_length (float): the full length of the road center_road_mark (RoadMark): roadmark for the center line lane_width (float): the width of the lanes lane_width_end (float): the end width of the lanes Return ------ road (Lanes): the lanes of a road """ lanesections = [] # expand the lane list right_lane, left_lane = _create_lane_lists( right_lane_def, left_lane_def, road_length, lane_width ) # create the lanesections needed for ls in range(len(left_lane)): lc = Lane(a=0) lc.add_roadmark(copy.deepcopy(center_road_mark)) lsec = LaneSection(left_lane[ls].s_start, lc) # do the right lanes for i in range(max(right_lane[ls].n_lanes_start, right_lane[ls].n_lanes_end)): # add broken roadmarks for all lanes, except for the outer lane where a solid line is added if i == max(right_lane[ls].n_lanes_start, right_lane[ls].n_lanes_end) - 1: rm = std_roadmark_solid() else: rm = std_roadmark_broken() # check if the number of lanes should change or not if ( right_lane[ls].n_lanes_start > right_lane[ls].n_lanes_end and i == np.abs(right_lane[ls].sub_lane) - 1 ): # lane merge coeff = get_coeffs_for_poly3( right_lane[ls].s_end - right_lane[ls].s_start, right_lane[ls].lane_start_widths[i], False, right_lane[ls].lane_end_widths[i], ) rightlane = Lane(a=coeff[0], b=coeff[1], c=coeff[2], d=coeff[3]) rightlane.add_roadmark(rm) elif ( right_lane[ls].n_lanes_start < right_lane[ls].n_lanes_end and i == np.abs(right_lane[ls].sub_lane) - 1 ): # lane split coeff = get_coeffs_for_poly3( right_lane[ls].s_end - right_lane[ls].s_start, right_lane[ls].lane_start_widths[i], True, right_lane[ls].lane_end_widths[i], ) rightlane = Lane(a=coeff[0], b=coeff[1], c=coeff[2], d=coeff[3]) rightlane.add_roadmark(rm) elif (lane_width_end is not None) and (lane_width != lane_width_end): coeff = get_coeffs_for_poly3( right_lane[ls].s_end - right_lane[ls].s_start, lane_width, False, lane_width_end=lane_width_end, ) rightlane = Lane(a=coeff[0], b=coeff[1], c=coeff[2], d=coeff[3]) rightlane.add_roadmark(rm) elif right_lane[ls].lane_start_widths: coeff = get_coeffs_for_poly3( right_lane[ls].s_end - right_lane[ls].s_start, right_lane[ls].lane_start_widths[i], False, lane_width_end=right_lane[ls].lane_end_widths[i], ) rightlane = Lane(a=coeff[0], b=coeff[1], c=coeff[2], d=coeff[3]) rightlane.add_roadmark(rm) else: rightlane = Lane(lane_width) rightlane.add_roadmark(rm) lsec.add_right_lane(rightlane) # do the left lanes for i in range(max(left_lane[ls].n_lanes_start, left_lane[ls].n_lanes_end)): # add broken roadmarks for all lanes, except for the outer lane where a solid line is added if i == max(left_lane[ls].n_lanes_start, left_lane[ls].n_lanes_end) - 1: rm = std_roadmark_solid() else: rm = std_roadmark_broken() # check if the number of lanes should change or not if ( left_lane[ls].n_lanes_start < left_lane[ls].n_lanes_end and i == left_lane[ls].sub_lane - 1 ): # lane split coeff = get_coeffs_for_poly3( left_lane[ls].s_end - left_lane[ls].s_start, left_lane[ls].lane_start_widths[i], True, left_lane[ls].lane_end_widths[i], ) leftlane = Lane(a=coeff[0], b=coeff[1], c=coeff[2], d=coeff[3]) leftlane.add_roadmark(rm) elif ( left_lane[ls].n_lanes_start > left_lane[ls].n_lanes_end and i == left_lane[ls].sub_lane - 1 ): # lane merge coeff = get_coeffs_for_poly3( left_lane[ls].s_end - left_lane[ls].s_start, left_lane[ls].lane_start_widths[i], False, left_lane[ls].lane_end_widths[i], ) leftlane = Lane(a=coeff[0], b=coeff[1], c=coeff[2], d=coeff[3]) leftlane.add_roadmark(rm) elif (lane_width_end is not None) and (lane_width != lane_width_end): coeff = get_coeffs_for_poly3( left_lane[ls].s_end - left_lane[ls].s_start, lane_width, False, lane_width_end=lane_width_end, ) leftlane = Lane(a=coeff[0], b=coeff[1], c=coeff[2], d=coeff[3]) leftlane.add_roadmark(rm) elif left_lane[ls].lane_start_widths: coeff = get_coeffs_for_poly3( left_lane[ls].s_end - left_lane[ls].s_start, left_lane[ls].lane_start_widths[i], False, lane_width_end=left_lane[ls].lane_end_widths[i], ) leftlane = Lane(a=coeff[0], b=coeff[1], c=coeff[2], d=coeff[3]) leftlane.add_roadmark(rm) else: leftlane = Lane(lane_width) leftlane.add_roadmark(rm) lsec.add_left_lane(leftlane) lanesections.append(lsec) # create the lane linker to link the lanes correctly lanelinker = LaneLinker() for i in range(1, len(right_lane)): if right_lane[i].n_lanes_end > right_lane[i].n_lanes_start: # lane split for j in range(0, right_lane[i - 1].n_lanes_end + 1): # adjust for the new lane if right_lane[i].sub_lane < -(j + 1): lanelinker.add_link( lanesections[i - 1].rightlanes[j], lanesections[i].rightlanes[j] ) elif right_lane[i].sub_lane > -(j + 1): lanelinker.add_link( lanesections[i - 1].rightlanes[j - 1], lanesections[i].rightlanes[j], ) elif right_lane[i - 1].n_lanes_end < right_lane[i - 1].n_lanes_start: # lane merge for j in range(0, right_lane[i - 1].n_lanes_end + 1): # adjust for the lost lane if right_lane[i - 1].sub_lane < -(j + 1): lanelinker.add_link( lanesections[i - 1].rightlanes[j], lanesections[i].rightlanes[j] ) elif right_lane[i - 1].sub_lane > -(j + 1): lanelinker.add_link( lanesections[i - 1].rightlanes[j], lanesections[i].rightlanes[j - 1], ) else: # same number of lanes, just add the links for j in range(right_lane[i - 1].n_lanes_end): lanelinker.add_link( lanesections[i - 1].rightlanes[j], lanesections[i].rightlanes[j] ) for i in range(1, len(left_lane)): if left_lane[i].n_lanes_end > left_lane[i].n_lanes_start: # lane split for j in range(0, left_lane[i - 1].n_lanes_end + 1): # adjust for the new lane if left_lane[i].sub_lane < (j + 1): lanelinker.add_link( lanesections[i - 1].leftlanes[j - 1], lanesections[i].leftlanes[j], ) elif left_lane[i].sub_lane > (j + 1): lanelinker.add_link( lanesections[i - 1].leftlanes[j], lanesections[i].leftlanes[j] ) elif left_lane[i - 1].n_lanes_end < left_lane[i - 1].n_lanes_start: # lane merge for j in range(0, left_lane[i - 1].n_lanes_end + 1): # adjust for the lost lane if left_lane[i - 1].sub_lane < (j + 1): lanelinker.add_link( lanesections[i - 1].leftlanes[j], lanesections[i].leftlanes[j - 1], ) elif left_lane[i - 1].sub_lane > (j + 1): lanelinker.add_link( lanesections[i - 1].leftlanes[j], lanesections[i].leftlanes[j] ) else: # same number of lanes, just add the links for j in range(left_lane[i - 1].n_lanes_end): lanelinker.add_link( lanesections[i - 1].leftlanes[j], lanesections[i].leftlanes[j] ) # Add the lanesections to the lanes struct together the lanelinker lanes = Lanes() for ls in lanesections: lanes.add_lanesection(ls, lanelinker) return lanes
create_lanes_merge_split is a generator that will create the Lanes of a road road that can contain one or more lane merges/splits This is a simple implementation and has some constraints: - left and right merges has to be at the same place (or one per lane), TODO: will be fixed with the singleSide attribute later on. - the change will be a 3 degree polynomial with the derivative 0 on both start and end.
Please note that the merges/splits are defined in the road direction, NOT the driving direction.
Parameters
right_lane_def (list of LaneDef, or an int): a list of the splits/merges that are wanted on the right side of the road, if int constant number of lanes left_lane_def (list of LaneDef, or an int): a list of the splits/merges that are wanted on the left side of the road, if int constant number of lanes. road_length (float): the full length of the road center_road_mark (RoadMark): roadmark for the center line lane_width (float): the width of the lanes lane_width_end (float): the end width of the lanes
Return
road (Lanes): the lanes of a road
def std_roadmark_broken()
-
Expand source code
def std_roadmark_broken(): roadmark = RoadMark(RoadMarkType.broken, 0.2) roadmark.add_specific_road_line(RoadLine(0.15, 3, 9, 0, 0)) return roadmark
def std_roadmark_broken_broken()
-
Expand source code
def std_roadmark_broken_broken(): roadmark = RoadMark(RoadMarkType.broken_broken) roadmark.add_specific_road_line(RoadLine(0.2, 3, 3, 0.2, 0)) roadmark.add_specific_road_line(RoadLine(0.2, 3, 3, -0.2, 0)) return roadmark
def std_roadmark_broken_long_line()
-
Expand source code
def std_roadmark_broken_long_line(): roadmark = RoadMark(RoadMarkType.broken, 0.2) roadmark.add_specific_road_line(RoadLine(0.15, 9, 3, 0, 0)) return roadmark
def std_roadmark_broken_solid()
-
Expand source code
def std_roadmark_broken_solid(): roadmark = RoadMark(RoadMarkType.broken_solid) roadmark.add_specific_road_line(RoadLine(0.2, 0, 0, -0.2, 0)) roadmark.add_specific_road_line(RoadLine(0.2, 3, 3, 0.2, 0)) return roadmark
def std_roadmark_broken_tight()
-
Expand source code
def std_roadmark_broken_tight(): roadmark = RoadMark(RoadMarkType.broken, 0.2) roadmark.add_specific_road_line(RoadLine(0.15, 3, 3, 0, 0)) return roadmark
def std_roadmark_solid()
-
Expand source code
def std_roadmark_solid(): return RoadMark(RoadMarkType.solid, 0.2)
def std_roadmark_solid_broken()
-
Expand source code
def std_roadmark_solid_broken(): roadmark = RoadMark(RoadMarkType.solid_broken) roadmark.add_specific_road_line(RoadLine(0.2, 0, 0, 0.2, 0)) roadmark.add_specific_road_line(RoadLine(0.2, 3, 3, -0.2, 0)) return roadmark
def std_roadmark_solid_solid()
-
Expand source code
def std_roadmark_solid_solid(): roadmark = RoadMark(RoadMarkType.solid_solid) roadmark.add_specific_road_line(RoadLine(0.2, 0, 0, 0.2, 0)) roadmark.add_specific_road_line(RoadLine(0.2, 0, 0, -0.2, 0)) return roadmark
Classes
class LaneDef (s_start,
s_end,
n_lanes_start,
n_lanes_end,
sub_lane=None,
lane_start_widths=[],
lane_end_widths=[])-
Expand source code
class LaneDef: """LaneDef is used to help create a lane merge or split. Can handle one lane merging or spliting. NOTE: This is not part of the OpenDRIVE standard, but a helper for the xodr module. Parameters ---------- s_start (float): s coordinate of the start of the change s_end (float): s coordinate of the end of the change n_lanes_start (int): number of lanes at s_start n_lanes_end (int): number of lanes at s_end sub_lane (int): the lane that should be created (split) or removed (merge) lane_start_widths (list of float): widths of lanes at start, must be [] or same length as n_lanes_start Default: [] lane_end_widths (list of float): widths of lanes at end, must be [] or same length as n_lanes_end Default: same as lane_start_widths Attributes ---------- s_start (float): s coordinate of the start of the change s_end (float): s coordinate of the end of the change n_lanes_start (int): number of lanes at s_start n_lanes_end (int): number of lanes at s_end sub_lane (int): the lane that should be created (split) or removed (merge) lane_start_widths (list of float): widths of lanes at start, must be [] or same length as n_lanes_start lane_end_widths (list of float): widths of lanes at end, must be [] or same length as n_lanes_end """ def __init__( self, s_start, s_end, n_lanes_start, n_lanes_end, sub_lane=None, lane_start_widths=[], lane_end_widths=[], ): self.s_start = s_start self.s_end = s_end self.n_lanes_start = n_lanes_start self.n_lanes_end = n_lanes_end self.sub_lane = sub_lane self.lane_start_widths = lane_start_widths if lane_end_widths == []: self.lane_end_widths = self.lane_start_widths.copy() else: self.lane_end_widths = lane_end_widths def _adjust_lane_widths(self): if self.sub_lane: if self.lane_end_widths and len(self.lane_end_widths) < self.n_lanes_start: # mergeo self.lane_end_widths.insert(abs(self.sub_lane) - 1, 0) elif ( self.lane_start_widths and len(self.lane_start_widths) < self.n_lanes_end ): # split self.lane_start_widths.insert(abs(self.sub_lane) - 1, 0) # TODO: add some checks here?
LaneDef is used to help create a lane merge or split. Can handle one lane merging or spliting.
NOTE: This is not part of the OpenDRIVE standard, but a helper for the xodr module.
Parameters
s_start (float): s coordinate of the start of the change s_end (float): s coordinate of the end of the change n_lanes_start (int): number of lanes at s_start n_lanes_end (int): number of lanes at s_end sub_lane (int): the lane that should be created (split) or removed (merge) lane_start_widths (list of float): widths of lanes at start, must be [] or same length as n_lanes_start Default: [] lane_end_widths (list of float): widths of lanes at end, must be [] or same length as n_lanes_end Default: same as lane_start_widths
Attributes
s_start (float): s coordinate of the start of the change s_end (float): s coordinate of the end of the change n_lanes_start (int): number of lanes at s_start n_lanes_end (int): number of lanes at s_end sub_lane (int): the lane that should be created (split) or removed (merge) lane_start_widths (list of float): widths of lanes at start, must be [] or same length as n_lanes_start lane_end_widths (list of float): widths of lanes at end, must be [] or same length as n_lanes_end