예제 #1
0
    def process(data, request):
        mode = request["mode"]
        if mode == "time":
            return {"time": [data]}
        elif mode == "meta":
            return {"meta": [None]}
        # load the geometry and transform it into the requested projection
        geometry = load_wkt(data["wkt"])
        if data["projection"] != request["projection"]:
            geometry = utils.shapely_transform(
                geometry, data["projection"], request["projection"]
            )

        # take a shortcut when the geometry does not intersect the bbox
        x1, y1, x2, y2 = request["bbox"]
        if (x1 == x2) and (y1 == y2):
            # Don't do box(x1, y1, x2, y2), this gives an invalid geometry.
            bbox_geom = Point(x1, y1)
        else:
            bbox_geom = box(x1, y1, x2, y2)
        if not geometry.intersects(bbox_geom):
            return {
                "values": np.full(
                    (1, request["height"], request["width"]), False, dtype=bool
                ),
                "no_data_value": None,
            }

        return utils.rasterize_geoseries(
            geoseries=GeoSeries([geometry]) if not geometry.is_empty else None,
            bbox=request["bbox"],
            projection=request["projection"],
            height=request["height"],
            width=request["width"],
        )
예제 #2
0
 def process(data, request):
     mode = request["mode"]
     if mode == "time":
         return {"time": [data]}
     elif mode == "meta":
         return {"meta": [None]}
     # load the geometry and transform it into the requested projection
     geometry = load_wkt(data["wkt"])
     if data["projection"] != request["projection"]:
         geometry = utils.shapely_transform(geometry, data["projection"],
                                            request["projection"])
     # take a shortcut when the geometry does not intersect the bbox
     if not geometry.intersects(box(*request["bbox"])):
         return {
             "values":
             np.full((1, request["height"], request["width"]),
                     False,
                     dtype=np.bool),
             "no_data_value":
             None,
         }
     return utils.rasterize_geoseries(
         geoseries=GeoSeries([geometry]) if not geometry.is_empty else None,
         bbox=request["bbox"],
         projection=request["projection"],
         height=request["height"],
         width=request["width"],
     )
예제 #3
0
 def test_shapely_transform(self):
     src_srs = "EPSG:28992"
     dst_srs = "EPSG:4326"
     box28992 = geometry.box(100000, 400000, 200000, 500000)
     box4326 = utils.shapely_transform(box28992,
                                       src_srs=src_srs,
                                       dst_srs=dst_srs)
     assert_almost_equal((5.4, 52.0),
                         list(box4326.centroid.coords)[0],
                         decimal=1)
예제 #4
0
def test_place_reproject(source, center_epsg3857):
    target = 572050, 6812050  # EPSG3857 coords somewhere inside RD validity
    place = raster.Place(source, "EPSG:3857", center_epsg3857, [target])
    x, y = shapely_transform(Point(*target), "EPSG:3857", "EPSG:28992").coords[0]
    values = place.get_data(
        mode="vals",
        bbox=(x - 40, y - 40, x + 40, y + 40),
        projection="EPSG:28992",
        width=8,
        height=8,
    )["values"]
    assert (values == 7).all()
예제 #5
0
def test_rasterize_wkt_attrs():
    geom = box(135004, 455995, 135004.5, 455996)
    view = raster.RasterizeWKT(geom.wkt, "EPSG:28992")
    assert view.projection == "EPSG:28992"
    assert_almost_equal(view.geometry.GetEnvelope(), [135004, 135004.5, 455995, 455996])
    assert view.geometry.GetSpatialReference().IsSame(get_sr("EPSG:28992"))
    assert view.dtype == bool
    assert view.fillvalue is None
    assert_almost_equal(
        view.extent, shapely_transform(geom, "EPSG:28992", "EPSG:4326").bounds
    )
    assert view.timedelta is None
    assert view.period == (datetime(1970, 1, 1), datetime(1970, 1, 1))
