Example #1
0
def test_from_string():
    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert wgs84_crs.to_dict() == {'init': 'epsg:4326'}

    # Make sure this doesn't get handled using the from_epsg() even though 'epsg' is in the string
    epsg_init_crs = CRS.from_string('+init=epsg:26911')
    assert epsg_init_crs.to_dict() == {'init': 'epsg:26911'}
Example #2
0
def test_from_epsg_string():
    crs_dict = CRS.from_string('epsg:4326')
    assert crs_dict['init'].lower() == 'epsg:4326'

    # Test with invalid EPSG code
    with pytest.raises(ValueError):
        assert CRS.from_string('epsg:xyz')
Example #3
0
def test_from_string():
    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert wgs84_crs.to_dict() == {'no_defs': True, 'ellps': 'WGS84', 'datum': 'WGS84', 'proj': 'longlat'}

    # Make sure this doesn't get handled using the from_epsg() even though 'epsg' is in the string
    epsg_init_crs = CRS.from_string('+units=m +init=epsg:26911 +no_defs=True')
    assert epsg_init_crs.to_dict() == {'units': 'm', 'init': 'epsg:26911', 'no_defs': True}
Example #4
0
def test_from_proj4_json():
    json_str = '{"proj": "longlat", "ellps": "WGS84", "datum": "WGS84"}'
    crs_dict = CRS.from_string(json_str)
    assert crs_dict == json.loads(json_str)

    # Test with invalid JSON code
    with pytest.raises(ValueError):
        assert CRS.from_string('{foo: bar}')
Example #5
0
def test_is_projected():
    assert CRS({'init': 'EPSG:3857'}).is_projected is True

    lcc_crs = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert CRS(lcc_crs).is_projected is True

    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert CRS(wgs84_crs).is_projected is False
Example #6
0
def test_is_geographic_from_string():
    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert wgs84_crs.is_geographic is True

    nad27_crs = CRS.from_string('+proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs')
    assert nad27_crs.is_geographic is True

    lcc_crs = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert lcc_crs.is_geographic is False
Example #7
0
def test_issue_1446():
    """Confirm resolution of #1446"""
    g = transform_geom(
        CRS.from_epsg(4326),
        CRS.from_epsg(32610),
        {"type": "Point", "coordinates": (-122.51403808499907, 38.06106733107932)},
    )
    assert round(g["coordinates"][0], 1) == 542630.9
    assert round(g["coordinates"][1], 1) == 4212702.1
Example #8
0
def test_bare_parameters():
    """ Make sure that bare parameters (e.g., no_defs) are handled properly,
    even if they come in with key=True.  This covers interaction with pyproj,
    which makes presents bare parameters as key=<bool>."""

    # Example produced by pyproj
    crs_dict = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert crs_dict.get('no_defs', False) is True

    crs_dict = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=False +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert crs_dict.get('no_defs', True) is False
Example #9
0
def test_symmetric_proj4(tmpdir):
    """ Test writing and reading proj4 string as attribute of variable """

    ds = Dataset(str(tmpdir.join('test.nc')), 'w')
    proj4 = '+proj=stere +units=m +datum=WGS84 +lat_ts=60 +lat_0=90 +lon_0=263 +lat_1=60 +x_0=3475000 +y_0=7475000'
    ds.createVariable('data', 'S1')
    set_crs(ds, 'data', Proj(proj4), set_proj4_att=True)
    out_proj4 = get_crs(ds, 'data')

    out_data = CRS.from_string(out_proj4).to_dict()

    assert len(out_data) == 9  # There should be 9 parameters
    assert CRS.from_string(proj4).to_dict() == out_data
Example #10
0
def test_get_crs(tmpdir):
    """ Test reading proj4 string from CF convention parameters """

    ds = Dataset(str(tmpdir.join('test.nc')), 'w')
    data_var = ds.createVariable('data', 'S1')
    data_var.setncattr('grid_mapping', 'crs_Lambert')
    crs_var = ds.createVariable('crs_Lambert', 'S1')

    in_proj4 = '+proj=lcc +units=m +lat_1=30 +lat_2=60 +lat_0=47.5 +lon_0=-97 +x_0=3825000 +y_0=3200000'

    # These parameters match the above proj4 string
    ncatts = dict()
    ncatts['grid_mapping_name'] = 'lambert_conformal_conic'
    ncatts['latitude_of_projection_origin'] = 47.5
    ncatts['longitude_of_central_meridian'] = -97
    ncatts['standard_parallel'] = [30, 60]
    ncatts['false_northing'] = 3200000
    ncatts['false_easting'] = 3825000
    set_ncattrs(crs_var, ncatts)

    out_proj4 = get_crs(ds, 'data')
    assert out_proj4 is not None

    out_data = CRS.from_string(out_proj4).to_dict()

    assert len(out_data) == 8  # There should be 8 parameters
    assert CRS.from_string(in_proj4).to_dict() == out_data

    # Test WGS84 lat/long
    data_var = ds.createVariable('data2', 'S1')
    data_var.setncattr('grid_mapping', 'crs_latlong')
    crs_var = ds.createVariable('crs_latlong', 'S1')

    in_proj4 = '+proj=latlong +a={0} +rf={1}'.format(pj_ellps['WGS84']['a'], pj_ellps['WGS84']['rf'])

    # These parameters match the above proj4 string
    ncatts = dict()
    ncatts['grid_mapping_name'] = 'latitude_longitude'
    ncatts['semi_major_axis'] = 6378137.0
    ncatts['inverse_flattening'] = 298.257223563
    set_ncattrs(crs_var, ncatts)

    out_proj4 = get_crs(ds, 'data2')
    assert out_proj4 is not None

    out_data = CRS.from_string(out_proj4).to_dict()

    assert len(out_data) == 4  # There should be 4 parameters
    # Note: pyproj adds units=m even for latlong, which is incorrect but not our problem
    assert CRS.from_string(in_proj4 + ' +units=m').to_dict() == out_data
