def test_geobox_simple():
    t = geometry.GeoBox(4000, 4000,
                        Affine(0.00025, 0.0, 151.0, 0.0, -0.00025, -29.0),
                        epsg4326)

    expect_lon = np.asarray([151.000125, 151.000375, 151.000625, 151.000875, 151.001125,
                             151.001375, 151.001625, 151.001875, 151.002125, 151.002375])

    expect_lat = np.asarray([-29.000125, -29.000375, -29.000625, -29.000875, -29.001125,
                             -29.001375, -29.001625, -29.001875, -29.002125, -29.002375])
    expect_resolution = np.asarray([-0.00025, 0.00025])

    assert t.coordinates['latitude'].values.shape == (4000,)
    assert t.coordinates['longitude'].values.shape == (4000,)

    np.testing.assert_almost_equal(t.resolution, expect_resolution)
    np.testing.assert_almost_equal(t.coords['latitude'].values[:10], expect_lat)
    np.testing.assert_almost_equal(t.coords['longitude'].values[:10], expect_lon)

    assert (t == "some random thing") is False

    # ensure GeoBox accepts string CRS
    assert isinstance(geometry.GeoBox(4000, 4000,
                                      Affine(0.00025, 0.0, 151.0, 0.0, -0.00025, -29.0),
                                      'epsg:4326').crs, CRS)

    # Check GeoBox class is hashable
    t_copy = GeoBox(t.width, t.height, t.transform, t.crs)
    t_other = GeoBox(t.width+1, t.height, t.transform, t.crs)
    assert t_copy is not t
    assert t == t_copy
    assert len(set([t, t, t_copy])) == 1
    assert len(set([t, t_copy, t_other])) == 2
Exemple #2
0
    def __call__(self, product, time, group_by) -> Tile:
        # Do for a specific poly whose boundary is known
        output_crs = CRS(self.storage['crs'])
        filtered_item = [
            'geopolygon', 'lon', 'lat', 'longitude', 'latitude', 'x', 'y'
        ]
        filtered_dict = {
            k: v
            for k, v in filter(lambda t: t[0] in filtered_item,
                               self.input_region.items())
        }
        if 'feature_id' in self.input_region:
            filtered_dict['geopolygon'] = Geometry(
                self.input_region['geom_feat'],
                CRS(self.input_region['crs_txt']))
            geopoly = filtered_dict['geopolygon']
        else:
            geopoly = query_geopolygon(**self.input_region)
        datasets = self.dc.find_datasets(product=product,
                                         time=time,
                                         group_by=group_by,
                                         **filtered_dict)
        group_by = query_group_by(group_by=group_by)
        sources = self.dc.group_datasets(datasets, group_by)
        output_resolution = [
            self.storage['resolution'][dim] for dim in output_crs.dimensions
        ]
        geopoly = geopoly.to_crs(output_crs)
        geobox = GeoBox.from_geopolygon(geopoly, resolution=output_resolution)

        return Tile(sources, geobox)
Exemple #3
0
    def fetch(self, grouped: VirtualDatasetBox,
              **load_settings: Dict[str, Any]) -> xarray.Dataset:
        """ Convert grouped datasets to `xarray.Dataset`. """

        load_keys = self._LOAD_KEYS - {'measurements'}
        merged = merge_search_terms(select_keys(self, load_keys),
                                    select_keys(load_settings, load_keys))

        product = grouped.product_definitions[self._product]

        if 'measurements' in self and 'measurements' in load_settings:
            for measurement in load_settings['measurements']:
                self._assert(
                    measurement in self['measurements'],
                    '{} not found in {}'.format(measurement, self._product))

        measurement_dicts = self.output_measurements(
            grouped.product_definitions, load_settings.get('measurements'))

        if grouped.load_natively:
            canonical_names = [
                product.canonical_measurement(measurement)
                for measurement in measurement_dicts
            ]
            dataset_geobox = geobox_union_conservative([
                native_geobox(ds,
                              measurements=canonical_names,
                              basis=merged.get('like'))
                for ds in grouped.box.sum().item()
            ])

            if grouped.geopolygon is not None:
                reproject_roi = compute_reproject_roi(
                    dataset_geobox,
                    GeoBox.from_geopolygon(
                        grouped.geopolygon,
                        crs=dataset_geobox.crs,
                        align=dataset_geobox.alignment,
                        resolution=dataset_geobox.resolution))

                self._assert(reproject_roi.is_st,
                             "native load is not axis-aligned")
                self._assert(numpy.isclose(reproject_roi.scale, 1.0),
                             "native load should not require scaling")

                geobox = dataset_geobox[reproject_roi.roi_src]
            else:
                geobox = dataset_geobox
        else:
            geobox = grouped.geobox

        result = Datacube.load_data(grouped.box,
                                    geobox,
                                    list(measurement_dicts.values()),
                                    fuse_func=merged.get('fuse_func'),
                                    dask_chunks=merged.get('dask_chunks'),
                                    resampling=merged.get(
                                        'resampling', 'nearest'))

        return result
