import enum
from typing import List, Union
import numpy as np
from commonroad.common.validity import *
import commonroad.geometry.transform
__author__ = "Hanna Krasowski, Benedikt Pfleiderer, Fabian Thomas-Barein"
__copyright__ = "TUM Cyber-Physical System Group"
__credits__ = ["ConVeY"]
__version__ = "2022a"
__maintainer__ = "Hanna Krasowski"
__email__ = "commonocean@lists.lrz.de"
__status__ = "released"
@enum.unique
class TrafficSignElementID(enum.Enum):
LATERAL_MARK_RED_A = '101'
LATERAL_MARK_GREEN_A = '102'
SPECIAL_MARK = '103'
CARDINAL_MARK_NORTH = '104'
CARDINAL_MARK_EAST = '105'
CARDINAL_MARK_SOUTH = '106'
CARDINAL_MARK_WEST = '107'
"""
e.g. östlich umfahren, Untiefe, ankern verboten
"""
[docs]class TrafficSignElement:
""" Class which represents a collection of traffic signs at one position"""
def __init__(self, traffic_sign_element_id: Union[TrafficSignElementID],
additional_values: List[str]):
"""
:param traffic_sign_element_id: ID of traffic sign element (must be element of a traffic sign element enum)
:param additional_values: list of additional values of a traffic sign element, e.g. velocity, time, city name
"""
self._traffic_sign_element_id = traffic_sign_element_id
self._additional_values = additional_values
@property
def traffic_sign_element_id(self) -> enum:
return self._traffic_sign_element_id
@property
def additional_values(self) -> List[str]:
return self._additional_values
def __eq__(self, other: 'TrafficSignElement'):
if self.traffic_sign_element_id == other.traffic_sign_element_id \
and self.additional_values == other.additional_values:
return True
else:
return False
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(str(self._traffic_sign_element_id) + str(self.additional_values))
def __str__(self):
return f"Sign Element with id {self._traffic_sign_element_id} and values {self._additional_values} "
def __repr__(self):
return f"Sign Element with id {self._traffic_sign_element_id} and values {self._additional_values} "
[docs]class TrafficSign:
"""Class to represent a traffic sign"""
def __init__(self, traffic_sign_id: int, traffic_sign_elements: List[TrafficSignElement],
position: np.ndarray, virtual: bool = False):
"""
:param traffic_sign_id: ID of traffic sign
:param traffic_sign_elements: list of traffic sign elements
:param position: position of traffic sign
:param virtual: boolean indicating if this traffic sign is also placed there in the real environment or it
is added for other reasons (e.g., completeness of scenario)
"""
self._traffic_sign_id = traffic_sign_id
self._position = position
self._traffic_sign_elements = traffic_sign_elements
self._virtual = virtual
self._related_obstacle = None
def __eq__(self, other):
if not isinstance(other, TrafficSign):
warnings.warn(f"Inequality between TrafficSign {repr(self)} and different type {type(other)}")
return False
list_elements_eq = True
traffic_sign_elements = {traffic_sign_element.traffic_sign_element_id: traffic_sign_element
for traffic_sign_element in self._traffic_sign_elements}
traffic_sign_elements_other = {traffic_sign_element.traffic_sign_element_id: traffic_sign_element
for traffic_sign_element in other._traffic_sign_elements}
traffic_sign_eq = len(traffic_sign_elements) == len(traffic_sign_elements_other)
for k in traffic_sign_elements.keys():
if k not in traffic_sign_elements_other:
traffic_sign_eq = False
continue
if traffic_sign_elements.get(k) != traffic_sign_elements_other.get(k):
list_elements_eq = False
position_string = None if self._position is None else \
np.array2string(np.around(self._position.astype(float), 10), precision=10)
position_other_string = None if other._position is None else \
np.array2string(np.around(other.position.astype(float), 10), precision=10)
if traffic_sign_eq and self._traffic_sign_id == other.traffic_sign_id \
and position_string == position_other_string and self._virtual == other.virtual:
return list_elements_eq
warnings.warn(f"Inequality of TrafficSign {repr(self)} and the other one {repr(other)}")
return False
def __hash__(self):
position_string = None if self._position is None else \
np.array2string(np.around(self._position.astype(float), 10), precision=10)
return hash((self._traffic_sign_id, position_string, frozenset(self._traffic_sign_elements), self._virtual))
def __repr__(self):
return f"TrafficSign(traffic_sign_id={self._traffic_sign_id}, " \
f"traffic_sign_elements={repr(self._traffic_sign_elements)}, " \
f"position={None if self._position is None else self._position.tolist()}, virtual={self._virtual})"
def __str__(self):
return f"Sign At {self._position} with {self._traffic_sign_elements} "
@property
def traffic_sign_id(self) -> int:
return self._traffic_sign_id
@property
def position(self) -> Union[None, np.ndarray]:
return self._position
@property
def traffic_sign_elements(self) -> List[TrafficSignElement]:
return self._traffic_sign_elements
@property
def virtual(self) -> bool:
return self._virtual
@property
def related_obstacle(self) -> Union[None, int]:
return self._related_obstacle
@related_obstacle.setter
def related_obstacle(self, obstacle_id: int):
self._related_obstacle = obstacle_id
[docs] def translate_rotate(self, translation: np.ndarray, angle: float):
"""
This method translates and rotates a traffic sign
:param translation: The translation given as [x_off,y_off] for the x and y translation
:param angle: The rotation angle in radian (counter-clockwise defined)
"""
assert is_real_number_vector(translation, 2), '<TrafficSign/translate_rotate>: argument translation is ' \
'not a vector of real numbers of length 2.'
assert is_real_number(angle), '<TrafficSign/translate_rotate>: argument angle must be a scalar. ' \
'angle = %s' % angle
assert is_valid_orientation(angle), '<TrafficSign/translate_rotate>: argument angle must be within the ' \
'interval [-2pi, 2pi]. angle = %s' % angle
self._position = commonroad.geometry.transform.translate_rotate(np.array([self._position]),
translation, angle)[0]