예제 #1
0
    def to_geometry(self, road_network: SumoRoadNetwork) -> Polygon:
        def resolve_offset(offset, geometry_length, lane_length,
                           buffer_from_ends):
            if offset == "base" or offset == 0:
                return buffer_from_ends
            # push off of end of lane
            elif offset == "max":
                return lane_length - geometry_length - buffer_from_ends
            elif offset == "random":
                return random.uniform(
                    0, lane_length - geometry_length - buffer_from_ends)
            else:
                return float(offset)

        lane_shapes = []
        edge_id, lane_idx, offset = self.start
        edge = road_network.edge_by_id(edge_id)
        for lane_idx in range(lane_idx, lane_idx + self.n_lanes):
            lane = edge.getLanes()[lane_idx]
            lane_length = lane.getLength()
            geom_length = max(self.length - 1e-6, 1e-6)

            assert lane_length > geom_length  # Geom is too long for lane
            assert geom_length > 0  # Geom length is negative

            lane_shape = SumoRoadNetwork.buffered_lane_or_edge(
                lane, width=lane.getWidth() + 0.3)

            min_cut = resolve_offset(offset, geom_length, lane_length, 1e-6)
            # Second cut takes into account shortening of geometry by `min_cut`.
            max_cut = min(min_cut + geom_length, lane_length - min_cut - 1e-6)

            lane_shape = road_network.split_lane_shape_at_offset(
                Polygon(lane_shape), lane, min_cut)

            if isinstance(lane_shape, GeometryCollection):
                if len(lane_shape) < 2:
                    break
                lane_shape = lane_shape[1]

            lane_shape = road_network.split_lane_shape_at_offset(
                lane_shape,
                lane,
                max_cut,
            )[0]
            lane_shapes.append(lane_shape)

        geom = unary_union(MultiPolygon(lane_shapes))
        return geom
예제 #2
0
    def to_geometry(self, road_network: SumoRoadNetwork) -> Polygon:
        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, length, lane):
            lane_shape = geometry_collection
            if not isinstance(lane_shape, GeometryCollection):
                return lane_shape

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

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

            expected_bbox_area = lane.getWidth() * length
            keep_index = 0
            if (lane_shape[0].minimum_rotated_rectangle.area - expected_bbox_area) < (
                lane_shape[1].minimum_rotated_rectangle.area - expected_bbox_area
            ):
                # 0 is the discard piece, keep the other
                keep_index = 1
            lane_shape = lane_shape[keep_index]

            return lane_shape

        lane_shapes = []
        edge_id, lane_idx, offset = self.start
        edge = road_network.edge_by_id(edge_id)
        buffer_from_ends = 1e-6
        for lane_idx in range(lane_idx, lane_idx + self.n_lanes):
            lane = edge.getLanes()[lane_idx]
            lane_length = lane.getLength()
            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.getID()}, using length={lane_length} instead"
                )
                geom_length = lane_length

            assert geom_length > 0  # Geom length is negative

            lane_shape = SumoRoadNetwork._buffered_lane_or_edge(
                lane, width=lane.getWidth() + 0.3
            )

            lane_offset = resolve_offset(offset, geom_length, lane_length)
            lane_offset += buffer_from_ends
            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 - min_cut)

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

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

            lane_shapes.append(lane_shape)

        geom = unary_union(MultiPolygon(lane_shapes))
        return geom