Exemple #4
0
def assert_same_read_results(source, dst_shape, dst_dtype, dst_transform,
                             dst_nodata, dst_projection, resampling):
    expected = np.empty(dst_shape, dtype=dst_dtype)
    with source.open() as src:
        rasterio.warp.reproject(src.data,
                                expected,
                                src_transform=src.transform,
                                src_crs=str(src.crs),
                                src_nodata=src.nodata,
                                dst_transform=dst_transform,
                                dst_crs=str(dst_projection),
                                dst_nodata=dst_nodata,
                                resampling=resampling)

    result = np.full(dst_shape, dst_nodata, dtype=dst_dtype)
    H, W = dst_shape
    dst_gbox = GeoBox(W, H, dst_transform, dst_projection)
    with datacube.set_options(reproject_threads=1):
        with source.open() as rdr:
            read_time_slice(rdr,
                            result,
                            dst_gbox,
                            dst_nodata=dst_nodata,
                            resampling=resampling)

    assert np.isclose(result, expected, atol=0, rtol=0.05,
                      equal_nan=True).all()
    return result
Exemple #5
0
def make_sample_netcdf(tmpdir):
    """Make a test Geospatial NetCDF file, 4000x4000 int16 random data, in a variable named `sample`.
    Return the GDAL access string."""
    sample_nc = str(tmpdir.mkdir('netcdfs').join('sample.nc'))
    geobox = GeoBox(4000,
                    4000,
                    affine=Affine(25.0, 0.0, 1200000, 0.0, -25.0, -4200000),
                    crs=epsg3577)

    sample_data = np.random.randint(10000, size=(4000, 4000), dtype=np.int16)

    variables = {
        'sample':
        Variable(sample_data.dtype,
                 nodata=-999,
                 dims=geobox.dimensions,
                 units=1)
    }
    nco = create_netcdf_storage_unit(sample_nc,
                                     geobox.crs,
                                     geobox.coordinates,
                                     variables=variables,
                                     variable_params={})

    nco['sample'][:] = sample_data

    nco.close()

    return 'NetCDF:"%s":sample' % sample_nc, geobox, sample_data
Exemple #6
0
def rasterfile_to_xarray(file, geobox=None, name=None, nodata=None):
    """Blit like"""
    with rasterio.open(file) as src:
        assert src.indexes == (1, )  # assume single band
        if geobox is None:
            from datacube.utils.geometry import GeoBox, CRS

            # TODO: fix this heinousness
            global crs
            global affine
            crs = src.crs
            affine = src.transform

            geobox = GeoBox(
                width=src.width,
                height=src.height,
                affine=src.
                affine,  # .transform is a list, .affine is an object
                crs=CRS(src.crs.wkt))
            array = src.read(1)
        else:
            band = rasterio.band(
                src, 1)  # do not attempt to read entire extent into memory
            array = np.empty((geobox.height, geobox.width), dtype=band.dtype)
            rasterio.warp.reproject(source=band,
                                    destination=array,
                                    dst_crs=geobox.crs.crs_str,
                                    dst_transform=geobox.affine,
                                    dst_nodata=nodata)
    return numpy_to_xarray(array, geobox, name)
Exemple #7
0
    def internal_make_sample_geotiff(nodata=-999):
        sample_geotiff = str(tmpdir.mkdir('tiffs').join('sample.tif'))

        geobox = GeoBox(100,
                        200,
                        affine=Affine(25.0, 0.0, 0, 0.0, -25.0, 0),
                        crs=epsg3577)
        if np.isnan(nodata):
            out_dtype = 'float64'
            sample_data = 10000 * np.random.random_sample(size=geobox.shape)
        else:
            out_dtype = 'int16'
            sample_data = np.random.randint(10000,
                                            size=geobox.shape,
                                            dtype=out_dtype)
        rio_args = {
            'height': geobox.height,
            'width': geobox.width,
            'count': 1,
            'dtype': out_dtype,
            'crs': 'EPSG:3577',
            'transform': geobox.transform,
            'nodata': nodata
        }
        with rasterio.open(sample_geotiff, 'w', driver='GTiff',
                           **rio_args) as dst:
            dst.write(sample_data, 1)

        return sample_geotiff, geobox, sample_data
