Source code for simulation.utils.road.sections.traffic_island

"""TrafficIsland."""

import functools
import math
from dataclasses import dataclass
from typing import List

import simulation.utils.road.sections.type as road_section_type
from simulation.utils.geometry import Line, Point, Polygon, Vector
from simulation.utils.road.config import Config
from simulation.utils.road.sections import SurfaceMarkingPoly, TrafficSign
from simulation.utils.road.sections.bezier_curve import add_quad_bezier_points
from simulation.utils.road.sections.road_section import MarkedLine, RoadSection


[docs]@dataclass class TrafficIsland(RoadSection): """Road section representing an traffic island. Args: island_width (float) = 0.3: width of the island in the middle zebra_length (float) = 0.45: length of zebra section on the island curve_area_length (float) = 0.8: length of curve area section curvature (float) = 0.5: amount of curvature ranging from 0 to 1 zebra_marking_type (int) = TrafficIsland.LINES: marking on the middle of the island """ TYPE = road_section_type.TRAFFIC_ISLAND LINES = 0 """Possible value for :attr:`zebra_marking_type`. Show lines on the island.""" ZEBRA = 1 """Possible value for :attr:`zebra_marking_type`. Show zebra crossing on the island.""" island_width: float = 0.3 """Width of island in the middle.""" zebra_length: float = 0.45 """Length of the zebra crossing area.""" curve_area_length: float = 0.8 """Length of the bezier curve area at start and end of island.""" curvature: float = 0.4 """Define where along the curve area the control points are located.""" zebra_marking_type: int = ZEBRA """Type of zebra marking type. Can be LINES or ZEBRA.""" _sign_distance: float = 0.30 """Distance of the directions signs from the mid island part.""" def __post_init__(self): super().__post_init__() self.p_offset = self.curve_area_length * self.curvature """Offset for the bezier control points of the curve area.""" traffic_sign_start_point = Point(self.curve_area_length - self._sign_distance, 0) self.traffic_signs.append( TrafficSign( TrafficSign.PASS_RIGHT, *traffic_sign_start_point.xy, angle=0, normalize_x=False, ) ) traffic_sign_end_point = Point( self.length - self.curve_area_length + self._sign_distance, 0 ) self.traffic_signs.append( TrafficSign( TrafficSign.PASS_RIGHT, *traffic_sign_end_point.xy, angle=math.pi, normalize_x=False, visible=False, ) ) if self.zebra_marking_type == self.ZEBRA: vector = Vector( self.right_line.interpolate( self.right_line.project(traffic_sign_start_point) ) ) point = vector + Vector(0, -0.1) self.traffic_signs.append( TrafficSign( TrafficSign.ZEBRA_CROSSING, *point.xy, angle=0, normalize_x=False, ) ) right_poly = Polygon( [ self.right_zebra_start, self.right_zebra_end, self.middle_r_zebra_end, self.middle_r_zebra_start, ] ) left_poly = Polygon( [ self.left_zebra_start, self.left_zebra_end, self.middle_l_zebra_end, self.middle_l_zebra_start, ] ) if self.zebra_marking_type == self.LINES: kind = SurfaceMarkingPoly.ZEBRA_LINES else: kind = SurfaceMarkingPoly.ZEBRA_CROSSING self.surface_markings.append( SurfaceMarkingPoly(_frame=right_poly, kind=kind, normalize_x=False) ) self.surface_markings.append( SurfaceMarkingPoly(_frame=left_poly, kind=kind, normalize_x=False) ) blocked_start_poly = Polygon( [ self.middle_l_zebra_start, *reversed(self.bezier_points_mid_l_start), self.middle_start, *self.bezier_points_mid_r_start, self.middle_r_zebra_start, ] ) blocked_end_poly = Polygon( [ self.middle_r_zebra_end, *self.bezier_points_mid_r_end, self.middle_end, *reversed(self.bezier_points_mid_l_end), self.middle_l_zebra_end, ] ) self.surface_markings.append( SurfaceMarkingPoly( _frame=blocked_start_poly, kind=SurfaceMarkingPoly.TRAFFIC_ISLAND_BLOCKED, normalize_x=False, ) ) self.surface_markings.append( SurfaceMarkingPoly( _frame=blocked_end_poly, kind=SurfaceMarkingPoly.TRAFFIC_ISLAND_BLOCKED, normalize_x=False, ) ) @property def length(self) -> float: """Length of the entire section.""" return self.curve_area_length * 2 + self.zebra_length @property def middle_start(self) -> Vector: return Vector(0, 0) @property def middle_r_zebra_start(self) -> Vector: return self.middle_start + Vector(self.curve_area_length, -self.island_width / 2) @property def middle_r_zebra_end(self) -> Vector: return self.middle_r_zebra_start + Vector(self.zebra_length, 0) @property def middle_end(self) -> Vector: return self.middle_r_zebra_end + Vector( self.curve_area_length, self.island_width / 2 ) @property def right_zebra_start(self) -> Vector: return self.middle_start + Vector( self.curve_area_length, -Config.road_width - self.island_width / 2 ) @property def right_zebra_end(self) -> Vector: return self.right_zebra_start + Vector(self.zebra_length, 0) @property def left_zebra_start(self) -> Vector: return self.middle_start + Vector( self.curve_area_length, Config.road_width + self.island_width / 2 ) @property def left_zebra_end(self) -> Vector: return self.left_zebra_start + Vector(self.zebra_length, 0) @property def middle_l_zebra_start(self) -> Vector: return self.middle_start + Vector(self.curve_area_length, self.island_width / 2) @property def middle_l_zebra_end(self) -> Vector: return self.middle_l_zebra_start + Vector(self.zebra_length, 0) @property def bezier_points_mid_r_start(self) -> List[Point]: return add_quad_bezier_points( self.middle_start.to_numpy(), (self.middle_start + Vector(self.p_offset, 0)).to_numpy(), (self.middle_r_zebra_start - Vector(self.p_offset, 0)).to_numpy(), self.middle_r_zebra_start.to_numpy(), ) @property def bezier_points_mid_r_end(self) -> List[Point]: return add_quad_bezier_points( self.middle_r_zebra_end.to_numpy(), (self.middle_r_zebra_end + Vector(self.p_offset, 0)).to_numpy(), (self.middle_end - Vector(self.p_offset, 0)).to_numpy(), self.middle_end.to_numpy(), ) @property def bezier_points_mid_l_start(self) -> List[Point]: return add_quad_bezier_points( self.middle_start.to_numpy(), (self.middle_start + Vector(self.p_offset, 0)).to_numpy(), (self.middle_l_zebra_start - Vector(self.p_offset, 0)).to_numpy(), self.middle_l_zebra_start.to_numpy(), ) @property def bezier_points_mid_l_end(self) -> List[Point]: return add_quad_bezier_points( self.middle_l_zebra_end.to_numpy(), (self.middle_l_zebra_end + Vector(self.p_offset, 0)).to_numpy(), (self.middle_end - Vector(self.p_offset, 0)).to_numpy(), self.middle_end.to_numpy(), ) @property def middle_line_r(self) -> Line: """Line: Middle line on the right side of the traffic island.""" return ( self.transform * Line( [ self.middle_start, *self.bezier_points_mid_r_start, self.middle_r_zebra_start, self.middle_r_zebra_end, *self.bezier_points_mid_r_end, self.middle_end, ] ).simplify() ) """The simplification is necessary to be able to draw the blocked areas of the island. If the line is not simplified the result of the intersection process which is used to draw the blocked stripes is a MultiPoints. """ @property def middle_line_l(self) -> Line: """Line: Middle line on the left side of the traffic island.""" return ( self.transform * Line( [ self.middle_start, *self.bezier_points_mid_l_start, self.middle_l_zebra_start, self.middle_l_zebra_end, *self.bezier_points_mid_l_end, self.middle_end, ] ).simplify() ) @functools.cached_property def middle_line(self) -> Line: """Line: Middle line of the road section. Here it is the left middle line. """ return self.middle_line_r @property def right_line(self) -> Line: """Line: Right line of the road section.""" return self.middle_line_r.parallel_offset(Config.road_width, "right") @property def left_line(self) -> Line: """Line: Left line of the road section.""" return self.middle_line_l.parallel_offset(Config.road_width, "left") @property def lines(self) -> List[MarkedLine]: """List[MarkedLine]: All road lines with their marking type.""" lines = [] lines.append( MarkedLine.from_line(self.left_line, self.left_line_marking, self.prev_length) ) lines.append( MarkedLine.from_line( self.middle_line, self.SOLID_LINE_MARKING, self.prev_length ) ) lines.append( MarkedLine.from_line(self.right_line, self.right_line_marking, self.prev_length) ) lines.append( MarkedLine.from_line( self.middle_line_l, self.SOLID_LINE_MARKING, self.prev_length ) ) return lines