예제 #6
0
    def process(data, request):

        mode = request["mode"]
        if mode not in ("extent", "intersects", "centroid"):
            raise ValueError("Unknown mode '{}'".format(mode))

        # load the geometry and transform it into the requested projection
        geometry = load_wkt(data["wkt"])
        if data["projection"] != request["projection"]:
            geometry = utils.shapely_transform(geometry, data["projection"],
                                               request["projection"])

        f = gpd.GeoDataFrame(geometry=[geometry],
                             crs=utils.get_crs(request["projection"]))

        # compute the bounds of each geometry and filter on min_size
        min_size = request.get("min_size")
        if min_size:
            minx, miny, maxx, maxy = geometry.bounds
            if (maxy - miny) < min_size or (maxx - minx) < min_size:
                return {
                    "projection": request["projection"],
                    "features": gpd.GeoDataFrame([]),
                }

        if mode == "intersects":
            if not geometry.intersects(request["geometry"]):
                return {
                    "projection": request["projection"],
                    "features": gpd.GeoDataFrame([]),
                }
            return {"features": f, "projection": request["projection"]}

        elif mode == "centroid":
            with warnings.catch_warnings():  # geopandas warns if in WGS84
                warnings.simplefilter("ignore")
                centroid = geometry.centroid
            if not centroid.intersects(request["geometry"]):
                return {
                    "projection": request["projection"],
                    "features": gpd.GeoDataFrame([]),
                }
            return {"features": f, "projection": request["projection"]}

        elif mode == "extent":
            if not geometry.intersects(request["geometry"]):
                return {"projection": request["projection"], "extent": None}
            return {
                "extent": tuple(geometry.bounds),
                "projection": request["projection"],
            }
예제 #7
0
def test_place_attrs_reproject(source, center_epsg3857):
    # Place should adapt the spatial attributes (extent & geometry)
    place = raster.Place(
        source, "EPSG:3857", center_epsg3857, [(572050, 6812050), (570050, 6811050)]
    )
    # The native projection != store projection:
    assert place.projection is None
    assert place.geo_transform is None

    extent_epsg3857 = 570000, 6811000, 572100, 6812100
    extent_epsg4326 = shapely_transform(
        box(*extent_epsg3857), "EPSG:3857", "EPSG:4326"
    ).bounds
    x1, x2, y1, y2 = place.geometry.GetEnvelope()
    assert (x1, y1, x2, y2) == pytest.approx(extent_epsg3857, rel=1e-4)
    assert place.extent == pytest.approx(extent_epsg4326, rel=1e-4)