Exemple #8
0
    def __call__(self, index, product, time, group_by) -> Tile:
        # Do for a specific poly whose boundary is known
        output_crs = CRS(self.storage['crs'])
        filtered_items = [
            'geopolygon', 'lon', 'lat', 'longitude', 'latitude', 'x', 'y'
        ]
        filtered_dict = {
            k: v
            for k, v in self.input_region.items() if k in filtered_items
        }
        if self.feature is not None:
            filtered_dict['geopolygon'] = self.feature.geopolygon
            geopoly = filtered_dict['geopolygon']
        else:
            geopoly = query_geopolygon(**self.input_region)

        dc = Datacube(index=index)
        datasets = dc.find_datasets(product=product,
                                    time=time,
                                    group_by=group_by,
                                    **filtered_dict)
        group_by = query_group_by(group_by=group_by)
        sources = dc.group_datasets(datasets, group_by)
        output_resolution = [
            self.storage['resolution'][dim] for dim in output_crs.dimensions
        ]
        geopoly = geopoly.to_crs(output_crs)
        geobox = GeoBox.from_geopolygon(geopoly, resolution=output_resolution)

        return Tile(sources, geobox)
def mk_sample_xr_dataset(crs="EPSG:3578",
                         shape=(33, 74),
                         resolution=None,
                         xy=(0, 0),
                         time='2020-02-13T11:12:13.1234567Z',
                         name='band',
                         dtype='int16',
                         nodata=-999,
                         units='1'):
    """ Note that resolution is in Y,X order to match that of GeoBox.

        shape (height, width)
        resolution (y: float, x: float) - in YX, to match GeoBox/shape notation

        xy (x: float, y: float) -- location of the top-left corner of the top-left pixel in CRS units
    """

    if isinstance(crs, str):
        crs = CRS(crs)

    if resolution is None:
        resolution = (-10, 10) if crs is None or crs.projected else (-0.01, 0.01)

    t_coords = {}
    if time is not None:
        t_coords['time'] = mk_time_coord([time])

    transform = Affine.translation(*xy)*Affine.scale(*resolution[::-1])
    h, w = shape
    geobox = GeoBox(w, h, transform, crs)

    return Datacube.create_storage(t_coords, geobox, [Measurement(name=name, dtype=dtype, nodata=nodata, units=units)])
Exemple #10
0
def compute_native_load_geobox(dst_geobox: GeoBox,
                               ds: Dataset,
                               band: str,
                               buffer: Optional[float] = None) -> GeoBox:
    """
    Compute area of interest for a given Dataset given query.

    Take native projection and resolution from ``ds, band`` pair and compute
    region in that projection that fully encloses footprint of the
    ``dst_geobox`` with some padding. Construct GeoBox that encloses that
    region fully with resolution/pixel alignment copied from supplied band.

    :param dst_geobox:
    :param ds: Sample dataset (only resolution and projection is used, not footprint)
    :param band: Reference band to use (resolution of output GeoBox will match resolution of this band)
    :param buffer: Buffer in units of CRS of ``ds`` (meters usually), default is 10 pixels worth
    """
    native: GeoBox = native_geobox(ds, basis=band)
    if buffer is None:
        buffer = 10 * cast(float, max(map(abs,
                                          native.resolution)))  # type: ignore

    assert native.crs is not None
    return GeoBox.from_geopolygon(
        dst_geobox.extent.to_crs(native.crs).buffer(buffer),
        crs=native.crs,
        resolution=native.resolution,
        align=native.alignment,
    )
def test_read_with_reproject(tmpdir):
    from datacube.testutils import mk_test_image
    from datacube.testutils.io import write_gtiff
    from pathlib import Path

    pp = Path(str(tmpdir))

    xx = mk_test_image(128, 64, nodata=None)
    assert (xx != -999).all()
    tile = AlbersGS.tile_geobox((17, -40))[:64, :128]

    mm = write_gtiff(pp / 'tst-read-with-reproject-128x64-int16.tif',
                     xx,
                     crs=str(tile.crs),
                     resolution=tile.resolution[::-1],
                     offset=tile.transform * (0, 0),
                     nodata=-999)
    assert mm.gbox == tile

    def _read(gbox,
              resampling='nearest',
              fallback_nodata=None,
              dst_nodata=-999):
        with RasterFileDataSource(mm.path, 1,
                                  nodata=fallback_nodata).open() as rdr:
            yy = np.full(gbox.shape, dst_nodata, dtype=rdr.dtype)
            roi = read_time_slice(rdr, yy, gbox, resampling, dst_nodata)
            return yy, roi

    gbox = gbx.pad(mm.gbox, 10)
    gbox = gbx.zoom_out(gbox, 0.873)
    yy, roi = _read(gbox)

    assert roi[0].start > 0 and roi[1].start > 0
    assert (yy[0] == -999).all()

    yy_expect, _ = rio_slurp(mm.path, gbox)
    np.testing.assert_array_equal(yy, yy_expect)

    gbox = gbx.zoom_out(mm.gbox[3:-3, 10:-10], 2.1)
    yy, roi = _read(gbox)

    assert roi_shape(roi) == gbox.shape
    assert not (yy == -999).any()

    gbox = GeoBox.from_geopolygon(mm.gbox.extent.to_crs(epsg3857).buffer(50),
                                  resolution=mm.gbox.resolution)

    assert gbox.extent.contains(mm.gbox.extent.to_crs(epsg3857))
    assert gbox.crs != mm.gbox.crs
    yy, roi = _read(gbox)
    assert roi[0].start > 0 and roi[1].start > 0
    assert (yy[0] == -999).all()

    gbox = gbx.zoom_out(gbox, 4)
    yy, roi = _read(gbox, resampling='average')
    nvalid = (yy != -999).sum()
    nempty = (yy == -999).sum()
    assert nvalid > nempty
