```"""Road elements are simple individual components of the road that have a frame.

Examples are traffic signs, obstacles or surface markings (e.g. turn arrow on the ground.
"""

from dataclasses import dataclass
from typing import Union

from simulation.utils.geometry import Line, Point, Polygon, Transform

[docs]@dataclass
normalize_x: bool = True
"""If true, all x-values are substracted by the lowest x-value."""

_frame: Polygon = Polygon(
[Point(-0.1, -0.2), Point(0.1, -0.2), Point(0.1, 0.2), Point(-0.1, 0.2)]
)
"""Polygon: Frame of the element in local coordinates."""

[docs]    def set_transform(self, obj: Union[Line, Transform]):
"""Calculate the correct transform to this element.

Depending on :attr:`self.normalize_x` the positional behavior is different. If
:attr:`self.normalize_x` is True, the element is aligned along the provided line.
"""
if type(obj) is Line:
pose = obj.interpolate_pose(
arc_length=self._center.x if self.normalize_x else 0
)
obj = Transform(pose, pose.get_angle())
super().set_transform(obj)

@property
def frame(self) -> Polygon:
"""Polygon: Frame of the element in global coordinates."""
tf = (
Transform([-self._center.x, 0], 0) if self.normalize_x else Transform([0, 0], 0)
)
return self.transform * (tf * self._frame)

@property
def center(self) -> Point:
"""Point: Center point of the element in global coordinates."""
return Point(self.frame.centroid)

@property
def _center(self) -> Point:
"""Point: Center point of the element in local coordinates."""
return Point(self._frame.centroid)

[docs]@dataclass
"""Generic element of the road that has a frame.

Examples of road elements are obstacles and traffic signs.

Args:
arc_length: x coordinate of the element along the road.
y: y coordinate of the element. (Perpendicular to the road.)
width: Width of the element.
depth: Depth of the element. Component of the size in the direction of the road.
angle: Angle [radian] between the middle line and the element
(measured at the center).
"""

width: float = 0.2
"""Width of the element."""
depth: float = 0.2
"""Depth (length) of the element."""
angle: float = 0
"""Angle [radian] between the middle line and the element (measured at the center)."""

def __init__(
self,
arc_length: float = 0.4,
y: float = -0.2,
width: float = width,
depth: float = depth,
angle: float = angle,
normalize_x: bool = True,
z: float = 0,
height: float = 0,
):
for obj in arc_length, y, width, depth, angle:
assert isinstance(obj, float) or isinstance(
obj, int
), f"Should be a number but is {obj}"

self.width = width
self.depth = depth
self.angle = angle
self.height = height
super().__init__(
normalize_x=normalize_x,
_frame=Transform(Point(arc_length, y, z), self.angle)
* Polygon(
[
[-self.depth / 2, self.width / 2],
[self.depth / 2, self.width / 2],
[self.depth / 2, -self.width / 2],
[-self.depth / 2, -self.width / 2],
]
),
)

@property
def orientation(self) -> float:
"""float: Orientation of the element in global coordinates in radians."""
return self.transform.get_angle() + self.angle
```