def way_position_at(self, point: Point) -> WayPosition: """Get the way position at the given point. The `position` value is in meters from the start of the way. """ way_position, _ = self.way_position_raw(point, False) return WayPosition(EntityRef(self), way_position)
def __post_init__(self): if not isinstance(self.way_ref, EntityRef): self.way_ref = EntityRef(self.way_ref) self.half_width = self.way_ref().total_lane_count * HALF_LANE_WIDTH self._build_segments() self._build_polygon()
def __init__(self, start: Union[Node, EntityRef[Node]], end: Union[Node, EntityRef[Node]], lane_count: Tuple[int, int], waypoints: Tuple[Point] = (), max_speed: float = DEFAULT_MAX_SPEED_MPS): self.id = None self.start_ref = EntityRef(start) self.end_ref = EntityRef(end) self.start.starts.append(EntityRef(self)) self.start.clear_cache(True) self.end.ends.append(EntityRef(self)) self.end.clear_cache(True) self.lane_count = lane_count self.waypoints = waypoints self.max_speed = max_speed super().__init__()
def __post_init__(self) -> NodeGeometry: """Create a new `NodeGeometry` instance for the given node.""" if not isinstance(self.node_ref, EntityRef): self.node_ref = EntityRef(self.node_ref) node = self.node_ref() ways = node.sorted_ways() self.way_indexes = {w: i for i, w in enumerate(ways)} self.way_distances = [None for _ in ways] self.polygon = build_polygon(node, ways, self.way_distances)
def __init__(self, node: Node): self.node_ref = EntityRef(node) self.lane_connections = _build_lane_connections(node) self.connection_map = _build_connection_map(node, self.lane_connections) self.curves = _build_bezier_curves(node, self.lane_connections) _build_conflict_points(node, self.curves) self._build_way_connections() for curve in self.curves.values(): curve.init_traffic()
def _build_bezier_curves(node: Node, connections: LaneConnections) \ -> Dict[LaneConnection, Curve]: """Create bezier curves for each lane connection on the node.""" vectors = {w: w.way.direction_from_node(node, w.endpoint).normalized() for w in node.oriented_ways} points = {} for way in node.oriented_ways: vector = vectors[way] right = vector.rotated_right() first = right * LaneRef(*way, 0).distance_from_center() for lane in way.lane_refs(include_opposite=True): points[lane.positive()] = (vector * node.geometry.distance(way) + right * lane.index * LANE_WIDTH + first) crossings = {} for source, dests in connections.items(): for lane1, lane2 in product((source,), dests): point_vector_1 = (points[lane1], vectors[lane1.oriented_way.flipped()]) point_vector_2 = (points[lane2], vectors[lane2.oriented_way]) crossing = line_intersection_safe(*point_vector_1, *point_vector_2) closest = min((point_vector_1, point_vector_2), key=lambda pv, c=crossing: pv[0].distance(c)) if closest[1].dot_product(crossing - closest[0]) >= 0.0: crossing = closest[0] - closest[1] crossings[(lane1, lane2)] = crossing curves = {} node_ref = EntityRef(node) for lanes, crossing in crossings.items(): start, end = map(points.get, lanes) points_ = list(zip(*map(node.position.add, (start, crossing, end)))) curve = bezier.Curve(numpy.asfortranarray(points_), degree=2) curves[lanes] = Curve(node_ref, lanes, curve) return curves
def build(way: Way, endpoint: Endpoint): """Create OrientedWay from a Way instead of a weak reference.""" return OrientedWay(EntityRef(way), endpoint)
def end(self, value): if value is None: self.end_ref = None else: self.end_ref = EntityRef(value)
def start(self, value): if value is None: self.start_ref = None else: self.start_ref = EntityRef(value)
def build(way: Way, endpoint: Endpoint, index: int): """Create LaneRef from a Way instead of a weak reference.""" return LaneRef(EntityRef(way), endpoint, index)