Exemple #12
0
def _read_from_source(source, dest, dst_transform, dst_nodata, dst_projection, resampling):
    """
    Adapt old signature to new function, so that we can keep old tests at least for now
    """
    H, W = dest.shape
    gbox = GeoBox(W, H, dst_transform, dst_projection)
    dest[:] = dst_nodata  # new code assumes pre-populated image
    with source.open() as rdr:
        read_time_slice(rdr, dest, gbox, resampling=resampling, dst_nodata=dst_nodata)
Exemple #13
0
def test_gbox_tiles():
    A = Affine.identity()
    H, W = (300, 200)
    h, w = (10, 20)
    gbox = GeoBox(W, H, A, epsg3857)
    tt = gbx.GeoboxTiles(gbox, (h, w))
    assert tt.shape == (300/10, 200/20)
    assert tt.base is gbox

    assert tt[0, 0] == gbox[0:h, 0:w]
    assert tt[0, 1] == gbox[0:h, w:w+w]

    assert tt[0, 0] is tt[0, 0]  # Should cache exact same object
    assert tt[4, 1].shape == (h, w)

    H, W = (11, 22)
    h, w = (10, 9)
    gbox = GeoBox(W, H, A, epsg3857)
    tt = gbx.GeoboxTiles(gbox, (h, w))
    assert tt.shape == (2, 3)
    assert tt[1, 2] == gbox[10:11, 18:22]

    for idx in [tt.shape, (-1, 0), (0, -1), (-33, 1)]:
        with pytest.raises(IndexError):
            tt[idx]

        with pytest.raises(IndexError):
            tt.chunk_shape(idx)

    cc = np.zeros(tt.shape, dtype='int32')
    for idx in tt.tiles(gbox.extent):
        cc[idx] += 1
    np.testing.assert_array_equal(cc, np.ones(tt.shape))

    assert list(tt.tiles(gbox[:h, :w].extent)) == [(0, 0)]

    (H, W) = (11, 22)
    (h, w) = (10, 20)
    tt = gbx.GeoboxTiles(GeoBox(W, H, A, epsg3857), (h, w))
    assert tt.chunk_shape((0, 0)) == (h, w)
    assert tt.chunk_shape((0, 1)) == (h, 2)
    assert tt.chunk_shape((1, 1)) == (1, 2)
    assert tt.chunk_shape((1, 0)) == (1, w)
Exemple #14
0
    def geobox(self):
        """Object geobox

        Returns:
            datacube.utils.geometry.GeoBox
        """
        return GeoBox(width=self.array.shape[2],
                      height=self.array.shape[1],
                      affine=self.affine,
                      crs=CRS(self.crs))
Exemple #15
0
def test_gen_test_image_xy():
    gbox = GeoBox(3, 7, Affine.translation(10, 1000), epsg3857)

    xy, denorm = gen_test_image_xy(gbox, 'float64')
    assert xy.dtype == 'float64'
    assert xy.shape == (2, ) + gbox.shape

    x, y = denorm(xy)
    x_, y_ = xy_from_gbox(gbox)

    np.testing.assert_almost_equal(x, x_)
    np.testing.assert_almost_equal(y, y_)

    xy, denorm = gen_test_image_xy(gbox, 'uint16')
    assert xy.dtype == 'uint16'
    assert xy.shape == (2, ) + gbox.shape

    x, y = denorm(xy[0], xy[1])
    assert x.shape == xy.shape[1:]
    assert y.shape == xy.shape[1:]
    assert x.dtype == 'float64'

    x_, y_ = xy_from_gbox(gbox)

    np.testing.assert_almost_equal(x, x_, 4)
    np.testing.assert_almost_equal(y, y_, 4)

    for dt in ('int8', np.int16, np.dtype(np.uint64)):
        xy, _ = gen_test_image_xy(gbox, dt)
        assert xy.dtype == dt

    # check no-data
    xy, denorm = gen_test_image_xy(gbox, 'float32')
    assert xy.dtype == 'float32'
    assert xy.shape == (2, ) + gbox.shape
    xy[0, 0, :] = np.nan
    xy[1, 1, :] = np.nan
    xy_ = denorm(xy, nodata=np.nan)
    assert np.isnan(xy_[:, :2]).all()
    np.testing.assert_almost_equal(xy_[0][2:], x_[2:], 6)
    np.testing.assert_almost_equal(xy_[1][2:], y_[2:], 6)

    xy, denorm = gen_test_image_xy(gbox, 'int16')
    assert xy.dtype == 'int16'
    assert xy.shape == (2, ) + gbox.shape
    xy[0, 0, :] = -999
    xy[1, 1, :] = -999
    xy_ = denorm(xy, nodata=-999)
    assert np.isnan(xy_[:, :2]).all()
    np.testing.assert_almost_equal(xy_[0][2:], x_[2:], 4)
    np.testing.assert_almost_equal(xy_[1][2:], y_[2:], 4)

    # call without arguments should return linear mapping
    A = denorm()
    assert isinstance(A, Affine)