Example #11
0
def test_is_same_crs():
    crs1 = CRS({'init': 'EPSG:4326'})
    crs2 = CRS({'init': 'EPSG:3857'})

    assert crs1 == crs1
    assert crs1 != crs2

    wgs84_crs = CRS.from_string('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
    assert crs1 == wgs84_crs

    # Make sure that same projection with different parameter are not equal
    lcc_crs1 = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    lcc_crs2 = CRS.from_string('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=45 +lat_0=0')
    assert lcc_crs1 != lcc_crs2
Example #12
0
def main():
    samplefile = r'bxk1-d-ck.idf'
    tiffile = samplefile.replace('.idf', '.geotiff')
    dtype = rasterio.float64
    driver = 'AAIGrid'
    crs = CRS.from_epsg(28992)

    # read data from idf file
    idffile = idfpy.IdfFile(filepath=samplefile, mode='rb')
    geotransform = idffile.geotransform
    height = idffile.header['nrow']
    width = idffile.header['ncol']
    nodata = idffile.header['nodata']
    transform = Affine.from_gdal(*geotransform)

    # write data from idf file to geotiff with rasterio
    profile = {
        'width': width,
        'height': height,
        'count': 1,
        'dtype': dtype,
        'driver': driver,
        'crs': crs,
        'transform': transform,
        'nodata': nodata,
    }

    # the default profile would be sufficient for the example, however the profile dict shows how to make the export
    # profile
    idffile.to_raster(tiffile, **profile)
Example #13
0
    def index(self, *args, **kwargs):
        target_srs = self.crs
        # Annotations are always in WGS84
        source_srs = CRS.from_string("EPSG:4326")

        args = transform_coordinates(source_srs, target_srs,
                                     [args[0]], [args[1]])
        return self.dataset.index(*args, **kwargs)
Example #14
0
    def __init__(self, ul, crs, res, size, desc=None):
        self.ul = ul
        if isinstance(crs, six.string_types):
            self.crs = CRS.from_string(crs)
        elif isinstance(crs, int):
            self.crs = CRS.from_epsg(crs)
        else:
            self.crs = crs

        if not self.crs.is_valid:
            raise ValueError('Could not parse coordinate reference system '
                             'string to a valid projection ({})'.format(crs))

        self.crs_str = self.crs.to_string()
        self.res = res
        self.size = size
        self.desc = desc or 'unnamed'
        self._tiles = {}
Example #15
0
def test_warped_vrt(path_rgb_byte_tif):
    """A VirtualVRT has the expected VRT properties."""
    with rasterio.open(path_rgb_byte_tif) as src:
        vrt = WarpedVRT(src, crs=DST_CRS)
        assert vrt.dst_crs == CRS.from_string(DST_CRS)
        assert vrt.src_nodata == 0.0
        assert vrt.dst_nodata == 0.0
        assert vrt.tolerance == 0.125
        assert vrt.resampling == Resampling.nearest
        assert vrt.warp_extras == {"init_dest": "NO_DATA"}
        assert vrt.mask_flag_enums == ([MaskFlags.nodata],) * 3
Example #16
0
    def get_band_ix(self, indexes, x, y):
        # Reproject to native data coordinates
        target_srs = self.crs
        # Annotations are always in WGS84
        source_srs = CRS.from_string("EPSG:4326")

        transformed_x, transformed_y = transform_coordinates(source_srs,
                                                             target_srs,
                                                             [x], [y])
        return list(self.dataset.sample([(transformed_x, transformed_y)],
                                        indexes=indexes))[0]
Example #17
0
def test_reproject_init_dest_nodata():
    """No pixels should transfer over"""
    crs = CRS.from_epsg(4326)
    transform = Affine.identity()
    source = np.zeros((1, 100, 100))
    destination = np.ones((1, 100, 100))
    reproject(
        source, destination, src_crs=crs, src_transform=transform,
        dst_crs=crs, dst_transform=transform,
        src_nodata=0, init_dest_nodata=False
    )
    assert destination.all()
Example #18
0
def test_empty_json():
    with pytest.raises(CRSError):
        CRS.from_string('{}')
    with pytest.raises(CRSError):
        CRS.from_string('[]')
    with pytest.raises(CRSError):
        CRS.from_string('')
Example #19
0
def retrieve_tilespecs():
    """ Retrieve default tile specifications packaged within ``tilezilla``

    Returns:
        dict: default tilespecs packaged within ``tilezilla`` as TileSpec
            objects
    """
    tilespecs = json.loads(pkgutil.get_data('tilezilla',
                                            'data/tile_specs.json').decode())
    for key in tilespecs:
        tilespecs[key]['crs'] = CRS.from_string(tilespecs[key]['crs'])
        tilespecs[key] = TileSpec(desc=key, **tilespecs[key])
    return tilespecs
Example #20
0
def test_linear_units_factor():
    """CRS linear units can be had"""
    assert CRS.from_epsg(3857).linear_units_factor[0] == 'metre'
    assert CRS.from_epsg(3857).linear_units_factor[1] == 1.0
    assert CRS.from_epsg(2261).linear_units_factor[0] == 'US survey foot'
    assert CRS.from_epsg(2261).linear_units_factor[1] == pytest.approx(0.3048006096012192)
    with pytest.raises(CRSError):
        CRS.from_epsg(4326).linear_units_factor
Example #21
0
def test_wrap_file(path_rgb_byte_tif):
    """A VirtualVRT has the expected dataset properties."""
    with rasterio.open(path_rgb_byte_tif) as src:
        vrt = WarpedVRT(src, crs=DST_CRS)
        assert vrt.crs == CRS.from_string(DST_CRS)
        assert tuple(round(x, 1) for x in vrt.bounds) == (
            -8789636.7, 2700460.0, -8524406.4, 2943560.2
        )
        assert vrt.name.startswith("WarpedVRT(")
        assert vrt.name.endswith("tests/data/RGB.byte.tif)")
        assert vrt.indexes == (1, 2, 3)
        assert vrt.nodatavals == (0, 0, 0)
        assert vrt.dtypes == ("uint8", "uint8", "uint8")
        assert vrt.read().shape == (3, 736, 803)
Example #22
0
 def test_get_area_def_from_raster(self):
     from pyresample import utils
     from rasterio.crs import CRS
     from affine import Affine
     x_size = 791
     y_size = 718
     transform = Affine(300.0379266750948, 0.0, 101985.0,
                        0.0, -300.041782729805, 2826915.0)
     crs = CRS(init='epsg:3857')
     source = tmptiff(x_size, y_size, transform, crs=crs)
     area_id = 'area_id'
     proj_id = 'proj_id'
     name = 'name'
     area_def = utils._rasterio.get_area_def_from_raster(
         source, area_id=area_id, name=name, proj_id=proj_id)
     self.assertEqual(area_def.area_id, area_id)
     self.assertEqual(area_def.proj_id, proj_id)
     self.assertEqual(area_def.name, name)
     self.assertEqual(area_def.width, x_size)
     self.assertEqual(area_def.height, y_size)
     self.assertDictEqual(crs.to_dict(), area_def.proj_dict)
     self.assertTupleEqual(area_def.area_extent, (transform.c, transform.f + transform.e * y_size,
                                                  transform.c + transform.a * x_size, transform.f))
def feature_to_mercator(feature):
    '''Normalize feature and converts coords to 3857.

    Args:
      feature: geojson feature to convert to mercator geometry.
    '''
    # Ref: https://gist.github.com/dnomadb/5cbc116aacc352c7126e779c29ab7abe

    src_crs = CRS.from_epsg(4326)
    dst_crs = CRS.from_epsg(3857)

    geometry = feature['geometry']
    if geometry['type'] == 'Polygon':
        xys = (zip(*part) for part in geometry['coordinates'])
        xys = (list(zip(*transform(src_crs, dst_crs, *xy))) for xy in xys)

        yield {'coordinates': list(xys), 'type': 'Polygon'}

    elif geometry['type'] == 'MultiPolygon':
        for component in geometry['coordinates']:
            xys = (zip(*part) for part in component)
            xys = (list(zip(*transform(src_crs, dst_crs, *xy))) for xy in xys)

            yield {'coordinates': list(xys), 'type': 'Polygon'}
Example #24
0
def test_warped_vrt_add_alpha(path_rgb_byte_tif):
    """A VirtualVRT has the expected VRT properties."""
    with rasterio.open(path_rgb_byte_tif) as src:
        vrt = WarpedVRT(src, crs=DST_CRS, add_alpha=True)
        assert vrt.dst_crs == CRS.from_string(DST_CRS)
        assert vrt.src_nodata == 0.0
        assert vrt.dst_nodata is None
        assert vrt.tolerance == 0.125
        assert vrt.resampling == Resampling.nearest
        assert vrt.warp_extras == {"init_dest": "NO_DATA"}
        assert vrt.count == 4
        assert vrt.mask_flag_enums == (
            [MaskFlags.per_dataset, MaskFlags.alpha],
        ) * 3 + (
            [MaskFlags.all_valid],
        )
def example_reproject():
    import idfpy

    from matplotlib import pyplot as plt
    from rasterio import Affine
    from rasterio.crs import CRS
    from rasterio.warp import reproject, Resampling
    import numpy as np

    with idfpy.open('bxk1-d-ck.idf') as src:
        a = src.read(masked=True)
        nr, nc = src.header['nrow'], src.header['ncol']
        dx, dy = src.header['dx'], src.header['dy']
        src_transform = Affine.from_gdal(*src.geotransform)

    # define new grid transform (same extent, 10 times resolution)
    dst_transform = Affine.translation(src_transform.c, src_transform.f)
    dst_transform *= Affine.scale(dx / 10., -dy / 10.)

    # define coordinate system (here RD New)
    src_crs = CRS.from_epsg(28992)

    # initialize new data array
    b = np.empty((10*nr, 10*nc))

    # reproject using Rasterio
    reproject(
        source=a,
        destination=b,
        src_transform=src_transform,
        dst_transform=dst_transform,
        src_crs=src_crs,
        dst_crs=src_crs,
        resampling=Resampling.bilinear,
        )

    # result as masked array
    b = np.ma.masked_equal(b, a.fill_value)

    # plot images
    fig, axes = plt.subplots(nrows=2, ncols=1)
    axes[0].imshow(a.filled(np.nan))
    axes[0].set_title('bxk1 original')
    axes[1].imshow(b.filled(np.nan))
    axes[1].set_title('bxk1 resampled')
    plt.show()
Example #26
0
def test_warped_vrt_msk_nodata(path_rgb_msk_byte_tif, caplog):
    """Specifying dst nodata also works for source with .msk"""
    with rasterio.open(path_rgb_msk_byte_tif) as src:
        vrt = WarpedVRT(src, crs=DST_CRS, nodata=0.0)
        assert vrt.dst_crs == CRS.from_string(DST_CRS)
        assert vrt.src_nodata is None
        assert vrt.dst_nodata == 0.0
        assert vrt.count == 3
        assert vrt.mask_flag_enums == ([MaskFlags.nodata],) * 3

        caplog.set_level(logging.DEBUG)
        with rasterio.Env(CPL_DEBUG=True):
            masks = vrt.read_masks()
            assert masks[0, 0, 0] == 0
            assert masks[0].mean() > 0

        assert "RGB2.byte.tif.msk" in caplog.text
Example #27
0
def crs_handler(ctx, param, value):
    """Get crs value from a template file or command line."""
    retval = options.from_like_context(ctx, param, value)
    if retval is None and value:
        try:
            retval = json.loads(value)
        except ValueError:
            retval = value
        try:
            if isinstance(retval, dict):
                retval = CRS(retval)
            else:
                retval = CRS.from_string(retval)
        except CRSError:
            raise click.BadParameter(
                "'%s' is not a recognized CRS." % retval,
                param=param, param_hint='crs')
    return retval
Example #28
0
def test_utm(tmpdir):
    ds = Dataset(str(tmpdir.join('test.nc')), 'w')
    proj4 = '+init=epsg:3157'  # UTM Zone 10
    ds.createVariable('data', 'S1')
    set_crs(ds, 'data', Proj(proj4), set_proj4_att=True)
    out_proj4 = get_crs(ds, 'data')

    out_data = CRS.from_string(out_proj4).to_dict()

    # ESPG will have been converted to long form
    assert len(out_data) == 6

    expected = {
        u'zone': 10,
        u'ellps': u'GRS80',
        u'no_defs': True,
        u'proj': u'utm',
        u'units': u'm',
        u'towgs84': u'0,0,0,0,0,0,0'
    }
    assert expected == out_data
Example #29
0
def test_warped_vrt_dimensions(path_rgb_byte_tif):
    """
    A WarpedVRT with target dimensions has the expected dataset
    properties.
    """
    with rasterio.open(path_rgb_byte_tif) as src:
        extent = (-20037508.34, 20037508.34)
        size = (2 ** 16) * 256
        resolution = (extent[1] - extent[0]) / size
        dst_transform = affine.Affine(
            resolution, 0.0, extent[0], 0.0, -resolution, extent[1]
        )
        vrt = WarpedVRT(
            src, crs=DST_CRS, width=size, height=size, transform=dst_transform
        )
        assert vrt.dst_crs == CRS.from_string(DST_CRS)
        assert vrt.src_nodata == 0.0
        assert vrt.dst_nodata == 0.0
        assert vrt.resampling == Resampling.nearest
        assert vrt.width == size
        assert vrt.height == size
        assert vrt.transform == dst_transform
        assert vrt.warp_extras == {"init_dest": "NO_DATA"}
Example #30
0
    def to_raster(self, fp=None, epsg=28992, driver='AAIGrid'):
        """export Idf to a geotiff"""
        self.check_read()

        if fp is None:
            fp = self.filepath.replace('.idf', '.geotiff')
            logging.warning('no filepath was given, exported to {fp}'.format(fp=fp))

        # set profile
        profile = {
            'width': self.header['ncol'],
            'height': self.header['nrow'],
            'transform': Affine.from_gdal(*self.geotransform),
            'nodata': self.header['nodata'],
            'count': 1,
            'dtype': rasterio.float64,
            'driver': driver,
            'crs': CRS.from_epsg(epsg),
        }

        logging.info('writing to {f:}'.format(f=fp))
        with rasterio.open(fp, 'w', **profile) as dst:
            dst.write(self.masked_data.astype(profile['dtype']), 1)
Example #31
0
# coding=utf-8
from __future__ import absolute_import

import mercantile
from rasterio.crs import CRS

from .. import InvalidTileRequest

MIN_LAT = -85.05113
MIN_LON = -180.0
MAX_LAT = 85.05113
MAX_LON = 180
WGS84_CRS = CRS.from_epsg(4326)


class Catalog(object):
    _bounds = [MIN_LON, MIN_LAT, MAX_LON, MAX_LAT]
    _center = [0, 0, 2]
    _headers = {}
    _id = None
    _maxzoom = 22
    _metadata_url = None
    _minzoom = 0
    _name = "Untitled"
    _provider = None
    _provider_url = None

    @property
    def bounds(self):
        w, s, e, n = self._bounds
        return (max(MIN_LON, w), max(MIN_LAT, s), min(MAX_LON,
Example #32
0
"""timvt.custom.tms: Custom TileMatrixSet."""

import morecantile
from rasterio.crs import CRS

# CUSTOM TMS for EPSG:3413
EPSG3413 = morecantile.TileMatrixSet.custom(
    (-4194300, -4194300, 4194300, 4194300),
    CRS.from_epsg(3413),
    identifier="EPSG3413",
    matrix_scale=[2, 2],
)

# CUSTOM TMS for EPSG:6933
# info from https://epsg.io/6933
EPSG6933 = morecantile.TileMatrixSet.custom(
    (-17357881.81713629, -7324184.56362408, 17357881.81713629,
     7324184.56362408),
    CRS.from_epsg(6933),
    identifier="EPSG6933",
    matrix_scale=[1, 1],
)
Example #33
0
def test_esri_auth__to_epsg():
    assert CRS.from_user_input('ESRI:54009').to_epsg() is None
Example #34
0
def test_from_authority__to_authority():
    assert CRS.from_authority("EPSG", 4326).to_authority() == ("EPSG", "4326")
Example #35
0
def test_latlong_northingeasting_gdal3():
    """Check CRS created from epsg with GDAL 3."""
    assert epsg_treats_as_latlong(CRS.from_epsg(4326))
    assert epsg_treats_as_northingeasting(CRS.from_epsg(2193))
Example #36
0
class GeoRasterCropTest(TestCase):
    metric_affine = Affine(1, 0.0, 2653750, 0.0, -1, 4594461)
    metric_crs = CRS({'init': 'epsg:3857'})
    geographic_affine = Affine(8.03258139076081e-06, 0.0, 23.83904185232179,
                               0.0, -8.03258139076081e-06, 38.10635414334363)
    geographic_crs = CRS({'init': 'epsg:4326'})

    def metric_raster(cls):
        return GeoRaster2(np.random.uniform(0, 256, (3, 3911, 3708)),
                          affine=cls.metric_affine,
                          crs=cls.metric_crs)

    def geographic_raster(cls):
        return GeoRaster2(np.random.uniform(0, 256, (3, 4147, 4147)),
                          affine=cls.geographic_affine,
                          crs=cls.geographic_crs)

    def test_crop_and_get_tile_do_without_resizing_the_same(self):
        coords = mercantile.xy_bounds(*tiles[15])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf:
            raster.save(rf.name)
            raster2 = GeoRaster2.open(rf.name)
            tile15 = raster2.get_tile(*tiles[15], blocksize=None)
            # load the image data
            raster2.image
            cropped15 = raster2.crop(shape)
            self.assertEqual(tile15, cropped15)

    @window_data
    def test_crop_and_get_tile_do_the_same(self):
        coords = mercantile.xy_bounds(*tiles[15])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf:
            raster.save(rf.name)
            raster2 = GeoRaster2.open(rf.name)
            tile15 = raster2.get_tile(*tiles[15])
            # load the image data
            raster2.image
            cropped15 = raster2.crop(shape, mercator_zoom_to_resolution[15])
            self.assertEqual(tile15, cropped15)

    @window_data
    def test_crop_and_get_tile_do_the_same_when_image_is_populated(self):
        coords = mercantile.xy_bounds(*tiles[15])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf:
            raster.save(rf.name)
            raster = GeoRaster2.open(rf.name)
            tile15 = raster.get_tile(*tiles[15])
            raster._populate_from_rasterio_object(read_image=True)
            cropped_15 = raster.crop(shape, mercator_zoom_to_resolution[15])
            self.assertEqual(tile15, cropped_15)

    @window_data
    def test_crop_image_from_and_get_win_do_the_same_with_resize(self):
        bounds = (2, 3, 4, 5)
        win = rasterio.windows.Window(bounds[0], bounds[1],
                                      bounds[2] - bounds[0],
                                      bounds[3] - bounds[1])
        xsize = round((bounds[2] - bounds[0]) / 2)
        ysize = round((bounds[3] - bounds[1]) / 2)
        raster = self.metric_raster()

        with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf:
            raster.save(rf.name)
            raster.save('area.tif', tags={'AREA_OR_POINT': 'Area'})
            raster.save('point.tif', tags={'AREA_OR_POINT': 'Point'})
            saved_raster = GeoRaster2.open(rf.name)
            cropped_win = saved_raster.get_window(win,
                                                  xsize=xsize,
                                                  ysize=ysize)
            saved_raster_area = GeoRaster2.open('area.tif')
            cropped_win_area = saved_raster_area.get_window(win,
                                                            xsize=xsize,
                                                            ysize=ysize)
            saved_raster_point = GeoRaster2.open('point.tif')
            cropped_win_point = saved_raster_point.get_window(win,
                                                              xsize=xsize,
                                                              ysize=ysize)

        cropped_image = raster._crop(bounds, xsize=xsize, ysize=ysize)

        print('cropped_win_area pixels\n', cropped_win_area.image)
        print('cropped_win_point pixels\n', cropped_win_point.image)
        print('cropped_win pixels\n', cropped_win.image)
        print('cropped_image pixels\n', cropped_image.image)
        if (cropped_win_point == cropped_win_area):
            print('point == area')
        if (cropped_image == cropped_win_area):
            print('image == area')
        if (cropped_image == cropped_win_point):
            print('image == point')
        if (cropped_win == cropped_win_area):
            print('win == area')
        if (cropped_win == cropped_win_point):
            print('win == point')

        self.assertEqual(cropped_image, cropped_win)

    @framing
    def test_crop_and_get_tile_do_the_same_when_image_is_populated_first_high_zoom(
            self):
        coords = mercantile.xy_bounds(*tiles[17])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf:
            raster.save(rf.name)
            raster = GeoRaster2.open(rf.name)
            raster._populate_from_rasterio_object(read_image=True)
            tile17 = raster.get_tile(*tiles[17])
            cropped_17 = raster.crop(shape, mercator_zoom_to_resolution[17])
            self.assertEqual(tile17, cropped_17)

    @framing
    def test_crop_and_get_tile_do_the_same_when_image_is_populated_first_mid_zoom(
            self):
        coords = mercantile.xy_bounds(*tiles[15])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf:
            raster.save(rf.name)
            raster = GeoRaster2.open(rf.name)
            raster._populate_from_rasterio_object(read_image=True)
            tile15 = raster.get_tile(*tiles[15])
            cropped_15 = raster.crop(shape, mercator_zoom_to_resolution[15])
            self.assertEqual(tile15, cropped_15)

    @framing
    def test_crop_and_get_tile_do_the_same_when_image_is_populated_first_for_low_zoom(
            self):
        coords = mercantile.xy_bounds(*tiles[11])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf:
            raster.save(rf.name)
            raster = GeoRaster2.open(rf.name)
            raster._populate_from_rasterio_object(read_image=True)
            tile11 = raster.get_tile(*tiles[11])
            cropped_11 = raster.crop(shape, mercator_zoom_to_resolution[11])
            self.assertEqual(tile11, cropped_11)

    def test_crop_image_from_and_get_win_do_the_same_full_resolution(self):
        bounds = (200, 130, 400, 150)
        win = rasterio.windows.Window(bounds[0], bounds[1],
                                      bounds[2] - bounds[0],
                                      bounds[3] - bounds[1])
        raster = self.metric_raster()
        with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf:
            raster.save(rf.name)
            saved_raster = GeoRaster2.open(rf.name)
            cropped_win = saved_raster.get_window(win)
        cropped_image = raster._crop(bounds)
        self.assertEqual(cropped_image, cropped_win)

    @patch.object(GeoRaster2, '_crop')
    def test_crop_use_crop_image_for_a_loaded_image(self, mock__crop):
        coords = mercantile.xy_bounds(*tiles[15])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        raster.crop(shape, mercator_zoom_to_resolution[15])
        assert mock__crop.called_once

    @patch.object(GeoRaster2, 'get_window')
    def test_crop_use_get_window_for_a_not_loaded_image(self, mock_get_window):
        coords = mercantile.xy_bounds(*tiles[15])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf:
            raster.save(rf.name)
            raster = GeoRaster2.open(rf.name)
            raster.crop(shape, mercator_zoom_to_resolution[15])
            assert mock_get_window.called_once

    def test_crop_returns_full_resolution_as_default(self):
        coords = mercantile.xy_bounds(*tiles[17])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        _, win = raster._vector_to_raster_bounds(shape)
        cropped = raster.crop(shape)
        self.assertEqual(
            cropped.shape,
            (raster.num_bands, round(win.height), round(win.width)))
        self.assertEqual(cropped.affine[0], raster.affine[0])

    def test_memory_crop_returns_resized_resolution(self):
        coords = mercantile.xy_bounds(*tiles[15])
        shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS)
        raster = self.metric_raster()
        cropped = raster.crop(shape, mercator_zoom_to_resolution[15])
        self.assertEqual(cropped.shape, (raster.num_bands, 256, 256))
        self.assertAlmostEqual(cropped.affine[0],
                               mercator_zoom_to_resolution[15], 2)

    def test_geographic_crop(self):
        raster = self.geographic_raster()
        rhombus_on_image = Polygon([[0, 2], [1, 1], [2, 2], [1,
                                                             3]])  # in pixels
        rhombus_world = raster.to_world(rhombus_on_image)
        cropped = raster.crop(rhombus_world)
        r = raster[0:2, 1:3]
        assert cropped == r

    def test_geographic_crop_with_resize(self):
        coords = mercantile.xy_bounds(*tiles[17])
        raster = self.geographic_raster()
        vector = GeoVector(Polygon.from_bounds(*coords),
                           crs=self.metric_crs).reproject(self.geographic_crs)
        cropped = raster.crop(vector, mercator_zoom_to_resolution[17])
        x_ex_res, y_ex_res = convert_resolution_from_meters_to_deg(
            self.metric_affine[6], mercator_zoom_to_resolution[17])
        self.assertAlmostEqual(cropped.affine[0], x_ex_res)
        self.assertAlmostEqual(abs(cropped.affine[4]), y_ex_res, 6)
Example #37
0
def _tile_read(
    src_dst,
    bounds,
    tilesize,
    indexes=None,
    nodata=None,
    resampling_method="bilinear",
    tile_edge_padding=2,
    dst_crs=CRS({"init": "EPSG:3857"}),
    bounds_crs=None,
    minimum_tile_cover=None,
    warp_vrt_option={},
):
    """
    Read data and mask.

    Attributes
    ----------
    src_dst : rasterio.io.DatasetReader
        rasterio.io.DatasetReader object
    bounds : list
        Output bounds (left, bottom, right, top) in target crs ("dst_crs").
    tilesize : int
        Output image size
    indexes : list of ints or a single int, optional, (defaults: None)
        If `indexes` is a list, the result is a 3D array, but is
        a 2D array if it is a band index number.
    nodata: int or float, optional (defaults: None)
    resampling_method : str, optional (default: "bilinear")
        Resampling algorithm.
    tile_edge_padding : int, optional (default: 2)
        Padding to apply to each edge of the tile when retrieving data
        to assist in reducing resampling artefacts along edges.
    dst_crs: CRS or str, optional
        Target coordinate reference system (default "epsg:3857").
    bounds_crs: CRS or str, optional
        Overwrite bounds coordinate reference system (default None, equal to dst_crs).
    minimum_tile_cover: float, optional (default: None)
        Minimum % overlap for which to raise an error with dataset not
        covering enought of the tile.
    warp_vrt_option: dict, optional (default: {})
        These will be passed to the rasterio.warp.WarpedVRT class.

    Returns
    -------
    data : numpy ndarray
    mask: numpy array

    """
    if isinstance(indexes, int):
        indexes = [indexes]
    elif isinstance(indexes, tuple):
        indexes = list(indexes)

    if not bounds_crs:
        bounds_crs = dst_crs

    bounds = transform_bounds(bounds_crs, dst_crs, *bounds, densify_pts=21)

    vrt_params = dict(add_alpha=True,
                      crs=dst_crs,
                      resampling=Resampling[resampling_method])

    vrt_transform, vrt_width, vrt_height = get_vrt_transform(src_dst,
                                                             bounds,
                                                             dst_crs=dst_crs)

    out_window = windows.Window(col_off=0,
                                row_off=0,
                                width=vrt_width,
                                height=vrt_height)

    src_bounds = transform_bounds(src_dst.crs,
                                  dst_crs,
                                  *src_dst.bounds,
                                  densify_pts=21)
    x_overlap = max(
        0,
        min(src_bounds[2], bounds[2]) - max(src_bounds[0], bounds[0]))
    y_overlap = max(
        0,
        min(src_bounds[3], bounds[3]) - max(src_bounds[1], bounds[1]))
    cover_ratio = (x_overlap * y_overlap) / ((bounds[2] - bounds[0]) *
                                             (bounds[3] - bounds[1]))
    if minimum_tile_cover and cover_ratio < minimum_tile_cover:
        raise TileOutsideBounds(
            "Dataset covers less than {:.0f}% of tile".format(cover_ratio *
                                                              100))

    if tile_edge_padding > 0 and not _requested_tile_aligned_with_internal_tile(
            src_dst, bounds, tilesize):
        vrt_transform = vrt_transform * Affine.translation(
            -tile_edge_padding, -tile_edge_padding)
        orig_vrt_height = vrt_height
        orig_vrt_width = vrt_width
        vrt_height = vrt_height + 2 * tile_edge_padding
        vrt_width = vrt_width + 2 * tile_edge_padding
        out_window = windows.Window(
            col_off=tile_edge_padding,
            row_off=tile_edge_padding,
            width=orig_vrt_width,
            height=orig_vrt_height,
        )

    vrt_params.update(
        dict(transform=vrt_transform, width=vrt_width, height=vrt_height))

    indexes = indexes if indexes is not None else src_dst.indexes
    out_shape = (len(indexes), tilesize, tilesize)

    nodata = nodata if nodata is not None else src_dst.nodata
    if nodata is not None:
        vrt_params.update(
            dict(nodata=nodata, add_alpha=False, src_nodata=nodata))

    if has_alpha_band(src_dst):
        vrt_params.update(dict(add_alpha=False))

    vrt_params.update(warp_vrt_option)
    with WarpedVRT(src_dst, **vrt_params) as vrt:
        data = vrt.read(
            out_shape=out_shape,
            indexes=indexes,
            window=out_window,
            resampling=Resampling[resampling_method],
        )
        mask = vrt.dataset_mask(out_shape=(tilesize, tilesize),
                                window=out_window)

        return data, mask
Example #38
0
def write_data_grid(file_name, file_data, file_ancillary=None):

    if 'bb_left' in list(file_ancillary.keys()):
        bb_left = file_ancillary['bb_left']
    else:
        log_stream.error(
            ' ===> Geographical info "bb_left" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'bb_bottom' in list(file_ancillary.keys()):
        bb_bottom = file_ancillary['bb_bottom']
    else:
        log_stream.error(
            ' ===> Geographical info "bb_bottom" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'res_lon' in list(file_ancillary.keys()):
        res_lon = file_ancillary['res_lon']
    else:
        log_stream.error(
            ' ===> Geographical info "res_lon" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'res_lat' in list(file_ancillary.keys()):
        res_lat = file_ancillary['res_lat']
    else:
        log_stream.error(
            ' ===> Geographical info "res_lat" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'transform' in list(file_ancillary.keys()):
        transform = file_ancillary['transform']
    else:
        log_stream.error(
            ' ===> Geographical info "transform" for writing ascii grid file is undefined.'
        )
        raise IOError(
            'Geographical info is mandatory. Check your static datasets.')
    if 'no_data' in list(file_ancillary.keys()):
        no_data = file_ancillary['no_data']
    else:
        no_data = -9999
    if 'espg' in list(file_ancillary.keys()):
        epsg = file_ancillary['epsg']
    else:
        epsg = proj_epsg_default
    if 'decimal_precision' in list(file_ancillary.keys()):
        decimal_precision = int(file_ancillary['decimal_precision'])
    else:
        decimal_num = Decimal(str(file_data[0][0]))
        decimal_precision = abs(decimal_num.as_tuple().exponent)

    if isinstance(epsg, int):
        crs = CRS.from_epsg(epsg)
    elif isinstance(epsg, str):
        crs = CRS.from_string(epsg)
    else:
        log_stream.error(
            ' ===> Geographical info "epsg" defined by using an unsupported format.'
        )
        raise IOError(
            'Geographical EPSG must be in string format "EPSG:4326" or integer format "4326".'
        )

    dset_meta = dict(driver='AAIGrid',
                     height=file_data.shape[0],
                     width=file_data.shape[1],
                     crs=crs,
                     count=1,
                     dtype=str(file_data.dtype),
                     transform=transform,
                     nodata=no_data,
                     decimal_precision=decimal_precision)

    with rasterio.open(file_name, 'w', **dset_meta) as dset_handle:
        dset_handle.write(file_data, 1)
Example #39
0
def read_data_grid(file_name,
                   output_format='data_array',
                   output_dtype='float32'):

    try:
        dset = rasterio.open(file_name)
        bounds = dset.bounds
        res = dset.res
        transform = dset.transform
        data = dset.read()

        if dset.crs is None:
            crs = CRS.from_string(proj_epsg_default)
        else:
            crs = dset.crs

        values = data[0, :, :]

        decimal_round = 7

        center_right = bounds.right - (res[0] / 2)
        center_left = bounds.left + (res[0] / 2)
        center_top = bounds.top - (res[1] / 2)
        center_bottom = bounds.bottom + (res[1] / 2)

        lon = np.arange(center_left, center_right + np.abs(res[0] / 2),
                        np.abs(res[0]), float)
        lat = np.arange(center_bottom, center_top + np.abs(res[0] / 2),
                        np.abs(res[1]), float)
        lons, lats = np.meshgrid(lon, lat)

        min_lon_round = round(np.min(lons), decimal_round)
        max_lon_round = round(np.max(lons), decimal_round)
        min_lat_round = round(np.min(lats), decimal_round)
        max_lat_round = round(np.max(lats), decimal_round)

        center_right_round = round(center_right, decimal_round)
        center_left_round = round(center_left, decimal_round)
        center_bottom_round = round(center_bottom, decimal_round)
        center_top_round = round(center_top, decimal_round)

        assert min_lon_round == center_left_round
        assert max_lon_round == center_right_round
        assert min_lat_round == center_bottom_round
        assert max_lat_round == center_top_round

        lats = np.flipud(lats)

        if output_format == 'data_array':

            data_obj = create_darray_2d(values,
                                        lons,
                                        lats,
                                        coord_name_x='west_east',
                                        coord_name_y='south_north',
                                        dim_name_x='west_east',
                                        dim_name_y='south_north')

        elif output_format == 'dictionary':

            data_obj = {
                'values': values,
                'longitude': lons,
                'latitude': lats,
                'transform': transform,
                'crs': crs,
                'bbox': [bounds.left, bounds.bottom, bounds.right, bounds.top],
                'bb_left': bounds.left,
                'bb_right': bounds.right,
                'bb_top': bounds.top,
                'bb_bottom': bounds.bottom,
                'res_lon': res[0],
                'res_lat': res[1]
            }
        else:
            log_stream.error(' ===> File static "' + file_name +
                             '" output format not allowed')
            raise NotImplementedError('Case not implemented yet')

    except IOError as io_error:

        data_obj = None
        log_stream.warning(
            ' ===> File static in ascii grid was not correctly open with error "'
            + str(io_error) + '"')
        log_stream.warning(' ===> Filename "' + os.path.split(file_name)[1] +
                           '"')

    return data_obj
Example #40
0
def test_geovector_has_given_crs():
    crs = CRS({'init': 'epsg:4326'})
    gv = GeoVector(None, crs)

    assert gv.crs == crs
Example #41
0
import numpy as np
from PIL import Image

from .cog import COGReader, ReaderMixin

try:
    import morecantile
    from morecantile import TileMatrixSet
    from rasterio.crs import CRS
    from rasterio.transform import from_bounds
    from rasterio.warp import reproject, transform_bounds, transform as transform_coords
    from rio_tiler.mercator import zoom_for_pixelsize

    DEFAULT_TMS = morecantile.tms.get("WebMercatorQuad")
    WGS84 = CRS.from_epsg(4326)
except ImportError:
    CRS = None
    DEFAULT_TMS = None
    TileMatrixSet = None
    WGS84 = None


@dataclass
class COGInfo:
    min_zoom: int
    max_zoom: int
    bounds: List[float]
    dtype: str
    color_interp: str
Example #42
0
def test_deprecated_param(path_rgb_byte_tif):
    """dst_crs is deprecated"""
    with rasterio.open(path_rgb_byte_tif) as src:
        with pytest.warns(RasterioDeprecationWarning):
            vrt = WarpedVRT(src, dst_crs=DST_CRS)
            assert vrt.dst_crs == CRS.from_string(DST_CRS)
Example #43
0
def _raster_get_stats(
    src_dst,
    indexes=None,
    nodata=None,
    overview_level=None,
    max_size=1024,
    percentiles=(2, 98),
    dst_crs=CRS({"init": "EPSG:4326"}),
    histogram_bins=10,
    histogram_range=None,
    resampling_method="bilinear",
    warp_vrt_option={},
):
    """
    Retrieve dataset statistics.

    Attributes
    ----------
    src_dst : rasterio.io.DatasetReader
        rasterio.io.DatasetReader object
    indexes : tuple, list, int, optional
        Dataset band indexes.
    nodata, int, optional
        Custom nodata value if not preset in dataset.
    overview_level : int, optional
        Overview (decimation) level to fetch.
    max_size: int, optional
        Maximum size of dataset to retrieve
        (will be used to calculate the overview level to fetch).
    percentiles : tulple, optional
        Percentile or sequence of percentiles to compute,
        which must be between 0 and 100 inclusive (default: (2, 98)).
    dst_crs: CRS or dict
        Target coordinate reference system (default: EPSG:4326).
    histogram_bins: int, optional
        Defines the number of equal-width histogram bins (default: 10).
    histogram_range: tuple or list, optional
        The lower and upper range of the bins. If not provided, range is simply
        the min and max of the array.
    resampling_method : str, optional (default: "bilinear")
        Resampling algorithm.
    warp_vrt_option: dict, optional (default: {})
        These will be passed to the rasterio.warp.WarpedVRT class.

    Returns
    -------
    out : dict
        bounds, mercator zoom range, band descriptions
        and band statistics: (percentiles), min, max, stdev, histogram

        e.g.
        {
            'bounds': {
                'value': (145.72265625, 14.853515625, 145.810546875, 14.94140625),
                'crs': '+init=EPSG:4326'
            },
            'minzoom': 8,
            'maxzoom': 12,
            'band_descriptions': [(1, 'red'), (2, 'green'), (3, 'blue'), (4, 'nir')]
            'statistics': {
                1: {
                    'pc': [38, 147],
                    'min': 20,
                    'max': 180,
                    'std': 28.123562304138662,
                    'histogram': [
                        [1625, 219241, 28344, 15808, 12325, 10687, 8535, 7348, 4656, 1208],
                        [20.0, 36.0, 52.0, 68.0, 84.0, 100.0, 116.0, 132.0, 148.0, 164.0, 180.0]
                    ]
                }
                ...
                3: {...}
                4: {...}
            }
        }

    """
    if isinstance(indexes, int):
        indexes = [indexes]
    elif isinstance(indexes, tuple):
        indexes = list(indexes)

    levels = src_dst.overviews(1)
    width = src_dst.width
    height = src_dst.height
    indexes = indexes if indexes else src_dst.indexes
    nodata = nodata if nodata is not None else src_dst.nodata
    bounds = transform_bounds(src_dst.crs,
                              dst_crs,
                              *src_dst.bounds,
                              densify_pts=21)

    minzoom, maxzoom = get_zooms(src_dst)

    def _get_descr(ix):
        """Return band description."""
        name = src_dst.descriptions[ix - 1]
        if not name:
            name = "band{}".format(ix)
        return name

    band_descriptions = [(ix, _get_descr(ix)) for ix in indexes]

    if len(levels):
        if overview_level:
            decim = levels[overview_level]
        else:
            # determine which zoom level to read
            for ii, decim in enumerate(levels):
                if (max(_div_round_up(width, decim),
                        _div_round_up(height, decim)) < max_size):
                    break
    else:
        decim = 1
        warnings.warn("Dataset has no overviews, reading the full dataset",
                      NoOverviewWarning)

    out_shape = (
        len(indexes),
        _div_round_up(height, decim),
        _div_round_up(width, decim),
    )

    vrt_params = dict(add_alpha=True)
    if has_alpha_band(src_dst):
        vrt_params.update(dict(add_alpha=False))

    if nodata is not None:
        vrt_params.update(
            dict(nodata=nodata, add_alpha=False, src_nodata=nodata))

    vrt_params.update(warp_vrt_option)
    with WarpedVRT(src_dst, **vrt_params) as vrt:
        arr = vrt.read(
            out_shape=out_shape,
            indexes=indexes,
            resampling=Resampling[resampling_method],
            masked=True,
        )

        params = {}
        if histogram_bins:
            params.update(dict(bins=histogram_bins))
        if histogram_range:
            params.update(dict(range=histogram_range))

        stats = {
            indexes[b]: _stats(arr[b], percentiles=percentiles, **params)
            for b in range(arr.shape[0])
            if vrt.colorinterp[b] != ColorInterp.alpha
        }

    return {
        "bounds": {
            "value": bounds,
            "crs":
            dst_crs.to_string() if isinstance(dst_crs, CRS) else dst_crs,
        },
        "minzoom": minzoom,
        "maxzoom": maxzoom,
        "band_descriptions": band_descriptions,
        "statistics": stats,
    }
Example #44
0
def reproject_geometry(
    geometry, src_crs=None, dst_crs=None, error_on_clip=False,
    validity_check=True
):
    """
    Reproject a geometry to target CRS.

    Also, clips geometry if it lies outside the destination CRS boundary.
    Supported destination CRSes for clipping: 4326 (WGS84), 3857 (Spherical
    Mercator) and 3035 (ETRS89 / ETRS-LAEA).

    Parameters
    ----------
    geometry : ``shapely.geometry``
    src_crs : ``rasterio.crs.CRS`` or EPSG code
        CRS of source data
    dst_crs : ``rasterio.crs.CRS`` or EPSG code
        target CRS
    error_on_clip : bool
        raises a ``RuntimeError`` if a geometry is outside of CRS bounds
        (default: False)
    validity_check : bool
        checks if reprojected geometry is valid and throws ``TopologicalError``
        if invalid (default: True)

    Returns
    -------
    geometry : ``shapely.geometry``
    """
    src_crs = _validated_crs(src_crs)
    dst_crs = _validated_crs(dst_crs)

    def _repair(geom):
        if geom.geom_type in ["Polygon", "MultiPolygon"]:
            return geom.buffer(0)
        else:
            return geom

    def _reproject_geom(geometry, src_crs, dst_crs):
        if geometry.is_empty or src_crs == dst_crs:
            return _repair(geometry)
        out_geom = _repair(
            to_shape(
                transform_geom(
                    src_crs.to_dict(), dst_crs.to_dict(), mapping(geometry)
                )
            )
        )
        if validity_check and (not out_geom.is_valid or out_geom.is_empty):
            raise TopologicalError("invalid geometry after reprojection")
        return out_geom

    # return repaired geometry if no reprojection needed
    if src_crs == dst_crs:
        return _repair(geometry)

    # if geometry potentially has to be clipped, reproject to WGS84 and clip
    # with CRS bounds
    elif dst_crs.is_epsg_code and (
        dst_crs.get("init") in CRS_BOUNDS) and (  # if known CRS
        not dst_crs.get("init") == "epsg:4326"  # WGS84 does not need clipping
    ):
        wgs84_crs = CRS().from_epsg(4326)
        # get dst_crs boundaries
        crs_bbox = box(*CRS_BOUNDS[dst_crs.get("init")])
        # reproject geometry to WGS84
        geometry_4326 = _reproject_geom(geometry, src_crs, wgs84_crs)
        # raise error if geometry has to be clipped
        if error_on_clip and not geometry_4326.within(crs_bbox):
            raise RuntimeError("geometry outside target CRS bounds")
        # clip geometry dst_crs boundaries and return
        return _reproject_geom(
            crs_bbox.intersection(geometry_4326), wgs84_crs, dst_crs
        )

    # return without clipping if destination CRS does not have defined bounds
    else:
        return _reproject_geom(geometry, src_crs, dst_crs)
Example #45
0
def get_crs(dataset, variable_name):
    """
    Return a PROJ4 projection string for a variable in a dataset.
    If non-standard 'proj4' attribute is found in attributes of dataset or
    variable, that is used instead.  Otherwise, the projection parameters are
    extracted from attributes in the grid_mapping variable in the dataset
    referenced from the data variable's attributes.

    :param dataset: open netCDF dataset
    :param variable_name: name of data variable to extract projection
    :return: PROJ4 projection string or None
    """

    ncatts = get_ncattrs(dataset.variables[variable_name])
    dsatts = get_ncattrs(dataset)

    # If dataset already includes proj4 string, just use it
    existing_proj4 = dsatts.get(PROJ4_KEY) or ncatts.get(PROJ4_KEY)
    if existing_proj4:
        return existing_proj4

    # Attempt to construct proj4 string based on CF convention parameters
    if 'grid_mapping' not in ncatts:
        logger.debug('grid_mapping attribute not found for variable {0}'.format(variable_name))
        return None

    if ncatts['grid_mapping'] not in dataset.variables:
        logger.debug('grid_mapping variable {0} not found in dataset'.format(ncatts['grid_mapping']))
        return None

    crs_variable = dataset.variables[ncatts['grid_mapping']]
    crs_atts = get_ncattrs(crs_variable)

    cf_crs_name = crs_atts.get('grid_mapping_name')
    if not (cf_crs_name and cf_crs_name in CF_PROJ4_PARAM_MAP):
        # Could not determine projection name
        logger.debug('No supported projection found for {0}'.format(cf_crs_name))
        return None

    param_map = CF_PROJ4_PARAM_MAP[cf_crs_name]

    proj4_params = {'proj': CF_PROJ4_NAMES[cf_crs_name]}

    expected_params = set(CF_PROJ4_PARAM_MAP[cf_crs_name].keys())
    if expected_params.difference(crs_atts):
        logger.debug('Missing expected parameters {0}'.format(expected_params.difference(crs_atts)))

    for param in expected_params.intersection(crs_atts):
        value = crs_atts[param]

        if param == 'standard_parallel' and '{' in param_map[param]:
            # Special case: variable number of standard parallels
            value = list(value)
            for index, val in enumerate(value, start=1):
                proj4_params[param_map[param].format(index)] = val
        else:
            proj4_params[param_map[param]] = value

    for param in set(CF_PROJ4_ELLPSOID_MAP.keys()).intersection(crs_atts):
        proj4_params[CF_PROJ4_ELLPSOID_MAP[param]] = crs_atts[param]

    try:
        return Proj(**CRS(proj4_params).to_dict()).srs

    except:
        # Could not create valid projection
        logger.debug('Could not create valid Proj4 projection from parameters')

    return None
Example #46
0
def set_crs(dataset, variable_name, projection, set_proj4_att=False):
    """
    Set the projection information into a grid_mapping variable and reference it
    from the data variable.

    :param dataset: dataset open in write or append mode
    :param variable_name: name of data variable to attach projection to
    :param projection: pyproj.Proj projection object
    :param set_proj4_att: if True, set the 'proj4' attribute on the variable
    """

    if not isinstance(projection, Proj):
        raise ValueError('Projection must be instance of pyproj.Proj')

    variable = dataset.variables[variable_name]

    if 'epsg:' in projection.srs:
        proj_string = epsg_to_proj4(re.search('(?<=epsg:)\d+', projection.srs).group())
    else:
        proj_string = projection.srs

    if set_proj4_att:
        variable.setncattr(PROJ4_KEY, proj_string)

    proj = CRS.from_string(proj_string)
    proj_data = proj.to_dict()
    proj_key = 'latlong' if not proj.is_projected else proj_data['proj']
    if not proj_key in PROJ4_CF_PARAM_MAP.keys():
        raise ValueError('CF Convention mapping is not yet available for projection {0}'.format(proj_key))

    crs_variable_name = 'crs_{0}'.format(pj_list[proj_key].replace(' ', '_').replace('/', ''))
    if not crs_variable_name in dataset.variables:
        crs_variable = dataset.createVariable(crs_variable_name, 'S1')

        ncatts = {'grid_mapping_name': PROJ4_CF_NAMES[proj_key]}

        out_proj_params = PROJ4_CF_PARAM_MAP[proj_key]
        for param in out_proj_params:
            if param.count('{'):
                # Special case - standard parallel
                keys = [param.format(i) for i in (1, 2)]
                values = [proj_data[key] for key in keys if key in proj_data]
                if values:
                    if len(values) == 1:
                        values = values[0]
                    ncatts[out_proj_params[param]] = values

            elif param in proj_data:
                ncatts[out_proj_params[param]] = proj_data[param]

        if 'datum' in proj_data and not 'ellps' in proj_data:
            # Not all datums link to available pj_ellps keys, some had to be added manually here
            if proj_data['datum'] in pj_ellps:
                proj_data['ellps'] = proj_data['datum']
            elif proj_data['datum'] == 'NAD83':
                proj_data['ellps'] = 'GRS80'
            elif proj_data['datum'] == 'NAD27':
                proj_data['ellps'] = 'clrk66'
            else:
                raise ValueError('projection ellipsoid must be specified, datum {0}'
                                 'does not match a known ellipsoid'.format(proj_data['datum']))

        # Extract out parameters of known ellipsoids
        if 'ellps' in proj_data:
            if not proj_data['ellps'] in pj_ellps:
                raise ValueError('projection ellipsoid does not match a known ellipsoid')

            ellipsoid_params = pj_ellps[proj_data['ellps']]
            for param in set(PROJ4_CF_ELLIPSOID_MAP.keys()).intersection(ellipsoid_params):
                proj_data[param] = ellipsoid_params[param]

        for param in set(PROJ4_CF_ELLIPSOID_MAP.keys()).intersection(proj_data):
            ncatts[PROJ4_CF_ELLIPSOID_MAP[param]] = proj_data[param]

        set_ncattrs(crs_variable, ncatts)

    variable.setncattr('grid_mapping', crs_variable_name)
Example #47
0
    tundra = 70
    artificial = 80
    bareland = 90
    snow = 100
    no_data = 255


SETTINGS = {
    'headers': {
        'headers': {
            'User-Agent':
            "Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11"
        }
    },
    'wgs84':
    CRS.from_epsg(4326),
    'data':
    cache_directories(get_data_dir()),
    'canopy_densities':
    list(range(0, 100, 1)),  # old setting in 5 increment
    'cover_classes': [GL30Classes.forest.value],
    'classify_years':
    list(range(1, 11)),
    'canopy_density':
    10,
    'clustering': [GL30Classes.forest.value],
    'reject': [
        GL30Classes.zero.value, GL30Classes.forest.value,
        GL30Classes.no_data.value
    ],
    'buffer':
def reproject_geometry(geometry,
                       src_crs=None,
                       dst_crs=None,
                       error_on_clip=False,
                       validity_check=True,
                       antimeridian_cutting=False):
    """
    Reproject a geometry to target CRS.

    Also, clips geometry if it lies outside the destination CRS boundary.
    Supported destination CRSes for clipping: 4326 (WGS84), 3857 (Spherical
    Mercator) and 3035 (ETRS89 / ETRS-LAEA).

    Parameters
    ----------
    geometry : ``shapely.geometry``
    src_crs : ``rasterio.crs.CRS`` or EPSG code
        CRS of source data
    dst_crs : ``rasterio.crs.CRS`` or EPSG code
        target CRS
    error_on_clip : bool
        raises a ``RuntimeError`` if a geometry is outside of CRS bounds
        (default: False)
    validity_check : bool
        checks if reprojected geometry is valid and throws ``TopologicalError``
        if invalid (default: True)
    antimeridian_cutting : bool
        cut geometry at Antimeridian; can result in a multipart output geometry

    Returns
    -------
    geometry : ``shapely.geometry``
    """
    src_crs = validate_crs(src_crs)
    dst_crs = validate_crs(dst_crs)

    def _reproject_geom(geometry, src_crs, dst_crs):
        if geometry.is_empty:
            return geometry
        else:
            out_geom = to_shape(
                transform_geom(src_crs.to_dict(),
                               dst_crs.to_dict(),
                               mapping(geometry),
                               antimeridian_cutting=antimeridian_cutting))
            return _repair(out_geom) if validity_check else out_geom

    # return repaired geometry if no reprojection needed
    if src_crs == dst_crs or geometry.is_empty:
        return _repair(geometry)

    # geometry needs to be clipped to its CRS bounds
    elif (dst_crs.is_epsg_code and  # just in case for an CRS with EPSG code
          dst_crs.get("init") in CRS_BOUNDS and  # if CRS has defined bounds
          dst_crs.get("init") !=
          "epsg:4326"  # and is not WGS84 (does not need clipping)
          ):
        wgs84_crs = CRS().from_epsg(4326)
        # get dst_crs boundaries
        crs_bbox = box(*CRS_BOUNDS[dst_crs.get("init")])
        # reproject geometry to WGS84
        geometry_4326 = _reproject_geom(geometry, src_crs, wgs84_crs)
        # raise error if geometry has to be clipped
        if error_on_clip and not geometry_4326.within(crs_bbox):
            raise RuntimeError("geometry outside target CRS bounds")
        # clip geometry dst_crs boundaries and return
        return _reproject_geom(crs_bbox.intersection(geometry_4326), wgs84_crs,
                               dst_crs)

    # return without clipping if destination CRS does not have defined bounds
    else:
        return _reproject_geom(geometry, src_crs, dst_crs)
Example #49
0
def _describe_file(filepath):
    """
    Helper function to describe a geospatial data
    First checks if a sidecar mcf file is available, if so uses that
    if not, script will parse the file to retrieve some info from the file

    :param filepath: path to file

    :returns: `dict` of GeoJSON item
    """

    content = {'bbox': None, 'geometry': None, 'properties': {}}

    mcf_file = '{}.yml'.format(os.path.splitext(filepath)[0])

    if os.path.isfile(mcf_file):
        try:
            from pygeometa.core import read_mcf, MCFReadError
            from pygeometa.schemas.stac import STACItemOutputSchema

            md = read_mcf(mcf_file)
            stacjson = STACItemOutputSchema.write(STACItemOutputSchema, md)
            stacdata = loads(stacjson)
            for k, v in stacdata.items():
                content[k] = v
        except ImportError:
            LOGGER.debug('pygeometa not found')
        except MCFReadError as err:
            LOGGER.warning('MCF error: {}'.format(err))
    else:
        LOGGER.debug('No mcf found at: {}'.format(mcf_file))

    if content['geometry'] is None and content['bbox'] is None:
        try:
            import rasterio
            from rasterio.crs import CRS
            from rasterio.warp import transform_bounds
        except ImportError as err:
            LOGGER.warning('rasterio not found')
            LOGGER.warning(err)
            return content

        try:
            import fiona
        except ImportError as err:
            LOGGER.warning('fiona not found')
            LOGGER.warning(err)
            return content

        try:  # raster
            LOGGER.debug('Testing raster data detection')
            d = rasterio.open(filepath)
            content['bbox'] = [
                d.bounds.left, d.bounds.bottom, d.bounds.right, d.bounds.top
            ]
            content['geometry'] = {
                'type':
                'Polygon',
                'coordinates': [[[d.bounds.left, d.bounds.bottom],
                                 [d.bounds.left, d.bounds.top],
                                 [d.bounds.right, d.bounds.top],
                                 [d.bounds.right, d.bounds.bottom],
                                 [d.bounds.left, d.bounds.bottom]]]
            }
            for k, v in d.tags(1).items():
                content['properties'][k] = v
        except rasterio.errors.RasterioIOError:
            LOGGER.debug('Testing vector data detection')
            d = fiona.open(filepath)
            scrs = CRS(d.crs)
            if scrs.to_epsg() is not None and scrs.to_epsg() != 4326:
                tcrs = CRS.from_epsg(4326)
                bnds = transform_bounds(scrs, tcrs, d.bounds[0], d.bounds[1],
                                        d.bounds[2], d.bounds[3])
                content['properties']['projection'] = scrs.to_epsg()
            else:
                bnds = d.bounds

            if d.schema['geometry'] not in [None, 'None']:
                content['bbox'] = [bnds[0], bnds[1], bnds[2], bnds[3]]
                content['geometry'] = {
                    'type':
                    'Polygon',
                    'coordinates': [[[bnds[0], bnds[1]], [bnds[0], bnds[3]],
                                     [bnds[2], bnds[3]], [bnds[2], bnds[1]],
                                     [bnds[0], bnds[1]]]]
                }

            for k, v in d.schema['properties'].items():
                content['properties'][k] = v

        if d.driver == 'ESRI Shapefile':
            id_ = os.path.splitext(os.path.basename(filepath))[0]
            content['assets'] = {}
            for suffix in ['shx', 'dbf', 'prj', 'shp.xml']:
                content['assets'][suffix] = {
                    'href': './{}.{}'.format(id_, suffix)
                }
    return content
Example #50
0
def test_crs_constructor_crs_obj():
    """Can create a CRS from a CRS obj"""
    crs = CRS(CRS(init='epsg:3857'))
    assert crs['init'] == 'epsg:3857'
    assert 'PROJCS["WGS 84 / Pseudo-Mercator"' in crs.wkt
Example #51
0
def test_to_authority__no_code_available():
    lcc_crs = CRS.from_string(
        '+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc '
        '+x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0')
    assert lcc_crs.to_authority() is None
Example #52
0
def test_from_user_input_custom_crs_class():
    """Support comparison to foreign objects that provide to_wkt()"""
    assert CRS.from_user_input(CustomCRS()) == CRS.from_epsg(4326)
Example #53
0
def test_esri_auth__to_authority():
    assert CRS.from_user_input('ESRI:54009').to_authority() == ('ESRI',
                                                                '54009')
Example #54
0
"""Useful constants.

"""
from rasterio.crs import CRS

WGS84_SRID = 4326
#: WGS84 CRS.
WGS84_CRS = CRS.from_epsg(WGS84_SRID)

WEB_MERCATOR_SRID = 3857
#: Web Mercator CRS.
WEB_MERCATOR_CRS = CRS.from_epsg(WEB_MERCATOR_SRID)

# Best widely used, equal area projection according to
# http://icaci.org/documents/ICC_proceedings/ICC2001/icc2001/file/f24014.doc
# (found on https://en.wikipedia.org/wiki/Winkel_tripel_projection#Comparison_with_other_projections)
#: Eckert IV CRS.
EQUAL_AREA_CRS = CRS({'proj': 'eck4'})

DEFAULT_SRID = WGS84_SRID
#: Default CRS, set to :py:data:`~telluric.constants.WGS84_CRS`.
DEFAULT_CRS = WGS84_CRS


def _MERCATOR_RESOLUTION_MAPPING(zoom_level):
    return (2 * 20037508.342789244) / (256 * pow(2, zoom_level))


MERCATOR_RESOLUTION_MAPPING = dict(
    (i, _MERCATOR_RESOLUTION_MAPPING(i)) for i in range(19))
Example #55
0
def test_esri_auth__from_string():
    assert CRS.from_string('ESRI:54009').to_string() == 'ESRI:54009'
Example #56
0
        "boundless": mercantile.Tile(x=540, y=497, z=10),
    },
    "dateline": {
        "full": mercantile.Tile(x=510, y=169, z=10),
        "masked": mercantile.Tile(x=510, y=168, z=10),
        "boundless": mercantile.Tile(x=509, y=171, z=10),
    },
}

# LC08_L1TP_212004_20190816_20190902_01_T1
north = {
    "bounds":
    BoundingBox(left=433192.5, bottom=8534992.5, right=707407.5,
                top=8809207.5),
    "crs":
    CRS.from_epsg(32633),
}

# LC08_L1GT_054115_20200120_20200120_01_RT
south = {
    "bounds":
    BoundingBox(left=123892.5,
                bottom=-1521007.5,
                right=387607.5,
                top=-1258492.5),
    "crs":
    CRS.from_epsg(3031),
}

# LC08_L1TP_085024_20170816_20170825_01_T1
dateline = {
Example #57
0
def test_crs_constructor_keywords():
    """Can create a CRS from keyword args, ignoring unknowns"""
    crs = CRS(init='epsg:3857', foo='bar')
    assert crs['init'] == 'epsg:3857'
    assert 'PROJCS["WGS 84 / Pseudo-Mercator"' in crs.wkt
Example #58
0
def warp(
    ctx,
    files,
    output,
    driver,
    like,
    dst_crs,
    dimensions,
    src_bounds,
    dst_bounds,
    res,
    resampling,
    src_nodata,
    dst_nodata,
    threads,
    check_invert_proj,
    overwrite,
    creation_options,
    target_aligned_pixels,
    warper_options,
):
    """
    Warp a raster dataset.

    If a template raster is provided using the --like option, the
    coordinate reference system, affine transform, and dimensions of
    that raster will be used for the output.  In this case --dst-crs,
    --bounds, --res, and --dimensions options are not applicable and
    an exception will be raised.

    \b
        $ rio warp input.tif output.tif --like template.tif

    The output coordinate reference system may be either a PROJ.4 or
    EPSG:nnnn string,

    \b
        --dst-crs EPSG:4326
        --dst-crs '+proj=longlat +ellps=WGS84 +datum=WGS84'

    or a JSON text-encoded PROJ.4 object.

    \b
        --dst-crs '{"proj": "utm", "zone": 18, ...}'

    If --dimensions are provided, --res and --bounds are not applicable and an
    exception will be raised.
    Resolution is calculated based on the relationship between the
    raster bounds in the target coordinate system and the dimensions,
    and may produce rectangular rather than square pixels.

    \b
        $ rio warp input.tif output.tif --dimensions 100 200 \\
        > --dst-crs EPSG:4326

    If --bounds are provided, --res is required if --dst-crs is provided
    (defaults to source raster resolution otherwise).

    \b
        $ rio warp input.tif output.tif \\
        > --bounds -78 22 -76 24 --res 0.1 --dst-crs EPSG:4326

    """
    output, files = resolve_inout(files=files,
                                  output=output,
                                  overwrite=overwrite)

    resampling = Resampling[resampling]  # get integer code for method

    if not len(res):
        # Click sets this as an empty tuple if not provided
        res = None
    else:
        # Expand one value to two if needed
        res = (res[0], res[0]) if len(res) == 1 else res

    if target_aligned_pixels:
        if not res:
            raise click.BadParameter(
                '--target-aligned-pixels requires a specified resolution')
        if src_bounds or dst_bounds:
            raise click.BadParameter(
                '--target-aligned-pixels cannot be used with '
                '--src-bounds or --dst-bounds')

    # Check invalid parameter combinations
    if like:
        invalid_combos = (dimensions, dst_bounds, dst_crs, res)
        if any(p for p in invalid_combos if p is not None):
            raise click.BadParameter(
                "--like cannot be used with any of --dimensions, --bounds, "
                "--dst-crs, or --res")

    elif dimensions:
        invalid_combos = (dst_bounds, res)
        if any(p for p in invalid_combos if p is not None):
            raise click.BadParameter(
                "--dimensions cannot be used with --bounds or --res")

    with ctx.obj['env']:
        setenv(CHECK_WITH_INVERT_PROJ=check_invert_proj)

        with rasterio.open(files[0]) as src:
            left, bottom, right, top = src.bounds

            out_kwargs = src.profile
            out_kwargs.pop("driver", None)
            if driver:
                out_kwargs["driver"] = driver

            # Sort out the bounds options.
            if src_bounds and dst_bounds:
                raise click.BadParameter(
                    "--src-bounds and destination --bounds may not be "
                    "specified simultaneously.")

            if like:
                with rasterio.open(like) as template_ds:
                    dst_crs = template_ds.crs
                    dst_transform = template_ds.transform
                    dst_height = template_ds.height
                    dst_width = template_ds.width

            elif dst_crs is not None:
                try:
                    dst_crs = CRS.from_string(dst_crs)
                except ValueError as err:
                    raise click.BadParameter(str(err),
                                             param='dst_crs',
                                             param_hint='dst_crs')

                if dimensions:
                    # Calculate resolution appropriate for dimensions
                    # in target.
                    dst_width, dst_height = dimensions
                    bounds = src_bounds or src.bounds
                    try:
                        xmin, ymin, xmax, ymax = transform_bounds(
                            src.crs, dst_crs, *bounds)
                    except CRSError as err:
                        raise click.BadParameter(str(err),
                                                 param='dst_crs',
                                                 param_hint='dst_crs')
                    dst_transform = Affine(
                        (xmax - xmin) / float(dst_width), 0, xmin, 0,
                        (ymin - ymax) / float(dst_height), ymax)

                elif src_bounds or dst_bounds:
                    if not res:
                        raise click.BadParameter(
                            "Required when using --bounds.",
                            param='res',
                            param_hint='res')

                    if src_bounds:
                        try:
                            xmin, ymin, xmax, ymax = transform_bounds(
                                src.crs, dst_crs, *src_bounds)
                        except CRSError as err:
                            raise click.BadParameter(str(err),
                                                     param='dst_crs',
                                                     param_hint='dst_crs')
                    else:
                        xmin, ymin, xmax, ymax = dst_bounds

                    dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax)
                    dst_width = max(int(ceil((xmax - xmin) / res[0])), 1)
                    dst_height = max(int(ceil((ymax - ymin) / res[1])), 1)

                else:
                    try:
                        if src.transform.is_identity and src.gcps:
                            src_crs = src.gcps[1]
                            kwargs = {'gcps': src.gcps[0]}
                        else:
                            src_crs = src.crs
                            kwargs = src.bounds._asdict()
                        dst_transform, dst_width, dst_height = calcdt(
                            src_crs,
                            dst_crs,
                            src.width,
                            src.height,
                            resolution=res,
                            **kwargs,
                            **warper_options)
                    except CRSError as err:
                        raise click.BadParameter(str(err),
                                                 param='dst_crs',
                                                 param_hint='dst_crs')

            elif dimensions:
                # Same projection, different dimensions, calculate resolution.
                dst_crs = src.crs
                dst_width, dst_height = dimensions
                l, b, r, t = src_bounds or (left, bottom, right, top)
                dst_transform = Affine((r - l) / float(dst_width), 0, l, 0,
                                       (b - t) / float(dst_height), t)

            elif src_bounds or dst_bounds:
                # Same projection, different dimensions and possibly
                # different resolution.
                if not res:
                    res = (src.transform.a, -src.transform.e)

                dst_crs = src.crs
                xmin, ymin, xmax, ymax = (src_bounds or dst_bounds)
                dst_transform = Affine(res[0], 0, xmin, 0, -res[1], ymax)
                dst_width = max(int(round((xmax - xmin) / res[0])), 1)
                dst_height = max(int(round((ymax - ymin) / res[1])), 1)

            elif res:
                # Same projection, different resolution.
                dst_crs = src.crs
                dst_transform = Affine(res[0], 0, left, 0, -res[1], top)
                dst_width = max(int(round((right - left) / res[0])), 1)
                dst_height = max(int(round((top - bottom) / res[1])), 1)

            else:
                dst_crs = src.crs
                inv_transform = ~src.transform
                eps = sys.float_info.epsilon
                c1, r1 = inv_transform * (left + eps, top + eps)
                c2, r2 = inv_transform * (right + eps, top + eps)
                c3, r3 = inv_transform * (right + eps, bottom + eps)
                c4, r4 = inv_transform * (left + eps, bottom + eps)
                col1 = min(c1, c2, c3, c4)
                col2 = max(c1, c2, c3, c4)
                row1 = min(r1, r2, r3, r4)
                row2 = max(r1, r2, r3, r4)
                col1 = floor(col1)
                col2 = ceil(col2)
                row1 = floor(row1)
                row2 = ceil(row2)
                px = (right - left) / (col2 - col1)
                py = (top - bottom) / (row2 - row1)
                res = max(px, py)
                dst_width = max(int(round((right - left) / res)), 1)
                dst_height = max(int(round((top - bottom) / res)), 1)
                dst_transform = Affine.translation(left, top) * Affine.scale(
                    res, -res)

            if target_aligned_pixels:
                dst_transform, dst_width, dst_height = aligned_target(
                    dst_transform, dst_width, dst_height, res)

            # If src_nodata is not None, update the dst metadata NODATA
            # value to src_nodata (will be overridden by dst_nodata if it is not None
            if src_nodata is not None:
                # Update the dst nodata value
                out_kwargs.update(nodata=src_nodata)

            # Validate a manually set destination NODATA value
            # against the input datatype.
            if dst_nodata is not None:
                if src_nodata is None and src.meta['nodata'] is None:
                    raise click.BadParameter(
                        "--src-nodata must be provided because dst-nodata is not None"
                    )
                else:
                    # Update the dst nodata value
                    out_kwargs.update(nodata=dst_nodata)

            # When the bounds option is misused, extreme values of
            # destination width and height may result.
            if (dst_width < 0 or dst_height < 0 or dst_width > MAX_OUTPUT_WIDTH
                    or dst_height > MAX_OUTPUT_HEIGHT):
                raise click.BadParameter(
                    "Invalid output dimensions: {0}.".format(
                        (dst_width, dst_height)))

            out_kwargs.update(crs=dst_crs,
                              transform=dst_transform,
                              width=dst_width,
                              height=dst_height)

            # Adjust block size if necessary.
            if "blockxsize" in out_kwargs and dst_width < int(
                    out_kwargs["blockxsize"]):
                del out_kwargs["blockxsize"]
                logger.warning(
                    "Blockxsize removed from creation options to accomodate small output width"
                )
            if "blockysize" in out_kwargs and dst_height < int(
                    out_kwargs["blockysize"]):
                del out_kwargs["blockysize"]
                logger.warning(
                    "Blockxsize removed from creation options to accomodate small output height"
                )

            out_kwargs.update(**creation_options)

            with rasterio.open(output, 'w', **out_kwargs) as dst:
                reproject(source=rasterio.band(src,
                                               list(range(1, src.count + 1))),
                          destination=rasterio.band(
                              dst, list(range(1, src.count + 1))),
                          src_transform=src.transform,
                          src_crs=src.crs,
                          src_nodata=src_nodata,
                          dst_transform=out_kwargs['transform'],
                          dst_crs=out_kwargs['crs'],
                          dst_nodata=dst_nodata,
                          resampling=resampling,
                          num_threads=threads,
                          **warper_options)
Example #59
0
"""rio-tiler constant values."""

import multiprocessing
import os
from typing import Sequence, Tuple, Union

import morecantile
from rasterio.crs import CRS

NumType = Union[float, int]
BBox = Tuple[float, float, float, float]
ColorTuple = Tuple[int, int, int, int]
NoData = Union[float, int, str]
Indexes = Union[Sequence[int], int]

MAX_THREADS = int(
    os.environ.get("MAX_THREADS",
                   multiprocessing.cpu_count() * 5))

WEB_MERCATOR_CRS = CRS.from_epsg(3857)
WGS84_CRS = CRS.from_epsg(4326)

WEB_MERCATOR_TMS = morecantile.tms.get("WebMercatorQuad")
Example #60
0
def wms_vrt(wms_file, bounds=None, resolution=None):
    """Make a VRT XML document from a wms file.
    Parameters
    ----------
    wms_file : str
        The source wms file
    bounds : GeoVector, optional
        The requested footprint of the generated VRT
    resolution : float, optional
        The requested resolution of the generated VRT
    Returns
    -------
    bytes
        An ascii-encoded string (an ElementTree detail)
    """

    from telluric import rasterization, constants
    wms_tree = ET.parse(wms_file)
    service = wms_tree.find(".//Service")
    if service is not None:
        service_name = service.attrib.get("name")
    else:
        raise ValueError("Service tag is required")
    # definition is based on https://www.gdal.org/frmt_wms.html
    if service_name == "VirtualEarth":
        left = find_and_convert_to_type(float, wms_tree,
                                        ".//DataWindow/UpperLeftX",
                                        -20037508.34)
        up = find_and_convert_to_type(float, wms_tree,
                                      ".//DataWindow/UpperLeftY", 20037508.34)
        right = find_and_convert_to_type(float, wms_tree,
                                         ".//DataWindow/LowerRightX",
                                         20037508.34)
        bottom = find_and_convert_to_type(float, wms_tree,
                                          ".//DataWindow/LowerRightY",
                                          -20037508.34)
        upper_bound_zoom = find_and_convert_to_type(int, wms_tree,
                                                    ".//DataWindow/TileLevel",
                                                    19)
        projection = find_and_convert_to_type(str, wms_tree, ".//Projection",
                                              "EPSG: 3857")
        projection = CRS(init=projection)
        blockx = find_and_convert_to_type(str, wms_tree, ".//BlockSizeX", 256)
        blocky = find_and_convert_to_type(str, wms_tree, ".//BlockSizeY", 256)
    else:
        left = find_and_convert_to_type(float, wms_tree,
                                        ".//DataWindow/UpperLeftX", -180.0)
        up = find_and_convert_to_type(float, wms_tree,
                                      ".//DataWindow/UpperLeftY", 90.0)
        right = find_and_convert_to_type(float, wms_tree,
                                         ".//DataWindow/LowerRightX", 180.0)
        bottom = find_and_convert_to_type(float, wms_tree,
                                          ".//DataWindow/LowerRightY", -90.0)
        upper_bound_zoom = find_and_convert_to_type(int, wms_tree,
                                                    ".//DataWindow/TileLevel",
                                                    0)
        projection = find_and_convert_to_type(str, wms_tree, ".//Projection",
                                              "EPSG:4326")
        blockx = find_and_convert_to_type(str, wms_tree, ".//BlockSizeX", 1024)
        blocky = find_and_convert_to_type(str, wms_tree, ".//BlockSizeY", 1024)
        projection = CRS(init=projection)

    bands_count = find_and_convert_to_type(int, wms_tree, ".//BandsCount", 3)
    data_type = find_and_convert_to_type(str, wms_tree, ".//DataType", "Byte")

    src_bounds = (left, bottom, right, up)
    bounds = bounds.get_bounds(crs=projection) or src_bounds
    src_resolution = constants.MERCATOR_RESOLUTION_MAPPING[upper_bound_zoom]
    resolution = resolution or constants.MERCATOR_RESOLUTION_MAPPING[
        upper_bound_zoom]
    dst_width, dst_height, transform = rasterization.raster_data(
        bounds=bounds, dest_resolution=resolution)
    orig_width, orig_height, orig_transform = rasterization.raster_data(
        bounds=src_bounds, dest_resolution=src_resolution)
    src_window = from_bounds(*bounds, transform=orig_transform)

    vrt = BaseVRT(dst_width, dst_height, projection, transform)

    vrt.add_metadata(domain="IMAGE_STRUCTURE", items={"INTERLEAVE": "PIXEL"})

    if bands_count != 3:
        raise ValueError("We support currently on 3 bands WMS")

    for idx, band in enumerate(["RED", "GREEN", "BLUE"]):
        bidx = idx + 1

        band_element = vrt.add_band(data_type, bidx, band)
        dst_window = Window(0, 0, dst_width, dst_height)

        vrt.add_band_simplesource(band_element, bidx, data_type, False,
                                  os.path.abspath(wms_file), orig_width,
                                  orig_height, blockx, blocky, src_window,
                                  dst_window)

    return vrt