def process(data, kwargs): if "features" in data: if len(data["features"]) == 0: return data req_srs = data["projection"] buf_srs = kwargs["buf_srs"] features = data["features"].set_geometry( data["features"].geometry.apply( shapely_transform, args=(req_srs, buf_srs)).buffer( distance=kwargs["distance"], resolution=kwargs["resolution"]).apply( shapely_transform, args=(buf_srs, req_srs))) return {"features": features, "projection": req_srs} elif "extent" in data: if not data["extent"]: return data req_srs = data["projection"] buf_srs = kwargs["buf_srs"] distance = kwargs["distance"] extent = transform_extent(data["extent"], req_srs, buf_srs) extent = Extent(extent, buf_srs).buffered(distance).bbox extent = transform_extent(extent, buf_srs, req_srs) return {"extent": extent, "projection": req_srs} else: raise NotImplementedError("Dunno this mode!")
def test_transform_extent(self, shapely_transform): src_srs = "some_fiona_crs" dst_srs = "another_fiona_crs" extent = 0, 0, 1, 1 expected = 2, 2, 3, 3 shapely_transform.return_value = geometry.box(*expected) result = utils.transform_extent(extent, src_srs=src_srs, dst_srs=dst_srs) shapely_transform.assert_called_with( geometry.box(*extent), src_srs=src_srs, dst_srs=dst_srs ) self.assertEqual(expected, result)
def get_sources_and_requests(self, **request): if request.get("mode") == "extent": return [(self.source, request), (None, None), ({ "mode": "extent" }, None)] req_srs = request["projection"] agg_srs = self.projection # acquire the extent of the geometry data extent_request = {**request, "mode": "extent"} extent = self.source.get_data(**extent_request)["extent"] if extent is None: # make sources_and_request so that we get an empty result return [ (None, None), (None, None), ({ "empty": True, "projection": req_srs }, None), ] # transform the extent into the projection in which we aggregate x1, y1, x2, y2 = utils.transform_extent(extent, req_srs, agg_srs) # estimate the amount of required pixels required_pixels = int(((x2 - x1) * (y2 - y1)) / (self.pixel_size**2)) # in case this request is too large, we adapt pixel size max_pixels = self.max_pixels if max_pixels is None: max_pixels = config.get("geomodeling.raster-limit") pixel_size = self.pixel_size if required_pixels > max_pixels and self.auto_pixel_size: # adapt with integer multiples of pixel_size pixel_size *= ceil(sqrt(required_pixels / max_pixels)) elif required_pixels > max_pixels: raise RuntimeError( "The required raster size for the aggregation exceeded " "the maximum ({} > {})".format(required_pixels, max_pixels)) # snap the extent to (0, 0) to prevent subpixel shifts x1 = floor(x1 / pixel_size) * pixel_size y1 = floor(y1 / pixel_size) * pixel_size x2 = ceil(x2 / pixel_size) * pixel_size y2 = ceil(y2 / pixel_size) * pixel_size # compute the width and height width = max(int((x2 - x1) / pixel_size), 1) height = max(int((y2 - y1) / pixel_size), 1) raster_request = { "mode": "vals", "projection": agg_srs, "start": request.get("start"), "stop": request.get("stop"), "aggregation": None, # TODO "bbox": (x1, y1, x2, y2), "width": width, "height": height, } process_kwargs = { "mode": request.get("mode", "intersects"), "pixel_size": self.pixel_size, "agg_srs": agg_srs, "req_srs": req_srs, "actual_pixel_size": pixel_size, "statistic": self.statistic, "result_column": self.column_name, "agg_bbox": (x1, y1, x2, y2), } return [ (self.source, request), (self.raster, raster_request), (process_kwargs, None), ]