Exemple #16
0
def custom_native_geobox(ds, measurements=None, basis=None):
    metadata = ds.metadata_doc['image']['bands']['nbart_swir_3']['info']
    geotransform = metadata['geotransform']
    crs = CRS(
        ds.metadata_doc['grid_spatial']['projection']['spatial_reference'])
    affine = Affine(geotransform[1], 0.0, geotransform[0], 0.0,
                    geotransform[5], geotransform[3])
    return GeoBox(width=metadata['width'],
                  height=metadata['height'],
                  affine=affine,
                  crs=crs)
Exemple #17
0
def test_compute_reproject_roi_issue647():
    """ In some scenarios non-overlapping geoboxes will result in non-empty
    `roi_dst` even though `roi_src` is empty.

    Test this case separately.
    """
    from datacube.utils.geometry import CRS

    src = GeoBox(10980, 10980, Affine(10, 0, 300000, 0, -10, 5900020),
                 CRS('epsg:32756'))

    dst = GeoBox(976, 976, Affine(10, 0, 1730240, 0, -10, -4170240),
                 CRS('EPSG:3577'))

    assert src.extent.overlaps(dst.extent.to_crs(src.crs)) is False

    rr = compute_reproject_roi(src, dst)

    assert roi_is_empty(rr.roi_src)
    assert roi_is_empty(rr.roi_dst)
Exemple #18
0
def compute_native_load_geobox(dst_geobox: GeoBox,
                               ds: Dataset,
                               band: str,
                               buffer: Optional[float] = None):

    native = native_geobox(ds, basis=band)
    if buffer is None:
        buffer = 10*max(map(abs, native.resolution))

    return GeoBox.from_geopolygon(dst_geobox.extent.to_crs(native.crs).buffer(buffer),
                                  crs=native.crs,
                                  resolution=native.resolution,
                                  align=native.alignment)
Exemple #19
0
def test_geobox_scale_down():
    from datacube.utils.geometry import GeoBox, CRS

    crs = CRS('EPSG:3857')

    A = mkA(0, (111.2, 111.2), translation=(125671, 251465))
    for s in [2, 3, 4, 8, 13, 16]:
        gbox = GeoBox(233 * s, 755 * s, A, crs)
        gbox_ = scaled_down_geobox(gbox, s)

        assert gbox_.width == 233
        assert gbox_.height == 755
        assert gbox_.crs is crs
        assert gbox_.extent.contains(gbox.extent)
        assert gbox.extent.difference(gbox.extent).area == 0.0

    gbox = GeoBox(1, 1, A, crs)
    for s in [2, 3, 5]:
        gbox_ = scaled_down_geobox(gbox, 3)

        assert gbox_.shape == (1, 1)
        assert gbox_.crs is crs
        assert gbox_.extent.contains(gbox.extent)
def test_compute_reproject_roi_issue1047():
    """ `compute_reproject_roi(geobox, geobox[roi])` sometimes returns
    `src_roi != roi`, when `geobox` has (1) tiny pixels and (2) oddly
    sized `alignment`.

    Test this issue is resolved.
    """
    geobox = GeoBox(3000, 3000,
                    Affine(0.00027778, 0.0, 148.72673054908861,
                           0.0, -0.00027778, -34.98825802556622), "EPSG:4326")
    src_roi = np.s_[2800:2810, 10:30]
    rr = compute_reproject_roi(geobox, geobox[src_roi])

    assert rr.is_st is True
    assert rr.roi_src == src_roi
    assert rr.roi_dst == np.s_[0:10, 0:20]
