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: Road, road2: Road) ‑> tuple[bool, str]
Expand source code
def are_roads_connected(road1: "Road", road2: "Road") -> tuple[bool, str]:
    """Check if `road1` and `road2` are connected as successor/successor or
    predecessor/predecessor.

    Parameters
    ----------
    road1 : Road
        The first road.
    road2 : Road
        The second road.

    Returns
    -------
    tuple[bool, str]
        A tuple where the first element is a boolean indicating if the
        roads are connected, and the second element is a string
        ("successor" or "predecessor") describing the connection type.
    """
    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, ""

Check if road1 and road2 are connected as successor/successor or predecessor/predecessor.

Parameters

road1 : Road
The first road.
road2 : Road
The second road.

Returns

tuple[bool, str]
A tuple where the first element is a boolean indicating if the roads are connected, and the second element is a string ("successor" or "predecessor") describing the connection type.
def are_roads_consecutive(road1: Road, road2: Road) ‑> bool
Expand source code
def are_roads_consecutive(road1: "Road", road2: "Road") -> bool:
    """Check if `road2` follows `road1`.

    Parameters
    ----------
    road1 : Road
        The first road.
    road2 : Road
        The second road.

    Returns
    -------
    bool
        True if `road2` follows `road1`, False otherwise.
    """

    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

Check if road2 follows road1.

Parameters

road1 : Road
The first road.
road2 : Road
The second road.

Returns

