Module scenariogeneration.xodr.links
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.
Functions
def are_roads_connected(road1, road2)
-
Expand source code
def are_roads_connected(road1, road2): """checks if road1 and road2 are connected as successor/successor or predecessor/predecessor Parameters ---------- road1 (Road): the first road road1 (Road): the second road Returns ------- bool, str (successor or predecessor) """ if road1.successor is not None and road2.successor is not None: if ( road1.successor.element_type == ElementType.road and road2.successor.element_type == ElementType.road ): if ( road1.successor.element_id == road2.id and road2.successor.element_id == road1.id ): return True, "successor" if road1.predecessor is not None and road2.predecessor is not None: if ( road1.predecessor.element_type == ElementType.road and road2.predecessor.element_type == ElementType.road ): if ( road1.predecessor.element_id == road2.id and road2.predecessor.element_id == road1.id ): return True, "predecessor" return False, ""
checks if road1 and road2 are connected as successor/successor or predecessor/predecessor
Parameters
road1 (Road): the first road road1 (Road): the second road
Returns
bool, str (successor or predecessor)
def are_roads_consecutive(road1, road2)
-
Expand source code
def are_roads_consecutive(road1, road2): """checks if road2 follows road1 Parameters ---------- road1 (Road): the first road road1 (Road): the second road Returns ------- bool """ if road1.successor is not None and road2.predecessor is not None: if ( road1.successor.element_type == ElementType.road and road2.predecessor.element_type == ElementType.road ): if ( road1.successor.element_id == road2.id and road2.predecessor.element_id == road1.id ): return True return False
checks if road2 follows road1
Parameters
road1 (Road): the first road road1 (Road): the second road
Returns
bool
def create_lane_links(road1, road2)
-
Expand source code
def create_lane_links(road1, road2): """create_lane_links takes two roads and if they are connected, match their lanes and creates lane links. Parameters ---------- road1 (Road): first road to be lane linked road2 (Road): second road to be lane linked """ if road1.road_type == -1 and road2.road_type == -1: # both are roads if are_roads_consecutive(road1, road2): _create_links_roads(road1, road2) elif are_roads_consecutive(road2, road1): _create_links_roads(road2, road1) else: connected, connectiontype = are_roads_connected(road1, road2) if connected: _create_links_roads(road1, road2, connectiontype) elif road1.road_type != -1: _create_links_connecting_road(road1, road2) elif road2.road_type != -1: _create_links_connecting_road(road2, road1)
create_lane_links takes two roads and if they are connected, match their lanes and creates lane links.
Parameters
road1 (Road): first road to be lane linked road2 (Road): second road to be lane linked
def create_lane_links_from_ids(road1, road2, road1_lane_ids, road2_lane_ids)
-
Expand source code
def create_lane_links_from_ids(road1, road2, road1_lane_ids, road2_lane_ids): """ Experimental function to connect lanes of two roads given the corresponding lane IDs (numbers). NOTE: Usually only necessary when there is not the same amount of lanes at the connection of two roads or there are new lanes with zero width at the beginning of a road. Parameters ---------- road1 (Road): the first road road2 (Road): the second road road1_lane_ids (list of int): list of the ids of road1 (do not use the 0 lane) road2_lane_ids (list of int): list of the ids of road2 (do not use the 0 lane) """ if len(road1_lane_ids) != len(road2_lane_ids): raise GeneralIssueInputArguments("Length of the lane ID lists is not the same.") if (0 in road1_lane_ids) or (0 in road2_lane_ids): raise ValueError("The center lane (ID 0) should not be linked.") if road1.road_type == -1 and road2.road_type == -1: first_linktype, _, first_connecting_lanesec = _get_related_lanesection( road1, road2 ) second_linktype, _, second_connecting_lanesec = _get_related_lanesection( road2, road1 ) # The road links need to be reciprocal for the lane linking to succeed if first_linktype == None or second_linktype == None: raise ValueError( "Unable to create lane links for road with ID " + str(road1.id) + " and road with ID " + str(road2.id) + " due to non reciprocal road successor/predecessor links." ) for i in range(len(road1_lane_ids)): if road1_lane_ids[i] > 0: road1.lanes.lanesections[first_connecting_lanesec].leftlanes[ road1_lane_ids[i] - 1 ].add_link(first_linktype, road2_lane_ids[i]) else: road1.lanes.lanesections[first_connecting_lanesec].rightlanes[ abs(road1_lane_ids[i]) - 1 ].add_link(first_linktype, road2_lane_ids[i]) if road2_lane_ids[i] > 0: road2.lanes.lanesections[second_connecting_lanesec].leftlanes[ road2_lane_ids[i] - 1 ].add_link(second_linktype, road1_lane_ids[i]) else: road2.lanes.lanesections[second_connecting_lanesec].rightlanes[ abs(road2_lane_ids[i]) - 1 ].add_link(second_linktype, road1_lane_ids[i]) else: raise NotImplementedError( "This API currently does not support linking with junction connecting roads." )
Experimental function to connect lanes of two roads given the corresponding lane IDs (numbers).
NOTE: Usually only necessary when there is not the same amount of lanes at the connection of two roads or there are new lanes with zero width at the beginning of a road.
Parameters
road1 (Road): the first road road2 (Road): the second road road1_lane_ids (list of int): list of the ids of road1 (do not use the 0 lane) road2_lane_ids (list of int): list of the ids of road2 (do not use the 0 lane)
Classes
class Connection (incoming_road, connecting_road, contact_point, id=None)
-
Expand source code
class Connection(XodrBase): """Connection creates a connection as a base of junction Parameters ---------- incoming_road (int): the id of the incoming road to the junction connecting_road (int): id of the connecting road (type junction) contact_point (ContactPoint): the contact point of the link id (int): id of the junction (automated?) Attributes ---------- incoming_road (int): the id of the incoming road to the junction connecting_road (int): id of the connecting road (type junction) contact_point (ContactPoint): the contact point of the link id (int): id of the connection (automated?) links (list of tuple(int) ): a list of all lanelinks in the connection Methods ------- get_element() Returns the full ElementTree of the class get_attributes() Returns a dictionary of all attributes of the class add_lanelink(in_lane,out_lane) Adds a lane link to the connection """ def __init__(self, incoming_road, connecting_road, contact_point, id=None): """initalize the Connection Parameters ---------- incoming_road (int): the id of the incoming road to the junction connecting_road (int): id of the connecting road (for junctiontypes virutal and default), or the linkedRoad (for junctiontype direct) contact_point (ContactPoint): the contact point of the link id (int): id of the junction (automated) """ super().__init__() self.incoming_road = incoming_road self.connecting_road = connecting_road self.contact_point = enumchecker(contact_point, ContactPoint, True) self.id = id self.links = [] def __eq__(self, other): if isinstance(other, Connection) and super().__eq__(other): if ( self.get_attributes() == other.get_attributes() and self.links == other.links ): return True return False def _set_id(self, id): """id is set Parameters ---------- id (int): the id of the connection """ if self.id == None: self.id = id def add_lanelink(self, in_lane, out_lane): """Adds a new link to the connection Parameters ---------- in_lane: lane id of the incoming road out_lane: lane id of the outgoing road """ self.links.append((in_lane, out_lane)) return self def get_attributes(self, junctiontype=JunctionType.default): """returns the attributes as a dict of the Connection Parameters ---------- junctiontype (JunctionType): type of junction created (connections will be different) """ retdict = {} retdict["incomingRoad"] = str(self.incoming_road) retdict["id"] = str(self.id) retdict["contactPoint"] = enum2str(self.contact_point) if junctiontype == JunctionType.direct: retdict["linkedRoad"] = str(self.connecting_road) else: retdict["connectingRoad"] = str(self.connecting_road) return retdict def get_element(self, junctiontype=JunctionType.default): """returns the elementTree of the Connection Parameters ---------- junctiontype (JunctionType): type of junction created (connections will be different) """ element = ET.Element("connection", attrib=self.get_attributes(junctiontype)) self._add_additional_data_to_element(element) for l in sorted(self.links, key=lambda x: x[0], reverse=True): ET.SubElement( element, "laneLink", attrib={"from": str(l[0]), "to": str(l[1])} ) return element
Connection creates a connection as a base of junction
Parameters
incoming_road (int): the id of the incoming road to the junction connecting_road (int): id of the connecting road (type junction) contact_point (ContactPoint): the contact point of the link id (int): id of the junction (automated?)
Attributes
incoming_road (int): the id of the incoming road to the junction connecting_road (int): id of the connecting road (type junction) contact_point (ContactPoint): the contact point of the link id (int): id of the connection (automated?) links (list of tuple(int) ): a list of all lanelinks in the connection
Methods
get_element() Returns the full ElementTree of the class get_attributes() Returns a dictionary of all attributes of the class add_lanelink(in_lane,out_lane) Adds a lane link to the connection
initalize the Connection
Parameters
incoming_road (int): the id of the incoming road to the junction connecting_road (int): id of the connecting road (for junctiontypes virutal and default), or the linkedRoad (for junctiontype direct) contact_point (ContactPoint): the contact point of the link id (int): id of the junction (automated)
Ancestors
Methods
def add_lanelink(self, in_lane, out_lane)
-
Expand source code
def add_lanelink(self, in_lane, out_lane): """Adds a new link to the connection Parameters ---------- in_lane: lane id of the incoming road out_lane: lane id of the outgoing road """ self.links.append((in_lane, out_lane)) return self
Adds a new link to the connection
Parameters
in_lane: lane id of the incoming road out_lane: lane id of the outgoing road
def get_attributes(self, junctiontype=JunctionType.default)
-
Expand source code
def get_attributes(self, junctiontype=JunctionType.default): """returns the attributes as a dict of the Connection Parameters ---------- junctiontype (JunctionType): type of junction created (connections will be different) """ retdict = {} retdict["incomingRoad"] = str(self.incoming_road) retdict["id"] = str(self.id) retdict["contactPoint"] = enum2str(self.contact_point) if junctiontype == JunctionType.direct: retdict["linkedRoad"] = str(self.connecting_road) else: retdict["connectingRoad"] = str(self.connecting_road) return retdict
returns the attributes as a dict of the Connection
Parameters
junctiontype (JunctionType): type of junction created (connections will be different)
def get_element(self, junctiontype=JunctionType.default)
-
Expand source code
def get_element(self, junctiontype=JunctionType.default): """returns the elementTree of the Connection Parameters ---------- junctiontype (JunctionType): type of junction created (connections will be different) """ element = ET.Element("connection", attrib=self.get_attributes(junctiontype)) self._add_additional_data_to_element(element) for l in sorted(self.links, key=lambda x: x[0], reverse=True): ET.SubElement( element, "laneLink", attrib={"from": str(l[0]), "to": str(l[1])} ) return element
returns the elementTree of the Connection
Parameters
junctiontype (JunctionType): type of junction created (connections will be different)
Inherited members
class Junction (name,
id,
junction_type=JunctionType.default,
orientation=None,
sstart=None,
send=None,
mainroad=None)-
Expand source code
class Junction(XodrBase): """Junction creates a junction of OpenDRIVE Parameters ---------- name (str): name of the junction id (int): id of the junction junction_type (JunctionType): type of junction Default: JunctionType.default orientation (Orientation): the orientation of the junction (only used for virtual junction) Default: None sstart (float): start of the virtual junction (only used for virtual junction) Default: None send (float): end of the virtual junction (only used for virtual junction) Default: None mainroad (int): main road for a virtual junction Default: None Attributes ---------- name (str): name of the junction id (int): id of the junction connections (list of Connection): all the connections in the junction junction_type (JunctionType): type of junction Default: JunctionType.default orientation (Orientation): the orientation of the junction (only used for virtual junction) sstart (float): start of the virtual junction (only used for virtual junction) send (float): end of the virtual junction (only used for virtual junction) mainroad (int): main road for a virtual junction Methods ------- get_element() Returns the full ElementTree of the class get_attributes() Returns a dictionary of all attributes of the class add_connection(connection) Adds a connection to the junction """ def __init__( self, name, id, junction_type=JunctionType.default, orientation=None, sstart=None, send=None, mainroad=None, ): """initalize the Junction Parameters ---------- name (str): name of the junction id (int): id of the junction junction_type (JunctionType): type of junction Default: JunctionType.default orientation (Orientation): the orientation of the junction (only used for virtual junction) sstart (float): start of the virtual junction (only used for virtual junction) send (float): end of the virtual junction (only used for virtual junction) mainroad (int): main road for a virtual junction """ super().__init__() self.name = name self.id = id self.connections = [] self._id_counter = 0 self.junction_type = enumchecker(junction_type, JunctionType) if junction_type == JunctionType.virtual: if not ( sstart is not None and send is not None and mainroad is not None and orientation is not None ): raise NotEnoughInputArguments( "For virtual junctions sstart, send, orientation, and mainroad has to be added" ) self.sstart = sstart self.send = send self.mainroad = mainroad self.orientation = enumchecker(orientation, Orientation, True) def __eq__(self, other): if isinstance(other, Junction) and super().__eq__(other): if ( self.get_attributes() == other.get_attributes() and self.connections == other.connections ): return True return False def add_connection(self, connection): """Adds a new link to the Junction Parameters ---------- connection (Connection): adds a connection to the junction """ if not isinstance(connection, Connection): raise TypeError("connection is not of type Connection") connection._set_id(self._id_counter) self._id_counter += 1 self.connections.append(connection) return self def get_attributes(self): """returns the attributes as a dict of the Junction""" retdict = {} retdict["name"] = self.name retdict["id"] = str(self.id) retdict["type"] = self.junction_type.name # these are only used for virtual junctions if self.junction_type == JunctionType.virtual: if self.orientation == Orientation.positive: retdict["orientation"] = "+" elif self.orientation == Orientation.negative: retdict["orientation"] = "-" retdict["sEnd"] = str(self.send) retdict["sStart"] = str(self.sstart) retdict["mainRoad"] = str(self.mainroad) return retdict def get_element(self): """returns the elementTree of the Junction""" element = ET.Element("junction", attrib=self.get_attributes()) self._add_additional_data_to_element(element) for con in self.connections: element.append(con.get_element(self.junction_type)) return element
Junction creates a junction of OpenDRIVE
Parameters
name (str): name of the junction id (int): id of the junction junction_type (JunctionType): type of junction Default: JunctionType.default orientation (Orientation): the orientation of the junction (only used for virtual junction) Default: None sstart (float): start of the virtual junction (only used for virtual junction) Default: None send (float): end of the virtual junction (only used for virtual junction) Default: None mainroad (int): main road for a virtual junction Default: None
Attributes
name (str): name of the junction id (int): id of the junction connections (list of Connection): all the connections in the junction junction_type (JunctionType): type of junction Default: JunctionType.default orientation (Orientation): the orientation of the junction (only used for virtual junction) sstart (float): start of the virtual junction (only used for virtual junction) send (float): end of the virtual junction (only used for virtual junction) mainroad (int): main road for a virtual junction
Methods
get_element() Returns the full ElementTree of the class get_attributes() Returns a dictionary of all attributes of the class add_connection(connection) Adds a connection to the junction
initalize the Junction
Parameters
name (str): name of the junction id (int): id of the junction junction_type (JunctionType): type of junction Default: JunctionType.default orientation (Orientation): the orientation of the junction (only used for virtual junction) sstart (float): start of the virtual junction (only used for virtual junction) send (float): end of the virtual junction (only used for virtual junction) mainroad (int): main road for a virtual junction
Ancestors
Methods
def add_connection(self, connection)
-
Expand source code
def add_connection(self, connection): """Adds a new link to the Junction Parameters ---------- connection (Connection): adds a connection to the junction """ if not isinstance(connection, Connection): raise TypeError("connection is not of type Connection") connection._set_id(self._id_counter) self._id_counter += 1 self.connections.append(connection) return self
Adds a new link to the Junction
Parameters
connection (Connection): adds a connection to the junction
def get_attributes(self)
-
Expand source code
def get_attributes(self): """returns the attributes as a dict of the Junction""" retdict = {} retdict["name"] = self.name retdict["id"] = str(self.id) retdict["type"] = self.junction_type.name # these are only used for virtual junctions if self.junction_type == JunctionType.virtual: if self.orientation == Orientation.positive: retdict["orientation"] = "+" elif self.orientation == Orientation.negative: retdict["orientation"] = "-" retdict["sEnd"] = str(self.send) retdict["sStart"] = str(self.sstart) retdict["mainRoad"] = str(self.mainroad) return retdict
returns the attributes as a dict of the Junction
def get_element(self)
-
Expand source code
def get_element(self): """returns the elementTree of the Junction""" element = ET.Element("junction", attrib=self.get_attributes()) self._add_additional_data_to_element(element) for con in self.connections: element.append(con.get_element(self.junction_type)) return element
returns the elementTree of the Junction
Inherited members
class JunctionGroup (name, group_id, junction_type=JunctionGroupType.roundabout)
-
Expand source code
class JunctionGroup(XodrBase): """JunctionGroup creates a JunctionGroup of OpenDRIVE Parameters ---------- name (str): name of the junctiongroup group_id (int): id of the junctiongroup junction_type (JunctionGroupType): type of junction Default: JunctionGroupType.roundabout Attributes ---------- name (str): name of the junctiongroup group_id (int): id of the junctiongroup junctions (list of int): all the junctions in the junctiongroup Methods ------- get_element() Returns the full ElementTree of the class get_attributes() Returns a dictionary of all attributes of the class add_junction(junction_id) Adds a connection to the junction """ def __init__(self, name, group_id, junction_type=JunctionGroupType.roundabout): """initalize the JunctionGroup Parameters ---------- name (str): name of the junctiongroup group_id (int): id of the junctiongroup junction_type (JunctionGroupType): type of junction Default: JunctionGroupType.roundabout """ super().__init__() self.name = name self.group_id = group_id self.junctions = [] self.junction_type = enumchecker(junction_type, JunctionGroupType) def __eq__(self, other): if isinstance(other, JunctionGroup) and super().__eq__(other): if ( self.get_attributes() == other.get_attributes() and self.junctions == other.junctions ): return True return False def add_junction(self, junction_id): """Adds a new link to the JunctionGroup Parameters ---------- junction_id (int): adds a junction to the junctiongroup """ self.junctions.append(junction_id) return self def get_attributes(self): """returns the attributes as a dict of the JunctionGroup""" retdict = {} retdict["name"] = self.name retdict["id"] = str(self.group_id) retdict["type"] = enum2str(self.junction_type) return retdict def get_element(self): """returns the elementTree of the Junction""" element = ET.Element("junctionGroup", attrib=self.get_attributes()) self._add_additional_data_to_element(element) for j in self.junctions: ET.SubElement(element, "junctionReference", attrib={"junction": str(j)}) return element
JunctionGroup creates a JunctionGroup of OpenDRIVE
Parameters
name (str): name of the junctiongroup group_id (int): id of the junctiongroup junction_type (JunctionGroupType): type of junction Default: JunctionGroupType.roundabout
Attributes
name (str): name of the junctiongroup group_id (int): id of the junctiongroup junctions (list of int): all the junctions in the junctiongroup
Methods
get_element() Returns the full ElementTree of the class get_attributes() Returns a dictionary of all attributes of the class add_junction(junction_id) Adds a connection to the junction
initalize the JunctionGroup
Parameters
name (str): name of the junctiongroup group_id (int): id of the junctiongroup junction_type (JunctionGroupType): type of junction Default: JunctionGroupType.roundabout
Ancestors
Methods
def add_junction(self, junction_id)
-
Expand source code
def add_junction(self, junction_id): """Adds a new link to the JunctionGroup Parameters ---------- junction_id (int): adds a junction to the junctiongroup """ self.junctions.append(junction_id) return self
Adds a new link to the JunctionGroup
Parameters
junction_id (int): adds a junction to the junctiongroup
def get_attributes(self)
-
Expand source code
def get_attributes(self): """returns the attributes as a dict of the JunctionGroup""" retdict = {} retdict["name"] = self.name retdict["id"] = str(self.group_id) retdict["type"] = enum2str(self.junction_type) return retdict
returns the attributes as a dict of the JunctionGroup
def get_element(self)
-
Expand source code
def get_element(self): """returns the elementTree of the Junction""" element = ET.Element("junctionGroup", attrib=self.get_attributes()) self._add_additional_data_to_element(element) for j in self.junctions: ET.SubElement(element, "junctionReference", attrib={"junction": str(j)}) return element
returns the elementTree of the Junction
Inherited members
class LaneLinker
-
Expand source code
class LaneLinker: """LaneLinker stored information for linking lane sections NOTE: Not part of OpenDRIVE, but a helper to link lanes for the user. Parameters ---------- Attributes ---------- links: all lane links added (predlane (Lane), succlane (Lane), found=bool) Methods ------- add_link(predlane, succlane) adds a lane link """ def __init__(self): """initalize the _Links""" self.links = [] def add_link(self, predlane, succlane, connecting_road=None): """Adds a _Link Parameters ---------- predlane (Lane): predecessor lane succlane (Lane): successor lane connecting_road (id): id of a connecting road (used for junctions) """ self.links.append(_lanelink(predlane, succlane, connecting_road)) return self
LaneLinker stored information for linking lane sections NOTE: Not part of OpenDRIVE, but a helper to link lanes for the user.
Parameters
Attributes
links: all lane links added (predlane (Lane), succlane (Lane), found=bool)
Methods
add_link(predlane, succlane) adds a lane link
initalize the _Links
Methods
def add_link(self, predlane, succlane, connecting_road=None)
-
Expand source code
def add_link(self, predlane, succlane, connecting_road=None): """Adds a _Link Parameters ---------- predlane (Lane): predecessor lane succlane (Lane): successor lane connecting_road (id): id of a connecting road (used for junctions) """ self.links.append(_lanelink(predlane, succlane, connecting_road)) return self
Adds a _Link
Parameters
predlane (Lane): predecessor lane succlane (Lane): successor lane connecting_road (id): id of a connecting road (used for junctions)