Exemple #21
0
def gbox_reproject(
    geobox: GeoBox,
    crs: SomeCRS,
    resolution: Optional[Tuple[int, int]] = None,
    pad: int = 0,
    pad_wh: Union[int, Tuple[int, int]] = 16,
) -> GeoBox:
    """
    Compute GeoBox in a given projection that fully encloses footprint of the source GeoBox.

    :param geobox: Source GeoBox

    :param crs: CRS of the output GeoBox

    :param resolution: Desired output resolution (defaults to source
                       resolution, if source and destination projections share
                       common units)

    :param pad: Padding in pixels of output GeoBox

    :param pad_wh: Expand output GeoBox some more such that (W%pad_wh) == 0 and (H%pad_wh) == 0
    """
    from datacube.utils.geometry import gbox

    crs = _norm_crs_or_error(crs)

    if resolution is None:
        if geobox.crs.units == crs.units:
            resolution = geobox.resolution
        else:
            raise NotImplementedError(
                "Source and destination projections have different units: have to supply desired output resolution"
            )

    out = GeoBox.from_geopolygon(geobox.extent, resolution, crs)
    if pad > 0:
        out = gbox.pad(out, pad)
    if pad_wh:
        if isinstance(pad_wh, int):
            pad_wh = max(1, pad_wh)
            pad_wh = (pad_wh, pad_wh)
        out = gbox.pad_wh(out, *pad_wh)

    return out
Exemple #22
0
 def load_layer(self, geobox, _):
     import rasterio
     with rasterio.open(self.path) as src:
         assert src.indexes == (1,) # only support single-band
         if geobox is None:
             from datacube.utils.geometry import GeoBox, CRS
             geobox = GeoBox(src.width, src.height, src.affine,
                             CRS(src.crs.wkt))
             array = src.read(1)
         else:
             band = rasterio.band(src, 1)
             array = np.empty((geobox.height, geobox.width),
                              dtype = band.dtype)
             rasterio.warp.reproject(source=band,
                                     destination=array,
                                     dst_crs=geobox.crs.crs_str,
                                     dst_transform=geobox.affine,
                                     dst_nodata=None)
     return array
def test_can_paste():
    src = AlbersGS.tile_geobox((17, -40))

    def check_true(dst, **kwargs):
        ok, reason = can_paste(compute_reproject_roi(src, dst), **kwargs)
        if not ok:
            assert ok is True, reason

    def check_false(dst, **kwargs):
        ok, reason = can_paste(compute_reproject_roi(src, dst), **kwargs)
        if ok:
            assert ok is False, "Expected can_paste to return False, but got True"

    check_true(gbx.pad(src, 100))
    check_true(src[:10, :10])
    check_true(gbx.translate_pix(src, 0.1, 0.3), ttol=0.5)
    check_true(gbx.translate_pix(src, 3, -4))
    check_true(gbx.flipx(src))
    check_true(gbx.flipy(src))
    check_true(gbx.flipx(gbx.flipy(src)))
    check_true(gbx.zoom_out(src, 2))
    check_true(gbx.zoom_out(src, 4))
    check_true(gbx.zoom_out(src[:9, :9], 3))

    # Check False code paths
    dst = GeoBox.from_geopolygon(src.extent.to_crs(epsg3857).buffer(10),
                                 resolution=src.resolution)
    check_false(dst)  # non ST
    check_false(gbx.affine_transform_pix(src, Affine.rotation(1)))  # non ST

    check_false(gbx.zoom_out(src, 1.9))  # non integer scale
    check_false(gbx.affine_transform_pix(src, Affine.scale(1, 2)))  # sx != sy

    dst = gbx.translate_pix(src, -1, -1)
    dst = gbx.zoom_out(dst, 2)
    check_false(dst)  # src_roi doesn't align for scale

    check_false(dst, stol=0.7)  # src_roi/scale != dst_roi
    check_false(gbx.translate_pix(src, 0.3, 0.4))  # sub-pixel translation
Exemple #24
0
def scaled_down_geobox(src_geobox, scaler: int):
    """Given a source geobox and integer scaler compute geobox of a scaled down image.

        Output geobox will be padded when shape is not a multiple of scaler.
        Example: 5x4, scaler=2 -> 3x2

        NOTE: here we assume that pixel coordinates are 0,0 at the top-left
              corner of a top-left pixel.

    """
    from datacube.utils.geometry import GeoBox

    assert scaler > 1

    H, W = [X//scaler + (1 if X % scaler else 0)
            for X in src_geobox.shape]

    # Since 0,0 is at the corner of a pixel, not center, there is no
    # translation between pixel plane coords due to scaling
    A = src_geobox.transform * Affine.scale(scaler, scaler)

    return GeoBox(W, H, A, src_geobox.crs)