bool
True if road2 follows road1, False otherwise.
Expand source code
def create_lane_links(road1: "Road", road2: "Road") -> None:
    """Match lanes of two roads and create lane links if they are
    connected.

    Parameters
    ----------
    road1 : Road
        The first road to be lane linked.
    road2 : Road
        The 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)

Match lanes of two roads and create lane links if they are connected.

Parameters

road1 : Road
The first road to be lane linked.
road2 : Road
The second road to be lane linked.
Expand source code
def create_lane_links_from_ids(
    road1: "Road",
    road2: "Road",
    road1_lane_ids: list[int],
    road2_lane_ids: list[int],
) -> None:
    """Connect lanes of two roads given their corresponding lane IDs.

    NOTE: This function is typically used when the number of lanes at
    the connection of two roads differs or when new lanes with zero
    width exist 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 lane IDs for `road1` (do not include the center lane with ID 0).
    road2_lane_ids : list of int
        List of lane IDs for `road2` (do not include the center lane with ID 0).

    Raises
    ------
    GeneralIssueInputArguments
        If the lengths of `road1_lane_ids` and `road2_lane_ids` differ.
    ValueError
        If the center lane (ID 0) is included in either `road1_lane_ids`
        or `road2_lane_ids`.
    NotImplementedError
        If linking with junction connecting roads is not supported.
    """
    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."
        )

Connect lanes of two roads given their corresponding lane IDs.

NOTE: This function is typically used when the number of lanes at the connection of two roads differs or when new lanes with zero width exist 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 lane IDs for road1 (do not include the center lane with ID 0).
road2_lane_ids : list of int
List of lane IDs for road2 (do not include the center lane with ID 0).

Raises

GeneralIssueInputArguments
If the lengths of road1_lane_ids and road2_lane_ids differ.
ValueError
If the center lane (ID 0) is included in either road1_lane_ids or road2_lane_ids.
NotImplementedError
If linking with junction connecting roads is not supported.

Classes

class Connection (incoming_road: int,
connecting_road: int,
contact_point: ContactPoint,
id: int | None = None)
Expand source code
class Connection(XodrBase):
    """Create a connection as a base of a junction in OpenDRIVE.

    Parameters
    ----------
    incoming_road : int
        The ID of the incoming road to the junction.
    connecting_road : int
        The ID of the connecting road (type junction).
    contact_point : ContactPoint
        The contact point of the link.
    id : int, optional
        The ID of the connection (automated). Default is None.

    Attributes
    ----------
    incoming_road : int
        The ID of the incoming road to the junction.
    connecting_road : int
        The ID of the connecting road (type junction).
    contact_point : ContactPoint
        The contact point of the link.
    id : int or None
        The ID of the connection (automated).
    links : list of tuple(int, int)
        A list of all lane links in the connection.

    Methods
    -------
    add_lanelink(in_lane, out_lane)
        Add a lane link to the connection.
    get_attributes(junctiontype=JunctionType.default)
        Return the attributes of the connection as a dictionary.
    get_element(junctiontype=JunctionType.default)
        Return the ElementTree representation of the connection.
    """

    def __init__(
        self,
        incoming_road: int,
        connecting_road: int,
        contact_point: ContactPoint,
        id: Optional[int] = None,
    ) -> None:
        """Initialize the `Connection` object.

        Parameters
        ----------
        incoming_road : int
            The ID of the incoming road to the junction.
        connecting_road : int
            The ID of the connecting road (type junction).
        contact_point : ContactPoint
            The contact point of the link.
        id : int, optional
            The ID of the connection (automated). Default is None.
        """
        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: object) -> bool:
        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: int) -> None:
        """Set the ID of the connection.

        Parameters
        ----------
        id : int
            The ID to assign to the connection.
        """
        if self.id == None:
            self.id = id

    def add_lanelink(self, in_lane: int, out_lane: int) -> "Connection":
        """Add a new lane link to the connection.

        Parameters
        ----------
        in_lane : int
            The lane ID of the incoming road.
        out_lane : int
            The lane ID of the outgoing road.

        Returns
        -------
        Connection
            The updated `Connection` object.
        """
        self.links.append((in_lane, out_lane))
        return self

    def get_attributes(
        self, junctiontype: JunctionType = JunctionType.default
    ) -> dict:
        """Return the attributes of the connection as a dictionary.

        Parameters
        ----------
        junctiontype : JunctionType, optional
            The type of junction created (connections will differ).
            Default is `JunctionType.default`.

        Returns
        -------
        dict
            A dictionary containing the attributes of the connection.
        """
        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 = JunctionType.default
    ) -> ET.Element:
        """Return the ElementTree representation of the connection.

        Parameters
        ----------
        junctiontype : JunctionType, optional
            The type of junction created (connections will differ).
            Default is `JunctionType.default`.

        Returns
        -------
        ET.Element
            The XML ElementTree representation of the connection.
        """

        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

Create a connection as a base of a junction in OpenDRIVE.

Parameters

incoming_road : int
The ID of the incoming road to the junction.
connecting_road : int
The ID of the connecting road (type junction).
contact_point : ContactPoint
The contact point of the link.
id : int, optional
The ID of the connection (automated). Default is None.

Attributes

incoming_road : int
The ID of the incoming road to the junction.
connecting_road : int
The ID of the connecting road (type junction).
contact_point : ContactPoint
The contact point of the link.
id : int or None
The ID of the connection (automated).
links : list of tuple(int, int)
A list of all lane links in the connection.

Methods

add_lanelink(in_lane, out_lane) Add a lane link to the connection. get_attributes(junctiontype=JunctionType.default) Return the attributes of the connection as a dictionary. get_element(junctiontype=JunctionType.default) Return the ElementTree representation of the connection.

Initialize the Connection object.

Parameters

incoming_road : int
The ID of the incoming road to the junction.
connecting_road : int
The ID of the connecting road (type junction).
contact_point : ContactPoint
The contact point of the link.
id : int, optional
The ID of the connection (automated). Default is None.

Ancestors

Methods

Expand source code
def add_lanelink(self, in_lane: int, out_lane: int) -> "Connection":
    """Add a new lane link to the connection.

    Parameters
    ----------
    in_lane : int
        The lane ID of the incoming road.
    out_lane : int
        The lane ID of the outgoing road.

    Returns
    -------
    Connection
        The updated `Connection` object.
    """
    self.links.append((in_lane, out_lane))
    return self

Add a new lane link to the connection.

Parameters

in_lane : int
The lane ID of the incoming road.
out_lane : int
The lane ID of the outgoing road.

Returns

Connection
The updated Connection object.
def get_attributes(self,
junctiontype: JunctionType = JunctionType.default) ‑> dict
Expand source code
def get_attributes(
    self, junctiontype: JunctionType = JunctionType.default
) -> dict:
    """Return the attributes of the connection as a dictionary.

    Parameters
    ----------
    junctiontype : JunctionType, optional
        The type of junction created (connections will differ).
        Default is `JunctionType.default`.

    Returns
    -------
    dict
        A dictionary containing the attributes of the connection.
    """
    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

Return the attributes of the connection as a dictionary.

Parameters

junctiontype : JunctionType, optional
The type of junction created (connections will differ). Default is JunctionType.default.

Returns

dict
A dictionary containing the attributes of the connection.
def get_element(self,
junctiontype: JunctionType = JunctionType.default) ‑> xml.etree.ElementTree.Element
Expand source code
def get_element(
    self, junctiontype: JunctionType = JunctionType.default
) -> ET.Element:
    """Return the ElementTree representation of the connection.

    Parameters
    ----------
    junctiontype : JunctionType, optional
        The type of junction created (connections will differ).
        Default is `JunctionType.default`.

    Returns
    -------
    ET.Element
        The XML ElementTree representation of the connection.
    """

    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

Return the ElementTree representation of the connection.

Parameters

junctiontype : JunctionType, optional
The type of junction created (connections will differ). Default is JunctionType.default.

Returns

ET.Element
The XML ElementTree representation of the connection.

Inherited members

class Junction (name: str,
id: int,
junction_type: JunctionType = JunctionType.default,
orientation: Orientation | None = None,
sstart: float | None = None,
send: float | None = None,
mainroad: int | None = None)
Expand source code
class Junction(XodrBase):
    """Create a junction in OpenDRIVE.

    Parameters
    ----------
    name : str
        The name of the junction.
    id : int
        The ID of the junction.
    junction_type : JunctionType, optional
        The type of the junction. Default is `JunctionType.default`.
    orientation : Orientation, optional
        The orientation of the junction (used for virtual junctions).
        Default is None.
    sstart : float, optional
        The start of the virtual junction (used for virtual junctions).
        Default is None.
    send : float, optional
        The end of the virtual junction (used for virtual junctions).
        Default is None.
    mainroad : int, optional
        The main road for a virtual junction. Default is None.

    Attributes
    ----------
    name : str
        The name of the junction.
    id : int
        The ID of the junction.
    connections : list of Connection
        All the connections in the junction.
    junction_type : JunctionType
        The type of the junction.
    orientation : Orientation or None
        The orientation of the junction (used for virtual junctions).
    sstart : float or None
        The start of the virtual junction (used for virtual junctions).
    send : float or None
        The end of the virtual junction (used for virtual junctions).
    mainroad : int or None
        The main road for a virtual junction.

    Methods
    -------
    add_connection(connection)
        Add a connection to the junction.
    get_attributes()
        Return the attributes of the junction as a dictionary.
    get_element()
        Return the ElementTree representation of the junction.
    """

    def __init__(
        self,
        name: str,
        id: int,
        junction_type: JunctionType = JunctionType.default,
        orientation: Optional[Orientation] = None,
        sstart: Optional[float] = None,
        send: Optional[float] = None,
        mainroad: Optional[int] = None,
    ) -> None:
        """Initialize the `Junction` object.

        Parameters
        ----------
        name : str
            The name of the junction.
        id : int
            The ID of the junction.
        junction_type : JunctionType, optional
            The type of the junction. Default is `JunctionType.default`.
        orientation : Orientation, optional
            The orientation of the junction (used for virtual junctions).
            Default is None.
        sstart : float, optional
            The start of the virtual junction (used for virtual junctions).
            Default is None.
        send : float, optional
            The end of the virtual junction (used for virtual junctions).
            Default is None.
        mainroad : int, optional
            The main road for a virtual junction. Default is None.

        Raises
        ------
        NotEnoughInputArguments
            If required parameters for a virtual junction are missing.
        """
        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: object) -> bool:
        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: Connection) -> "Junction":
        """Add a new connection to the junction.

        Parameters
        ----------
        connection : Connection
            The connection to add to the junction.

        Returns
        -------
        Junction
            The updated `Junction` object.

        Raises
        ------
        TypeError
            If `connection` is not of type `Connection`.
        """
        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) -> dict:
        """Return the attributes of the junction as a dictionary.

        Returns
        -------
        dict
            A dictionary containing the attributes 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) -> ET.Element:
        """Return the ElementTree representation of the junction.

        Returns
        -------
        ET.Element
            The XML ElementTree representation 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

Create a junction in OpenDRIVE.

Parameters

name : str
The name of the junction.
id : int
The ID of the junction.
junction_type : JunctionType, optional
The type of the junction. Default is JunctionType.default.
orientation : Orientation, optional
The orientation of the junction (used for virtual junctions). Default is None.
sstart : float, optional
The start of the virtual junction (used for virtual junctions). Default is None.
send : float, optional
The end of the virtual junction (used for virtual junctions). Default is None.
mainroad : int, optional
The main road for a virtual junction. Default is None.

Attributes

name : str
The name of the junction.
id : int
The ID of the junction.
connections : list of Connection
All the connections in the junction.
junction_type : JunctionType
The type of the junction.
orientation : Orientation or None
The orientation of the junction (used for virtual junctions).
sstart : float or None
The start of the virtual junction (used for virtual junctions).
send : float or None
The end of the virtual junction (used for virtual junctions).
mainroad : int or None
The main road for a virtual junction.

Methods

add_connection(connection) Add a connection to the junction. get_attributes() Return the attributes of the junction as a dictionary. get_element() Return the ElementTree representation of the junction.

Initialize the Junction object.

Parameters

name : str
The name of the junction.
id : int
The ID of the junction.
junction_type : JunctionType, optional
The type of the junction. Default is JunctionType.default.
orientation : Orientation, optional
The orientation of the junction (used for virtual junctions). Default is None.
sstart : float, optional
The start of the virtual junction (used for virtual junctions). Default is None.
send : float, optional
The end of the virtual junction (used for virtual junctions). Default is None.
mainroad : int, optional
The main road for a virtual junction. Default is None.

Raises

NotEnoughInputArguments
If required parameters for a virtual junction are missing.

Ancestors

Methods

def add_connection(self,
connection: Connection) ‑> Junction
Expand source code
def add_connection(self, connection: Connection) -> "Junction":
    """Add a new connection to the junction.

    Parameters
    ----------
    connection : Connection
        The connection to add to the junction.

    Returns
    -------
    Junction
        The updated `Junction` object.

    Raises
    ------
    TypeError
        If `connection` is not of type `Connection`.
    """
    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

Add a new connection to the junction.

Parameters

connection : Connection
The connection to add to the junction.

Returns

Junction
The updated Junction object.

Raises

TypeError
If connection is not of type Connection.
def get_attributes(self) ‑> dict
Expand source code
def get_attributes(self) -> dict:
    """Return the attributes of the junction as a dictionary.

    Returns
    -------
    dict
        A dictionary containing the attributes 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

