Exemple #1
0
        def to_scenario_via(
            vias: Tuple[SSVia, ...], road_map: RoadMap
        ) -> Tuple[Via, ...]:
            s_vias = []
            for via in vias:
                road = road_map.road_by_id(via.road_id)
                lane = road.lane_at_index(via.lane_index)
                lane_width = lane.width_at_offset(via.lane_offset)
                hit_distance = (
                    via.hit_distance if via.hit_distance > 0 else lane_width / 2
                )
                via_position = lane.from_lane_coord(RefLinePoint(via.lane_offset))

                s_vias.append(
                    Via(
                        lane_id=lane.lane_id,
                        lane_index=via.lane_index,
                        road_id=via.road_id,
                        position=tuple(via_position[:2]),
                        hit_distance=hit_distance,
                        required_speed=via.required_speed,
                    )
                )

            return tuple(s_vias)
Exemple #2
0
 def to_position_and_heading(road_id, lane_index, offset, road_map):
     road = road_map.road_by_id(road_id)
     lane = road.lane_at_index(lane_index)
     offset = resolve_offset(offset, lane.length)
     position = lane.from_lane_coord(RefLinePoint(s=offset))
     lane_vector = lane.vector_at_offset(offset)
     heading = vec_to_radians(lane_vector[:2])
     return position, Heading(heading)
Exemple #3
0
        def split_lane_shape_at_offset(
            lane_shape: Polygon, lane: RoadMap.Lane, offset: float
        ):
            # XXX: generalize to n-dim
            width_2 = lane.width_at_offset(offset)
            point = np.array(lane.from_lane_coord(RefLinePoint(offset)))[:2]
            lane_vec = lane.vector_at_offset(offset)[:2]

            perp_vec_right = rotate_around_point(lane_vec, np.pi / 2, origin=(0, 0))
            perp_vec_right = (
                perp_vec_right / max(np.linalg.norm(perp_vec_right), 1e-3) * width_2
                + point
            )

            perp_vec_left = rotate_around_point(lane_vec, -np.pi / 2, origin=(0, 0))
            perp_vec_left = (
                perp_vec_left / max(np.linalg.norm(perp_vec_left), 1e-3) * width_2
                + point
            )

            split_line = LineString([perp_vec_left, perp_vec_right])
            return split(lane_shape, split_line)
Exemple #4
0
    def to_geometry(self, road_map: RoadMap) -> Polygon:
        """Generates a map zone over a stretch of the given lanes."""

        def resolve_offset(offset, geometry_length, lane_length):
            if offset == "base":
                return 0
            # push off of end of lane
            elif offset == "max":
                return lane_length - geometry_length
            elif offset == "random":
                return random.uniform(0, lane_length - geometry_length)
            else:
                return float(offset)

        def pick_remaining_shape_after_split(geometry_collection, expected_point):
            lane_shape = geometry_collection
            if not isinstance(lane_shape, GeometryCollection):
                return lane_shape

            # For simplicity, we only deal w/ the == 1 or 2 case
            if len(lane_shape.geoms) not in {1, 2}:
                return None

            if len(lane_shape.geoms) == 1:
                return lane_shape.geoms[0]

            # We assume that there are only two split shapes to choose from
            keep_index = 0
            if lane_shape.geoms[1].minimum_rotated_rectangle.contains(expected_point):
                # 0 is the discard piece, keep the other
                keep_index = 1

            lane_shape = lane_shape.geoms[keep_index]

            return lane_shape

        def split_lane_shape_at_offset(
            lane_shape: Polygon, lane: RoadMap.Lane, offset: float
        ):
            # XXX: generalize to n-dim
            width_2 = lane.width_at_offset(offset)
            point = np.array(lane.from_lane_coord(RefLinePoint(offset)))[:2]
            lane_vec = lane.vector_at_offset(offset)[:2]

            perp_vec_right = rotate_around_point(lane_vec, np.pi / 2, origin=(0, 0))
            perp_vec_right = (
                perp_vec_right / max(np.linalg.norm(perp_vec_right), 1e-3) * width_2
                + point
            )

            perp_vec_left = rotate_around_point(lane_vec, -np.pi / 2, origin=(0, 0))
            perp_vec_left = (
                perp_vec_left / max(np.linalg.norm(perp_vec_left), 1e-3) * width_2
                + point
            )

            split_line = LineString([perp_vec_left, perp_vec_right])
            return split(lane_shape, split_line)

        lane_shapes = []
        road_id, lane_idx, offset = self.start
        road = road_map.road_by_id(road_id)
        buffer_from_ends = 1e-6
        for lane_idx in range(lane_idx, lane_idx + self.n_lanes):
            lane = road.lane_at_index(lane_idx)
            lane_length = lane.length
            geom_length = self.length

            if geom_length > lane_length:
                logging.debug(
                    f"Geometry is too long={geom_length} with offset={offset} for "
                    f"lane={lane.lane_id}, using length={lane_length} instead"
                )
                geom_length = lane_length

            assert geom_length > 0  # Geom length is negative

            lane_offset = resolve_offset(offset, geom_length, lane_length)
            lane_offset += buffer_from_ends
            width = lane.width_at_offset(lane_offset)
            lane_shape = lane.shape(0.3, width)

            geom_length = max(geom_length - buffer_from_ends, buffer_from_ends)
            lane_length = max(lane_length - buffer_from_ends, buffer_from_ends)

            min_cut = min(lane_offset, lane_length)
            # Second cut takes into account shortening of geometry by `min_cut`.
            max_cut = min(min_cut + geom_length, lane_length)

            midpoint = Point(
                *lane.from_lane_coord(RefLinePoint(s=lane_offset + geom_length * 0.5))
            )

            lane_shape = split_lane_shape_at_offset(lane_shape, lane, min_cut)
            lane_shape = pick_remaining_shape_after_split(lane_shape, midpoint)
            if lane_shape is None:
                continue

            lane_shape = split_lane_shape_at_offset(
                lane_shape,
                lane,
                max_cut,
            )
            lane_shape = pick_remaining_shape_after_split(lane_shape, midpoint)
            if lane_shape is None:
                continue

            lane_shapes.append(lane_shape)

        geom = unary_union(MultiPolygon(lane_shapes))
        return geom