Exemple #25
0
def test_xy_from_geobox():
    gbox = GeoBox(3, 7, Affine.translation(10, 1000), epsg3857)
    xx, yy = xy_from_gbox(gbox)

    assert xx.shape == gbox.shape
    assert yy.shape == gbox.shape
    assert (xx[:, 0] == 10.5).all()
    assert (xx[:, 1] == 11.5).all()
    assert (yy[0, :] == 1000.5).all()
    assert (yy[6, :] == 1006.5).all()

    xx_, yy_, A = xy_norm(xx, yy)
    assert xx_.shape == xx.shape
    assert yy_.shape == yy.shape
    np.testing.assert_almost_equal((xx_.min(), xx_.max()), (0, 1))
    np.testing.assert_almost_equal((yy_.min(), yy_.max()), (0, 1))
    assert (xx_[0] - xx_[1]).sum() != 0
    assert (xx_[:, 0] - xx_[:, 1]).sum() != 0

    XX, YY = apply_affine(A, xx_, yy_)
    np.testing.assert_array_almost_equal(xx, XX)
    np.testing.assert_array_almost_equal(yy, YY)
Exemple #26
0
def make_sample_geotiff(tmpdir):
    """ Make a sample geotiff, filled with random data, and twice as tall as it is wide. """
    sample_geotiff = str(tmpdir.mkdir('tiffs').join('sample.tif'))

    geobox = GeoBox(100,
                    200,
                    affine=Affine(25.0, 0.0, 0, 0.0, -25.0, 0),
                    crs=CRS('EPSG:3577'))

    sample_data = np.random.randint(10000, size=geobox.shape, dtype='int16')
    rio_args = {
        'height': geobox.height,
        'width': geobox.width,
        'count': 1,
        'dtype': 'int16',
        'crs': 'EPSG:3577',
        'transform': geobox.transform,
        'nodata': -999
    }
    with rasterio.open(sample_geotiff, 'w', driver='GTiff', **rio_args) as dst:
        dst.write(sample_data, 1)

    return sample_geotiff, geobox, sample_data
Exemple #27
0
def web_geobox(zoom, tx, ty, tile_size=256):
    """Construct geobox for a given web-tile.

    Tile indexes should be the same as google maps.

    http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/
    """
    from datacube.utils.geometry import CRS, GeoBox
    from math import pi

    R = 6378137

    origin = pi * R
    res0 = 2 * pi * R / tile_size
    res = res0*(2**(-zoom))
    tsz = 2 * pi * R * (2**(-zoom))  # res*tile_size

    # maps pixel coord to meters in EPSG:3857
    #
    transform = Affine(res, 0, tx*tsz - origin,
                       0, -res, origin - ty*tsz)

    return GeoBox(tile_size, tile_size, transform, CRS('epsg:3857'))
Exemple #28
0
def test_geobox_xr_coords():
    A = mkA(0, scale=(10, -10), translation=(-48800, -2983006))

    w, h = 512, 256
    gbox = GeoBox(w, h, A, epsg3577)

    cc = gbox.xr_coords()
    assert list(cc) == ['y', 'x']
    assert cc['y'].shape == (gbox.shape[0], )
    assert cc['x'].shape == (gbox.shape[1], )
    assert 'crs' in cc['y'].attrs
    assert 'crs' in cc['x'].attrs

    cc = gbox.xr_coords(with_crs=True)
    assert list(cc) == ['y', 'x', 'spatial_ref']
    assert cc['spatial_ref'].shape is ()
    assert cc['spatial_ref'].attrs['spatial_ref'] == gbox.crs.wkt
    assert isinstance(cc['spatial_ref'].attrs['grid_mapping_name'], str)

    cc = gbox.xr_coords(with_crs='Albers')
    assert list(cc) == ['y', 'x', 'Albers']

    # geographic CRS
    A = mkA(0, scale=(0.1, -0.1), translation=(10, 30))
    gbox = GeoBox(w, h, A, 'epsg:4326')
    cc = gbox.xr_coords(with_crs=True)
    assert list(cc) == ['latitude', 'longitude', 'spatial_ref']
    assert cc['spatial_ref'].shape is ()
    assert cc['spatial_ref'].attrs['spatial_ref'] == gbox.crs.wkt
    assert isinstance(cc['spatial_ref'].attrs['grid_mapping_name'], str)

    # missing CRS for GeoBox
    gbox = GeoBox(w, h, A, None)
    cc = gbox.xr_coords(with_crs=True)
    assert list(cc) == ['y', 'x']

    # check CRS without name
    crs = MagicMock()
    crs.projected = True
    crs.wkt = epsg3577.wkt
    crs.epsg = epsg3577.epsg
    crs._crs = MagicMock()
    crs._crs.to_cf.return_value = {}
    assert _mk_crs_coord(crs).attrs['grid_mapping_name'] == '??'