Return the attributes of the junction as a dictionary.

Returns

dict
A dictionary containing the attributes of the junction.
def get_element(self) ‑> xml.etree.ElementTree.Element
Expand source code
def get_element(self) -> ET.Element:
    """Return the ElementTree representation of the junction.

    Returns
    -------
    ET.Element
        The XML ElementTree representation 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

Return the ElementTree representation of the junction.

Returns

ET.Element
The XML ElementTree representation of the junction.

Inherited members

class JunctionGroup (name: str,
group_id: int,
junction_type: JunctionGroupType = JunctionGroupType.roundabout)
Expand source code
class JunctionGroup(XodrBase):
    """Create a JunctionGroup in OpenDRIVE.

    Parameters
    ----------
    name : str
        The name of the junction group.
    group_id : int
        The ID of the junction group.
    junction_type : JunctionGroupType, optional
        The type of the junction group.
        Default is `JunctionGroupType.roundabout`.

    Attributes
    ----------
    name : str
        The name of the junction group.
    group_id : int
        The ID of the junction group.
    junctions : list of int
        All the junctions in the junction group.
    junction_type : JunctionGroupType
        The type of the junction group.

    Methods
    -------
    add_junction(junction_id)
        Add a junction to the junction group.
    get_attributes()
        Return the attributes of the junction group as a dictionary.
    get_element()
        Return the ElementTree representation of the junction group.
    """

    def __init__(
        self,
        name: str,
        group_id: int,
        junction_type: JunctionGroupType = JunctionGroupType.roundabout,
    ) -> None:
        """Initialize the JunctionGroup.

        Parameters
        ----------
        name : str
            The name of the junction group.
        group_id : int
            The ID of the junction group.
        junction_type : JunctionGroupType, optional
            The type of the junction group.
            Default is `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: object) -> bool:
        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: int) -> "JunctionGroup":
        """Add a new junction to the JunctionGroup.

        Parameters
        ----------
        junction_id : int
            The ID of the junction to add.

        Returns
        -------
        JunctionGroup
            The updated JunctionGroup object.
        """
        self.junctions.append(junction_id)
        return self

    def get_attributes(self) -> dict:
        """Return the attributes of the JunctionGroup as a dictionary.

        Returns
        -------
        dict
            A dictionary containing the attributes 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) -> ET.Element:
        """Return the ElementTree representation of the JunctionGroup.

        Returns
        -------
        ET.Element
            The XML ElementTree representation of the JunctionGroup.
        """
        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

Create a JunctionGroup in OpenDRIVE.

Parameters

name : str
The name of the junction group.
group_id : int
The ID of the junction group.
junction_type : JunctionGroupType, optional
The type of the junction group. Default is JunctionGroupType.roundabout.

Attributes

name : str
The name of the junction group.
group_id : int
The ID of the junction group.
junctions : list of int
All the junctions in the junction group.
junction_type : JunctionGroupType
The type of the junction group.

Methods

add_junction(junction_id) Add a junction to the junction group. get_attributes() Return the attributes of the junction group as a dictionary. get_element() Return the ElementTree representation of the junction group.

Initialize the JunctionGroup.

Parameters

name : str
The name of the junction group.
group_id : int
The ID of the junction group.
junction_type : JunctionGroupType, optional
The type of the junction group. Default is JunctionGroupType.roundabout.

Ancestors

Methods

def add_junction(self, junction_id: int) ‑> JunctionGroup
Expand source code
def add_junction(self, junction_id: int) -> "JunctionGroup":
    """Add a new junction to the JunctionGroup.

    Parameters
    ----------
    junction_id : int
        The ID of the junction to add.

    Returns
    -------
    JunctionGroup
        The updated JunctionGroup object.
    """
    self.junctions.append(junction_id)
    return self

Add a new junction to the JunctionGroup.

Parameters

junction_id : int
The ID of the junction to add.

Returns

JunctionGroup
The updated JunctionGroup object.
def get_attributes(self) ‑> dict
Expand source code
def get_attributes(self) -> dict:
    """Return the attributes of the JunctionGroup as a dictionary.

    Returns
    -------
    dict
        A dictionary containing the attributes of the JunctionGroup.
    """
    retdict = {}
    retdict["name"] = self.name
    retdict["id"] = str(self.group_id)
    retdict["type"] = enum2str(self.junction_type)
    return retdict

Return the attributes of the JunctionGroup as a dictionary.

Returns

dict
A dictionary containing the attributes of the JunctionGroup.
def get_element(self) ‑> xml.etree.ElementTree.Element
Expand source code
def get_element(self) -> ET.Element:
    """Return the ElementTree representation of the JunctionGroup.

    Returns
    -------
    ET.Element
        The XML ElementTree representation of the JunctionGroup.
    """
    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

Return the ElementTree representation of the JunctionGroup.

Returns

ET.Element
The XML ElementTree representation of the JunctionGroup.

Inherited members

class LaneLinker
Expand source code
class LaneLinker:
    """Store information for linking lane sections.

    NOTE: This class is not part of OpenDRIVE but serves as a helper to
    link lanes for the user.

    Attributes
    ----------
    links : list of _lanelink
        All lane links added, each represented as a tuple of predecessor
        lane, successor lane, and a boolean indicating if the link is
        found.

    Methods
    -------
    add_link(predlane, succlane, connecting_road=None)
        Add a lane link to the list.
    """

    def __init__(self) -> None:
        """Initialize the `LaneLinker` object.

        Attributes
        ----------
        links : list of _lanelink
            A list to store all lane links added to this object.
        """

        self.links = []

    def add_link(
        self,
        predlane: "Lane",
        succlane: "Lane",
        connecting_road: Optional[int] = None,
    ) -> "LaneLinker":
        """Add a lane link to the list.

        Parameters
        ----------
        predlane : Lane
            The predecessor lane.
        succlane : Lane
            The successor lane.
        connecting_road : int, optional
            The ID of a connecting road (used for junctions). Default is None.

        Returns
        -------
        LaneLinker
            The updated `LaneLinker` object.
        """
        self.links.append(_lanelink(predlane, succlane, connecting_road))
        return self

Store information for linking lane sections.

NOTE: This class is not part of OpenDRIVE but serves as a helper to link lanes for the user.

Attributes

links : list of _lanelink
All lane links added, each represented as a tuple of predecessor lane, successor lane, and a boolean indicating if the link is found.

Methods

add_link(predlane, succlane, connecting_road=None) Add a lane link to the list.

Initialize the LaneLinker object.

Attributes

links : list of _lanelink
A list to store all lane links added to this object.

Methods

Expand source code
def add_link(
    self,
    predlane: "Lane",
    succlane: "Lane",
    connecting_road: Optional[int] = None,
) -> "LaneLinker":
    """Add a lane link to the list.

    Parameters
    ----------
    predlane : Lane
        The predecessor lane.
    succlane : Lane
        The successor lane.
    connecting_road : int, optional
        The ID of a connecting road (used for junctions). Default is None.

    Returns
    -------
    LaneLinker
        The updated `LaneLinker` object.
    """
    self.links.append(_lanelink(predlane, succlane, connecting_road))
    return self

Add a lane link to the list.

Parameters

predlane : Lane
The predecessor lane.
succlane : Lane
The successor lane.
connecting_road : int, optional
The ID of a connecting road (used for junctions). Default is None.

Returns

LaneLinker
The updated LaneLinker object.