def test_rasterize_wkt_vals(vals_request, projection):
    # vals_request has width=4, height=6 and cell size of 0.5
    # we place a rectangle of 2 x 3 with corner at x=1, y=2
    view = raster.RasterizeWKT(
        shapely_transform(box(135000.5, 455998, 135001.5, 455999.5),
                          "EPSG:28992", projection).wkt,
        projection,
    )
    vals_request["start"] = vals_request["stop"] = None
    actual = view.get_data(**vals_request)
    assert actual["values"][0].astype(int).tolist() == [
        [0, 0, 0, 0],
        [0, 1, 1, 0],
        [0, 1, 1, 0],
        [0, 1, 1, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
    ]
예제 #9
0
    def get_sources_and_requests(self, **request):
        mode = request["mode"]
        if mode == "extent":
            return [(self.source, request)]
        if mode != "centroid":
            raise NotImplementedError("Cannot process '{}' mode".format(mode))

        # tile the requested geometry in boxes that have a maximum size
        req_geometry = request["geometry"]
        tile_srs = self.projection
        request_srs = request["projection"]

        # transform the requested geometry into the tile geometry
        geometry = utils.shapely_transform(req_geometry, request_srs, tile_srs)

        x1, y1, x2, y2 = geometry.bounds
        ncols = ceil((x2 - x1) / self.size)
        nrows = ceil((y2 - y1) / self.size)

        if ncols <= 1 and nrows <= 1:
            return [(self.source, request)]  # shortcut

        # resize the tiles so that all tiles have similar dimensions
        size_x = (x2 - x1) / ncols
        size_y = (y2 - y1) / nrows
        tiles = [
            box(
                x1 + i * size_x,
                y1 + j * size_y,
                x1 + (i + 1) * size_x,
                y1 + (j + 1) * size_y,
            )
            for i, j in product(range(ncols), range(nrows))
        ]

        # intersect the tiles with the requested geometry
        series = gpd.GeoSeries(tiles).intersection(geometry)

        # drop empty tiles
        series = series[~series.is_empty]

        source = self.source
        request["projection"] = tile_srs
        return [(source, {**request, "geometry": tile}) for tile in series]
예제 #10
0
def test_place_attrs(source, center):
    place = raster.Place(source, "EPSG:28992", center, [(50, 50)])

    # Place should not adapt these attributes:
    assert place.period == source.period
    assert place.timedelta == source.timedelta
    assert place.dtype == source.dtype
    assert place.fillvalue == source.fillvalue

    # If the place projection equals the store projection:
    assert place.projection == source.projection
    assert place.geo_transform == source.geo_transform

    extent_epsg28992 = (0, 0, 100, 100)
    extent_epsg4326 = shapely_transform(
        box(*extent_epsg28992), "EPSG:28992", "EPSG:4326"
    ).bounds
    x1, x2, y1, y2 = place.geometry.GetEnvelope()
    assert (x1, y1, x2, y2) == extent_epsg28992
    assert place.extent == pytest.approx(extent_epsg4326, rel=1e-4)
예제 #11
0
 def extent(self):
     return tuple(
         utils.shapely_transform(load_wkt(self.wkt), self.projection,
                                 "EPSG:4326").bounds)
예제 #12
0
 def test_shapely_transform_invalid(self):
     src_srs = "EPSG:4326"
     dst_srs = "EPSG:28992"
     box4326 = geometry.box(100000, 400000, 200000, 500000)
     with pytest.raises(utils.TransformException):
         utils.shapely_transform(box4326, src_srs=src_srs, dst_srs=dst_srs)
예제 #13
0
    def get_sources_and_requests(self, **request):
        if request["mode"] != "vals":
            return ({"mode": request["mode"]}, None), (self.store, request)

        # transform the anchor and coordinates into the requested projection
        anchor = shapely_transform(
            Point(self.anchor), self.place_projection, request["projection"]
        ).coords[0]
        coordinates = [
            shapely_transform(
                Point(coord), self.place_projection, request["projection"]
            ).coords[0]
            for coord in self.coordinates
        ]

        # transform the source's extent
        extent_geometry = self.store.geometry
        if extent_geometry is None:
            # no geometry means: no data
            return (({"mode": "null"}, None),)
        sr = get_sr(request["projection"])
        if not extent_geometry.GetSpatialReference().IsSame(sr):
            extent_geometry = extent_geometry.Clone()
            extent_geometry.TransformTo(sr)
        xmin, xmax, ymin, ymax = extent_geometry.GetEnvelope()

        # compute the requested cellsize
        x1, y1, x2, y2 = request["bbox"]
        size_x = (x2 - x1) / request["width"]
        size_y = (y2 - y1) / request["height"]

        # point requests: never request the full source extent
        if size_x > 0 and size_y > 0:
            # check what the full source extent would require
            full_height = math.ceil((ymax - ymin) / size_y)
            full_width = math.ceil((xmax - xmin) / size_x)
            if full_height * full_width <= request["width"] * request["height"]:
                _request = request.copy()
                _request["width"] = full_width
                _request["height"] = full_height
                _request["bbox"] = (
                    xmin,
                    ymin,
                    xmin + full_width * size_x,
                    ymin + full_height * size_y,
                )
                process_kwargs = {
                    "mode": "warp",
                    "anchor": anchor,
                    "coordinates": coordinates,
                    "src_bbox": _request["bbox"],
                    "dst_bbox": request["bbox"],
                    "cellsize": (size_x, size_y),
                    "statistic": self.statistic,
                }
                return [(process_kwargs, None), (self.store, _request)]

        # generate a new (backwards shifted) bbox for each coordinate
        sources_and_requests = []
        filtered_coordinates = []
        for _x, _y in coordinates:
            bbox = [
                x1 + anchor[0] - _x,
                y1 + anchor[1] - _y,
                x2 + anchor[0] - _x,
                y2 + anchor[1] - _y,
            ]
            # check the overlap with the source's extent
            # Note that raster cells are defined [xmin, xmax) and (ymin, ymax]
            # so points precisely at xmax or ymin certainly do not have data.
            if bbox[0] >= xmax or bbox[1] > ymax or bbox[2] < xmin or bbox[3] <= ymin:
                continue
            filtered_coordinates.append((_x, _y))
            _request = request.copy()
            _request["bbox"] = bbox
            sources_and_requests.append((self.store, _request))
        if len(sources_and_requests) == 0:
            # No coordinates inside: we still need to return an array
            # of the correct shape. Send a time request to get the depth.
            _request = request.copy()
            _request["mode"] = "time"
            process_kwargs = {
                "mode": "empty",
                "dtype": self.dtype,
                "fillvalue": self.fillvalue,
                "width": request["width"],
                "height": request["height"],
                "statistic": self.statistic,
            }
            return [(process_kwargs, None), (self.store, _request)]
        process_kwargs = {"mode": "group", "statistic": self.statistic}
        return [(process_kwargs, None)] + sources_and_requests
예제 #14
0
def center_epsg3857(center):
    yield shapely_transform(Point(*center), "EPSG:28992", "EPSG:3857").coords[0]