Exemple #29
0
def test_gbox_ops():
    s = GeoBox(1000, 100, Affine(10, 0, 12340, 0, -10, 316770), epsg3857)
    assert s.shape == (100, 1000)

    d = gbx.flipy(s)
    assert d.shape == s.shape
    assert d.crs is s.crs
    assert d.resolution == (-s.resolution[0], s.resolution[1])
    assert d.extent.contains(s.extent)
    with pytest.raises(ValueError):
        # flipped grid
        (s | d)
    with pytest.raises(ValueError):
        # flipped grid
        (s & d)

    d = gbx.flipx(s)
    assert d.shape == s.shape
    assert d.crs is s.crs
    assert d.resolution == (s.resolution[0], -s.resolution[1])
    assert d.extent.contains(s.extent)

    assert gbx.flipy(gbx.flipy(s)).affine == s.affine
    assert gbx.flipx(gbx.flipx(s)).affine == s.affine

    d = gbx.zoom_out(s, 2)
    assert d.shape == (50, 500)
    assert d.crs is s.crs
    assert d.extent.contains(s.extent)
    assert d.resolution == (s.resolution[0]*2, s.resolution[1]*2)

    d = gbx.zoom_out(s, 2*max(s.shape))
    assert d.shape == (1, 1)
    assert d.crs is s.crs
    assert d.extent.contains(s.extent)

    d = gbx.zoom_out(s, 1.33719)
    assert d.crs is s.crs
    assert d.extent.contains(s.extent)
    assert all(ds < ss for ds, ss in zip(d.shape, s.shape))
    with pytest.raises(ValueError):
        # lower resolution grid
        (s | d)
    with pytest.raises(ValueError):
        # lower resolution grid
        (s & d)

    d = gbx.zoom_to(s, s.shape)
    assert d == s

    d = gbx.zoom_to(s, (1, 3))
    assert d.shape == (1, 3)
    assert d.extent == s.extent

    d = gbx.zoom_to(s, (10000, 10000))
    assert d.shape == (10000, 10000)
    assert d.extent == s.extent

    d = gbx.pad(s, 1)
    assert d.crs is s.crs
    assert d.resolution == s.resolution
    assert d.extent.contains(s.extent)
    assert s.extent.contains(d.extent) is False
    assert d[1:-1, 1:-1].affine == s.affine
    assert d[1:-1, 1:-1].shape == s.shape
    assert d == (s | d)
    assert s == (s & d)

    d = gbx.pad_wh(s, 10)
    assert d == s

    d = gbx.pad_wh(s, 100, 8)
    assert d.width == s.width
    assert d.height % 8 == 0
    assert 0 < d.height - s.height < 8
    assert d.affine == s.affine
    assert d.crs is s.crs

    d = gbx.pad_wh(s, 13, 17)
    assert d.affine == s.affine
    assert d.crs is s.crs
    assert d.height % 17 == 0
    assert d.width % 13 == 0
    assert 0 < d.height - s.height < 17
    assert 0 < d.width - s.width < 13

    d = gbx.translate_pix(s, 1, 2)
    assert d.crs is s.crs
    assert d.resolution == s.resolution
    assert d.extent != s.extent
    assert s[2:3, 1:2].extent == d[:1, :1].extent

    d = gbx.translate_pix(s, -10, -2)
    assert d.crs is s.crs
    assert d.resolution == s.resolution
    assert d.extent != s.extent
    assert s[:1, :1].extent == d[2:3, 10:11].extent

    d = gbx.translate_pix(s, 0.1, 0)
    assert d.crs is s.crs
    assert d.shape == s.shape
    assert d.resolution == s.resolution
    assert d.extent != s.extent
    assert d.extent.contains(s[:, 1:].extent)

    d = gbx.translate_pix(s, 0, -0.5)
    assert d.crs is s.crs
    assert d.shape == s.shape
    assert d.resolution == s.resolution
    assert d.extent != s.extent
    assert s.extent.contains(d[1:, :].extent)

    d = gbx.affine_transform_pix(s, Affine(1, 0, 0,
                                           0, 1, 0))
    assert d.crs is s.crs
    assert d.shape == s.shape
    assert d.resolution == s.resolution
    assert d.extent == s.extent

    d = gbx.rotate(s, 180)
    assert d.crs is s.crs
    assert d.shape == s.shape
    assert d.extent != s.extent
    np.testing.assert_almost_equal(d.extent.area, s.extent.area, 1e-5)
    assert s[49:52, 499:502].extent.contains(d[50:51, 500:501].extent), "Check that center pixel hasn't moved"
Exemple #30
0
def mk_gbox(shape=(2, 2), transform=identity, crs=epsg4326):
    H, W = shape
    return GeoBox(W, H, transform, crs)