예제 #1
0
def test_rotation_angle():
    assert Affine.identity().rotation_angle == 0.0
    assert Affine.scale(2).rotation_angle == 0.0
    assert Affine.scale(2, 1).rotation_angle == 0.0
    assert Affine.translation(32, -47).rotation_angle == pytest.approx(0.0)
    assert Affine.rotation(30).rotation_angle == pytest.approx(30)
    assert Affine.rotation(-150).rotation_angle == pytest.approx(-150)
예제 #2
0
 def test_is_orthonormal(self):
     assert Affine.identity().is_orthonormal
     assert Affine.translation(4, -1).is_orthonormal
     assert Affine.rotation(90).is_orthonormal
     assert Affine.rotation(-26).is_orthonormal
     assert not Affine.scale(2.5, 6.1).is_orthonormal
     assert not Affine.scale(.5, 2).is_orthonormal
     assert not Affine.shear(4, -1).is_orthonormal
예제 #3
0
 def test_scale_constructor(self):
     scale = Affine.scale(5)
     assert isinstance(scale, Affine)
     assert_equal(tuple(scale), (5,0,0, 0,5,0, 0,0,1))
     scale = Affine.scale(-1, 2)
     assert_equal(tuple(scale), (-1,0,0, 0,2,0, 0,0,1))
     assert_equal(tuple(Affine.scale(1)), 
         tuple(Affine.identity()))
예제 #4
0
 def test_determinant(self):
     assert_equal(Affine.identity().determinant, 1)
     assert_equal(Affine.scale(2).determinant, 4)
     assert_equal(Affine.scale(0).determinant, 0)
     assert_equal(Affine.scale(5, 1).determinant, 5)
     assert_equal(Affine.scale(-1, 1).determinant, -1)
     assert_equal(Affine.scale(-1, 0).determinant, 0)
     assert_almost_equal(Affine.rotation(77).determinant, 1)
     assert_almost_equal(Affine.translation(32, -47).determinant, 1)
예제 #5
0
 def test_determinant(self):
     assert Affine.identity().determinant == 1
     assert Affine.scale(2).determinant == 4
     assert Affine.scale(0).determinant == 0
     assert Affine.scale(5, 1).determinant == 5
     assert Affine.scale(-1, 1).determinant == -1
     assert Affine.scale(-1, 0).determinant == 0
     assert Affine.rotation(77).determinant == pytest.approx(1)
     assert Affine.translation(32, -47).determinant == pytest.approx(1)
예제 #6
0
def test_eccentricity():
    assert Affine.identity().eccentricity == 0.0
    assert Affine.scale(2).eccentricity == 0.0
    #assert_equal(Affine.scale(0).eccentricity, ?)
    assert Affine.scale(2, 1).eccentricity == pytest.approx(math.sqrt(3) / 2)
    assert Affine.scale(2, 3).eccentricity == pytest.approx(math.sqrt(5) / 3)
    assert Affine.scale(1, 0).eccentricity == 1.0
    assert Affine.rotation(77).eccentricity == pytest.approx(0.0)
    assert Affine.translation(32, -47).eccentricity == pytest.approx(0.0)
    assert Affine.scale(-1, 1).eccentricity == pytest.approx(0.0)
예제 #7
0
def test_eccentricity_complex():
    assert \
        (Affine.scale(2, 3) * Affine.rotation(77)).eccentricity == \
        pytest.approx(math.sqrt(5) / 3)
    assert \
        (Affine.rotation(77) * Affine.scale(2, 3)).eccentricity == \
        pytest.approx(math.sqrt(5) / 3)
    assert \
        (Affine.translation(32, -47) * Affine.rotation(77) * Affine.scale(2, 3)).eccentricity == \
        pytest.approx(math.sqrt(5) / 3)
예제 #8
0
 def test_scale_constructor(self):
     scale = Affine.scale(5)
     assert isinstance(scale, Affine)
     assert \
         tuple(scale) == \
         (5, 0, 0,
          0, 5, 0,
          0, 0, 1)
     scale = Affine.scale(-1, 2)
     assert \
         tuple(scale) == \
         (-1, 0, 0,
          0, 2, 0,
          0, 0, 1)
     assert tuple(Affine.scale(1)) == tuple(Affine.identity())
예제 #9
0
def zoom_factor(args, crs):
    # Determine the geographic "zoom factor" for the request.
    # (Larger zoom factor means deeper zoom.  Smaller zoom factor means larger area.)
    # Extract request bbox and crs
    width = int(args['width'])
    height = int(args['height'])
    minx, miny, maxx, maxy = _get_geobox_xy(args, crs)

    # Project to a geographic coordinate system
    # This is why we can't just use the regular geobox.  The scale needs to be
    # "standardised" in some sense, not dependent on the CRS of the request.
    geo_crs = geometry.CRS("EPSG:4326")
    minx, miny, maxx, maxy = _bounding_pts(minx,
                                           miny,
                                           maxx,
                                           maxy,
                                           width,
                                           height,
                                           crs,
                                           dst_crs=geo_crs)
    # Create geobox affine transformation (N.B. Don't need an actual Geobox)
    affine = Affine.translation(minx, miny) * Affine.scale(
        (maxx - minx) / width, (maxy - miny) / height)
    # Zoom factor is the reciprocal of the square root of the transform determinant
    # (The determinant is x scale factor multiplied by the y scale factor)
    return 1.0 / math.sqrt(affine.determinant)
예제 #10
0
    def transform(self, recalc=False):
        """
        Parameters
        ----------
        recalc: bool, optional
            If True, it will re-calculate the transform instead of using
            the cached transform.

        Returns
        -------
        :obj:`affine.Afffine`:
            The affine of the :obj:`xarray.Dataset` | :obj:`xarray.DataArray`
        """
        transform = self._cached_transform()
        if transform and not transform.is_rectilinear:
            if recalc:
                warnings.warn("Non-rectilinear transform found. Unable to recalculate.")
            return transform

        try:
            src_left, _, _, src_top = self.bounds(recalc=recalc)
            src_resolution_x, src_resolution_y = self.resolution(recalc=recalc)
        except (DimensionMissingCoordinateError, DimensionError):
            return Affine.identity()
        return Affine.translation(src_left, src_top) * Affine.scale(
            src_resolution_x, src_resolution_y
        )
예제 #11
0
def test_geometry_window_rotated_boundless():
    """Get the right boundless window for a rotated dataset"""
    sqrt2 = math.sqrt(2.0)
    dataset = mock.MagicMock()
    dataset.transform = (Affine.rotation(-45.0) *
                         Affine.translation(-sqrt2, sqrt2) *
                         Affine.scale(sqrt2 / 2.0, -sqrt2 / 2.0))
    dataset.height = 4.0
    dataset.width = 4.0

    geometry = {
        "type":
        "Polygon",
        "coordinates": [[
            (-2.0, -2.0),
            (-2.0, 2.0),
            (2.0, 2.0),
            (2.0, -2.0),
            (-2.0, -2.0),
        ]],
    }

    win = geometry_window(dataset, [geometry, geometry], boundless=True)
    assert win.col_off == pytest.approx(-2.0)
    assert win.row_off == pytest.approx(-2.0)
    assert win.width == pytest.approx(2.0 * dataset.width)
    assert win.height == pytest.approx(2.0 * dataset.height)
예제 #12
0
def georef_nc_to_tif(env, target, source):
    nc = Dataset(str(source[0]))
    var = nc.variables[nc.subject]
    data = var[:].squeeze().data.astype(np.int32)
    nodata = var.missing_value
    lat_bnds = nc.variables['latitude_bnds'][:]
    lon_bnds = nc.variables['longitude_bnds'][:]

    yoff, xoff = data.shape
    sx = np.diff(lon_bnds).mean()
    sy = np.diff(lat_bnds).mean()

    affine = Affine.translation(lon_bnds.min(), lat_bnds.max()) * Affine.scale(
        sx, -sy)
    with rasterio.open(str(target[0]),
                       'w',
                       driver='GTiff',
                       width=xoff,
                       height=yoff,
                       crs={'init': 'epsg:4326'},
                       transform=affine,
                       count=1,
                       nodata=nodata,
                       dtype=str(data.dtype)) as dst:
        dst.write(np.flipud(data), 1)

    nc.close()
    return 0
def simple_geobox():
    from datacube_ows.wms_utils import _get_geobox
    from affine import Affine
    from datacube.utils import geometry

    aff = Affine.translation(145.0, -35.0) * Affine.scale(1.0 / 256, 2.0 / 256)
    return geometry.GeoBox(256, 256, aff, 'EPSG:4326')
예제 #14
0
def test_issue_2138():
    """WindowError is raised if bounds and transform are inconsistent"""
    w, s, e, n = 1.0, 45.7, 1.2, 45.9
    a = 0.001
    transform = Affine.translation(w, n) * Affine.scale(a, -a)
    with pytest.raises(WindowError):
        from_bounds(w, n, e, s, transform)
예제 #15
0
def black_and_white_raster(band_names=[],
                           height=10,
                           width=10,
                           dtype=np.uint16,
                           crs=WEB_MERCATOR_CRS,
                           affine=None):
    if affine is None:
        eps = 1e-100
        affine = Affine.translation(10, 12) * Affine.scale(1, -1)
    bands_num = len(band_names)
    shape = [bands_num, height, width]
    array = np.zeros(shape, dtype=dtype)
    mask = np.full(shape, False, dtype=np.bool)
    val = 0
    for i in range(height):
        for j in range(width):
            for z in range(bands_num):
                array[z, i, j] = val
                val = 1 - val

    image = np.ma.array(data=array, mask=mask)
    raster = GeoRaster2(image=image,
                        affine=affine,
                        crs=crs,
                        band_names=band_names)
    return raster
예제 #16
0
    def from_geopolygon(cls, geopolygon, resolution, crs=None, align=None):
        """
        :type geopolygon: geometry.Geometry
        :param resolution: (y_resolution, x_resolution)
        :param geometry.CRS crs: CRS to use, if different from the geopolygon
        :param (float,float) align: Align geobox such that point 'align' lies on the pixel boundary.
        :rtype: GeoBox
        """
        align = align or (0.0, 0.0)
        assert 0.0 <= align[1] <= abs(
            resolution[1]), "X align must be in [0, abs(x_resolution)] range"
        assert 0.0 <= align[0] <= abs(
            resolution[0]), "Y align must be in [0, abs(y_resolution)] range"

        if crs is None:
            crs = geopolygon.crs
        else:
            geopolygon = geopolygon.to_crs(crs)

        bounding_box = geopolygon.boundingbox
        offx, width = _align_pix(bounding_box.left, bounding_box.right,
                                 resolution[1], align[1])
        offy, height = _align_pix(bounding_box.bottom, bounding_box.top,
                                  resolution[0], align[0])
        affine = (Affine.translation(offx, offy) *
                  Affine.scale(resolution[1], resolution[0]))
        return GeoBox(crs=crs, affine=affine, width=width, height=height)
예제 #17
0
def render_tile_from_sources(
    tile, sources, transformation=None, format=None, scale=1, expand=True
):
    """Render a tile into Web Mercator.

    Arguments:
        tile {mercantile.Tile} -- Tile to render.
        sources {list} -- Sources to render from.

    Keyword Arguments:
        transformation {Transformation} -- Transformation to apply. (default: {None})
        format {function} -- Output format. (default: {None})
        scale {int} -- Output scale factor. (default: {1})
        expand {bool} -- Whether to expand single-band, paletted sources to RGBA. (default: {True})

    Returns:
        (dict, bytes) -- Tuple of HTTP headers (dict) and bytes.
    """
    bounds = Bounds(mercantile.xy_bounds(tile), WEB_MERCATOR_CRS)
    shape = tuple(map(int, Affine.scale(scale) * TILE_SHAPE))

    return render(
        bounds,
        shape,
        WEB_MERCATOR_CRS,
        sources=sources,
        format=format,
        transformation=transformation,
        expand=expand,
    )
예제 #18
0
    def from_geopolygon(cls, geopolygon, resolution, crs=None, align=None):
        """
        :type geopolygon: GeoPolygon
        :param resolution: (x_resolution, y_resolution)
        :param CRS crs: CRS to use, if different from the geopolygon
        :param (float,float) align: Alight geobox such that point 'align' lies on the pixel boundary.
        :rtype: GeoBox
        """
        # TODO: currently only flipped Y-axis data is supported

        assert resolution[1] > 0
        assert resolution[0] < 0

        align = align or (0.0, 0.0)
        assert 0.0 <= align[1] <= abs(resolution[1])
        assert 0.0 <= align[0] <= abs(resolution[0])

        if crs is None:
            crs = geopolygon.crs
        else:
            geopolygon = geopolygon.to_crs(crs)

        def align_pix(val, res, off):
            return math.floor((val-off)/res) * res + off

        bounding_box = geopolygon.boundingbox
        left = align_pix(bounding_box.left, resolution[1], align[1])
        top = align_pix(bounding_box.top, resolution[0], align[0])
        affine = (Affine.translation(left, top) * Affine.scale(resolution[1], resolution[0]))
        return GeoBox(crs=crs,
                      affine=affine,
                      width=int(math.ceil((bounding_box.right-left)/resolution[1])),
                      height=int(math.ceil((bounding_box.bottom-top)/resolution[0])))
예제 #19
0
def test_move(fps1px):
    fps = fps1px

    with buzz.Env(warnings=False, allow_complex_footprint=True):
        assert fpeq(
            fps.B,
            fps.A.move(fps.B.tl),
            fps.B.move(fps.B.tl),
            fps.C.move(fps.B.tl),
            fps.A.move(fps.B.tl, fps.B.tr),
            fps.B.move(fps.B.tl, fps.B.tr),
            fps.C.move(fps.B.tl, fps.B.tr),
            fps.A.move(fps.B.tl, fps.B.tr, fps.B.br),
            fps.B.move(fps.B.tl, fps.B.tr, fps.B.br),
            fps.C.move(fps.B.tl, fps.B.tr, fps.B.br),
        )

        aff = (Affine.translation(*fps.A.bl) * Affine.rotation(45) *
               Affine.scale(2**0.5, 2**0.5 * -2))
        assert fpeq(
            buzz.Footprint(gt=aff.to_gdal(), rsize=(1, 1)),
            fps.A.move(fps.A.bl, fps.A.tr, fps.I.tr),
            fps.B.move(fps.A.bl, fps.A.tr, fps.I.tr),
            fps.C.move(fps.A.bl, fps.A.tr, fps.I.tr),
        )
        with pytest.raises(ValueError, match='angle'):
            fps.C.move(fps.A.bl, fps.A.tr, fps.I.c)
def sources_for_tile(tile, catalog, scale=1, min_zoom=None, max_zoom=None):
    """Render a tile's source footprints."""
    bounds = Bounds(mercantile.bounds(tile), WGS84_CRS)
    shape = tuple(map(int, Affine.scale(scale) * TILE_SHAPE))
    resolution = get_resolution_in_meters(bounds, shape)

    for idx, source in enumerate(
            catalog.get_sources(bounds,
                                resolution,
                                min_zoom=min_zoom,
                                max_zoom=max_zoom)):
        yield {
            "url": source.url,
            "name": source.name,
            "resolution": source.resolution,
            "band": source.band,
            "band_info": source.band_info,
            "meta": source.meta,
            "recipes": source.recipes,
            "priority": source.priority,
            "coverage": source.coverage,
            "acquired_at": source.acquired_at,
            "filename": source.filename,
            "min_zoom": source.min_zoom,
            "max_zoom": source.max_zoom,
        }
예제 #21
0
def zoom_factor(args, crs):
    # Determine the geographic "zoom factor" for the request.
    # (Larger zoom factor means deeper zoom.  Smaller zoom factor means larger area.)
    # Extract request bbox and crs
    width = int(args['width'])
    height = int(args['height'])
    minx, miny, maxx, maxy = map(float, args['bbox'].split(','))
    p1 = geometry.point(minx, maxy, crs)
    p2 = geometry.point(minx, miny, crs)
    p3 = geometry.point(maxx, maxy, crs)
    p4 = geometry.point(maxx, miny, crs)

    # Project to a geographic coordinate system
    # This is why we can't just use the regular geobox.  The scale needs to be
    # "standardised" in some sense, not dependent on the CRS of the request.
    geo_crs = geometry.CRS("EPSG:4326")
    gp1 = p1.to_crs(geo_crs)
    gp2 = p2.to_crs(geo_crs)
    gp3 = p3.to_crs(geo_crs)
    gp4 = p4.to_crs(geo_crs)

    minx = min(gp1.points[0][0], gp2.points[0][0], gp3.points[0][0], gp4.points[0][0])
    maxx = max(gp1.points[0][0], gp2.points[0][0], gp3.points[0][0], gp4.points[0][0])
    miny = min(gp1.points[0][1], gp2.points[0][1], gp3.points[0][1], gp4.points[0][1])
    maxy = max(gp1.points[0][1], gp2.points[0][1], gp3.points[0][1], gp4.points[0][1])

    # Create geobox affine transformation (N.B. Don't need an actual Geobox)
    affine = Affine.translation(minx, miny) * Affine.scale((maxx - minx) / width, (maxy - miny) / height)

    # Zoom factor is the reciprocal of the square root of the transform determinant
    # (The determinant is x scale factor multiplied by the y scale factor)
    return 1.0 / math.sqrt(affine.determinant)
예제 #22
0
def test_merge_does_not_uncover_masked_pixels():
    # See https://github.com/satellogic/telluric/issues/65
    affine = Affine.translation(0, 2) * Affine.scale(1, -1)

    rs_a = GeoRaster2(
        image=np.ma.masked_array(
            [[[100, 89], [100, 89]], [[110, 99], [110, 99]]],
            [[[False, True], [False, True]], [[False, True], [False, True]]],
            dtype=np.uint8),
        affine=affine,
        crs=WGS84_CRS,
        band_names=['red', 'green'],
    )

    rs_b = GeoRaster2(
        image=np.array([[[0, 210], [0, 210]]], dtype=np.uint8),
        affine=affine,
        crs=WGS84_CRS,
        band_names=['green'],
    )

    expected_image = np.ma.masked_array(
        [[[100, 89], [100, 89]], [[110, 99], [110, 99]]],
        [[[False, True], [False, True]], [[False, True], [False, True]]],
        dtype=np.uint8)

    result = merge_all([rs_a, rs_b],
                       rs_a.footprint()).limit_to_bands(['red', 'green'])

    assert_array_equal(np.ma.filled(result.image, 0),
                       np.ma.filled(expected_image, 0))
    assert_array_equal(result.image.mask, expected_image.mask)
예제 #23
0
def test_georaster_save_emits_warning_if_uneven_mask(recwarn):
    affine = Affine.translation(0, 2) * Affine.scale(1, -1)
    raster = GeoRaster2(
        image=np.array([
            [
                [100, 200],
                [100, 200]
            ],
            [
                [110, 0],
                [110, 0]
            ]
        ], dtype=np.uint8),
        affine=affine,
        crs=WGS84_CRS,
        nodata=0
    )

    orig_mask = raster.image.mask

    assert not (orig_mask == orig_mask[0]).all()

    with NamedTemporaryFile(suffix=".tif") as fp:
        raster.save(fp.name)

    w = recwarn.pop(GeoRaster2Warning)
    assert (
        "Saving different masks per band is not supported, the union of the masked values will be performed."
        in str(w.message)
    )
예제 #24
0
 def transform(self):
     """Returns the affine transform."""
     return (
         from_bounds(*self.bounds, self.width, self.height)
         if self.bounds
         else Affine.scale(self.width, -self.height)
     )
예제 #25
0
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)])
예제 #26
0
def affine_from_axis(xx, yy, fallback_resolution=None):
    """ Compute Affine transform from pixel to real space given X,Y coordinates.

        :param xx: X axis coordinates
        :param yy: Y axis coordinates
        :param fallback_resolution: None|float|(resx:float, resy:float) resolution to
                                    assume for single element axis.

        (0, 0) in pixel space is defined as top left corner of the top left pixel
            \
            `` 0   1
             +---+---+
           0 |   |   |
             +---+---+
           1 |   |   |
             +---+---+

        Only uses first two coordinate values, assumes that data is regularly
        sampled.

        raises ValueError when any axis is empty
        raises ValueError when any axis has single value and fallback resolution was not supplied.
    """
    if fallback_resolution is not None:
        if isinstance(fallback_resolution, (float, int)):
            frx, fry = fallback_resolution, fallback_resolution
        else:
            frx, fry = fallback_resolution
    else:
        frx, fry = None, None

    xres, xoff = data_resolution_and_offset(xx, frx)
    yres, yoff = data_resolution_and_offset(yy, fry)

    return Affine.translation(xoff, yoff) * Affine.scale(xres, yres)
예제 #27
0
    def masked_raster(cls):
        data = np.array([
            [0, 1, 1, 1],
            [0, 2, 0, 2],
            [0, 3, 3, 3],
        ],
                        dtype=np.uint8)

        mask = np.array([
            [True, False, False, False],
            [True, False, False, False],
            [True, False, False, False],
        ],
                        dtype=np.bool)

        image = np.ma.array(np.repeat(data[np.newaxis, :, :], 3, 0),
                            mask=np.repeat(mask[np.newaxis, :, :], 3, 0))

        # Don't use exactly -1.0 for the affine for rasterio < 1.0a13, see
        # https://github.com/mapbox/rasterio/issues/1272
        affine = Affine.scale(1, -1.0001) * Affine.translation(0, -3)
        crs = WGS84_CRS

        return GeoRaster2(
            image,
            affine=affine,
            crs=crs,
        )
 def test_is_rectilinear(self):
     assert Affine.identity().is_rectilinear
     assert Affine.scale(2.5, 6.1).is_rectilinear
     assert Affine.translation(4, -1).is_rectilinear
     assert Affine.rotation(90).is_rectilinear
     assert not Affine.shear(4, -1).is_rectilinear
     assert not Affine.rotation(-26).is_rectilinear
예제 #29
0
    def test_full_stack_dataset_xysel(self, d, translate, scale, shear, rotate,
                                      samp):
        dataset = create3d_dataset(dims=d)
        xlines_, ilines_ = np.meshgrid(dataset.xline, dataset.iline)
        ix_pairs = np.dstack([ilines_, xlines_])
        tr = Affine.translation(*translate)
        sc = Affine.scale(scale)
        sh = Affine.shear(*shear)
        rt = Affine.rotation(rotate)
        trsfm = lambda x: tr * sc * sh * rt * x
        ix_pairs = np.apply_along_axis(trsfm, 1, ix_pairs.reshape(
            -1, 2)).reshape(ix_pairs.shape)
        dataset['cdp_x'] = (DimensionKeyField.cdp_3d, ix_pairs[:, :, 0])
        dataset['cdp_y'] = (DimensionKeyField.cdp_3d, ix_pairs[:, :, 1])

        dataset['data'] = (DimensionKeyField.threed_twt, np.random.rand(*d))

        test_points = np.dstack([
            np.random.random(samp) * (d[0] - 0.1) + 0.1,
            np.random.random(samp) * (d[1] - 0.1) + 0.1
        ])[0]
        # make sure at least one point is in the box
        test_points[0, :] = d[0] / 2, d[1] / 2

        xys = np.apply_along_axis(trsfm, 1, test_points)

        res = dataset.seis.xysel(xys[:, 0], xys[:, 1], method='linear')
        assert isinstance(res, xr.Dataset)
        res = dataset.seis.xysel(xys[:, 0], xys[:, 1], method='nearest')
        assert isinstance(res, xr.Dataset)
 def test_is_conformal(self):
     assert Affine.identity().is_conformal
     assert Affine.scale(2.5, 6.1).is_conformal
     assert Affine.translation(4, -1).is_conformal
     assert Affine.rotation(90).is_conformal
     assert Affine.rotation(-26).is_conformal
     assert not Affine.shear(4, -1).is_conformal
예제 #31
0
def test_rasters_covering_different_overlapping_areas_on_y():
    affine_a = Affine.translation(1, 2) * Affine.scale(1, -1)
    raster_a = make_test_raster(1, [1], height=20, width=20, affine=affine_a)
    affine_b = Affine.translation(1, -9) * Affine.scale(1, -1)
    raster_b = make_test_raster(2, [1], height=20, width=20, affine=affine_b)
    roi = GeoVector.from_bounds(xmin=1,
                                ymin=-29,
                                xmax=21,
                                ymax=2,
                                crs=WEB_MERCATOR_CRS)
    rasters = [raster_a, raster_b]
    merged = merge_all(rasters, roi)
    assert (merged.affine.almost_equals(affine_a))
    assert (not merged.image.mask.all())
    assert ((merged.image.data[0, 0:20, 0:20] == 1).all())
    assert ((merged.image.data[0, 21:30, 0:20] == 2).all())
예제 #32
0
def transform_from_latlon(lat, lon):
    """ input 1D array of lat / lon and output an Affine transformation """
    lat = np.asarray(lat)
    lon = np.asarray(lon)
    trans = Affine.translation(lon[0], lat[0])
    scale = Affine.scale(lon[1] - lon[0], lat[1] - lat[0])
    return trans * scale
예제 #33
0
def odc_style_xr_dataset():
    """An xarray.Dataset with ODC style coordinates and CRS, and no time dimension.

    Contains an EPSG:4326, single variable 'B10' of 100x100 int16 pixels."""
    affine = Affine.scale(0.1, 0.1) * Affine.translation(20, 30)
    geobox = geometry.GeoBox(100, 100, affine, geometry.CRS(GEO_PROJ))
    dataset = xarray.Dataset(attrs={
        'extent': geobox.extent,
        'crs': geobox.crs
    })
    for name, coord in geobox.coordinates.items():
        dataset[name] = (name, coord.values, {
            'units': coord.units,
            'crs': geobox.crs
        })
    dataset['B10'] = (geobox.dimensions,
                      np.arange(10000, dtype='int16').reshape(geobox.shape), {
                          'nodata': 0,
                          'units': '1',
                          'crs': geobox.crs
                      })

    # To include a time dimension:
    # dataset['B10'] = (('time', 'latitude', 'longitude'), np.arange(10000, dtype='int16').reshape((1, 100, 100)),
    #  {'nodata': 0, 'units': '1', 'crs': geobox.crs})

    return dataset
예제 #34
0
def test_write_dataset_to_netcdf(tmpnetcdf_filename):
    affine = Affine.scale(0.1, 0.1) * Affine.translation(20, 30)
    geobox = geometry.GeoBox(100, 100, affine, geometry.CRS(GEO_PROJ))
    dataset = xarray.Dataset(attrs={'extent': geobox.extent, 'crs': geobox.crs})
    for name, coord in geobox.coordinates.items():
        dataset[name] = (name, coord.values, {'units': coord.units, 'crs': geobox.crs})

    dataset['B10'] = (geobox.dimensions,
                      np.arange(10000, dtype='int16').reshape(geobox.shape),
                      {'nodata': 0, 'units': '1', 'crs': geobox.crs})

    write_dataset_to_netcdf(dataset, tmpnetcdf_filename, global_attributes={'foo': 'bar'},
                            variable_params={'B10': {'attrs': {'abc': 'xyz'}}})

    with netCDF4.Dataset(tmpnetcdf_filename) as nco:
        nco.set_auto_mask(False)
        assert 'B10' in nco.variables
        var = nco.variables['B10']
        assert (var[:] == dataset['B10'].values).all()

        assert 'foo' in nco.ncattrs()
        assert nco.getncattr('foo') == 'bar'

        assert 'abc' in var.ncattrs()
        assert var.getncattr('abc') == 'xyz'
예제 #35
0
 def test_is_rectilinear(self):
     assert Affine.identity().is_rectilinear
     assert Affine.scale(2.5, 6.1).is_rectilinear
     assert Affine.translation(4, -1).is_rectilinear
     assert Affine.rotation(90).is_rectilinear
     assert not Affine.shear(4, -1).is_rectilinear
     assert not Affine.rotation(-26).is_rectilinear
예제 #36
0
def from_origin(west, north, xsize, ysize):
    """Return an Affine transformation given upper left and pixel sizes.

    Return an Affine transformation for a georeferenced raster given
    the coordinates of its upper left corner `west`, `north` and pixel
    sizes `xsize`, `ysize`.
    """
    return Affine.translation(west, north) * Affine.scale(xsize, -ysize)
예제 #37
0
def from_origin(west, north, xsize, ysize):
    """Return an Affine transformation given upper left and pixel sizes.

    Return an Affine transformation for a georeferenced raster given
    the coordinates of its upper left corner `west`, `north` and pixel
    sizes `xsize`, `ysize`.
    """
    return Affine.translation(west, north) * Affine.scale(xsize, -ysize)
def transform_from_latlon( lat, lon ):
	''' simple way to make an affine transform from lats and lons coords '''
	from affine import Affine
	lat = np.asarray( lat )
	lon = np.asarray(lon)
	trans = Affine.translation(lon[0], lat[0])
	scale = Affine.scale(lon[1] - lon[0], lat[1] - lat[0])
	return trans * scale
예제 #39
0
def odc_style_xr_dataset():
    """An xarray.Dataset with ODC style coordinates and CRS, and no time dimension.

    Contains an EPSG:4326, single variable 'B10' of 100x100 int16 pixels."""
    affine = Affine.scale(0.1, 0.1) * Affine.translation(20, 30)
    geobox = geometry.GeoBox(100, 100, affine, geometry.CRS(GEO_PROJ))

    return Datacube.create_storage({}, geobox, [Measurement(name='B10', dtype='int16', nodata=0, units='1')])
예제 #40
0
def affine_from_bounds(a, b):
    # Force arguments to float
    a = [float(i) for i in a]
    b = [float(i) for i in b]

    return ~(Affine.translation(a[0], a[1]) * Affine.scale(
        (a[2] - a[0]) / (b[2] - b[0]),
        (a[3] - a[1]) / (b[3] - b[1])) * Affine.translation(-b[0], -b[1]))
예제 #41
0
def transform_from_latlon( lat, lon ):
	''' simple way to make an affine transform from lats and lons coords '''
	from affine import Affine
	lat = np.asarray( lat )
	lon = np.asarray( lon )
	trans = Affine.translation(lon[0], lat[0])
	scale = Affine.scale(lon[1] - lon[0], lat[1] - lat[0])
	return trans * scale
예제 #42
0
def from_bounds(west, south, east, north, width, height):
    """Return an Affine transformation given bounds, width and height.

    Return an Affine transformation for a georeferenced raster given
    its bounds `west`, `south`, `east`, `north` and its `width` and
    `height` in number of pixels.
    """
    return Affine.translation(west, north) * Affine.scale(
        (east - west) / width, (south - north) / height)
예제 #43
0
    def affine(self, pixelbuffer=0):
        """
        Return an Affine object of tile.

        - pixelbuffer: tile buffer in pixels
        """
        left = self.bounds(pixelbuffer=pixelbuffer)[0]
        top = self.bounds(pixelbuffer=pixelbuffer)[3]
        return Affine.translation(left, top) * Affine.scale(
            self.pixel_x_size, -self.pixel_y_size)
예제 #44
0
    def test_itransform(self):
        pts = [(4, 1), (-1, 0), (3, 2)]
        r = Affine.scale(-2).itransform(pts)
        assert r is None, r
        assert pts == [(-8, -2), (2, 0), (-6, -4)]

        A = Affine.rotation(33)
        pts = [(4, 1), (-1, 0), (3, 2)]
        pts_expect = [A*pt for pt in pts]
        r = A.itransform(pts)
        assert r is None
        assert pts == pts_expect
예제 #45
0
 def test_is_degenerate(self):
     from affine import EPSILON
     assert not Affine.identity().is_degenerate
     assert not Affine.translation(2, -1).is_degenerate
     assert not Affine.shear(0, -22.5).is_degenerate
     assert not Affine.rotation(88.7).is_degenerate
     assert not Affine.scale(0.5).is_degenerate
     assert Affine.scale(0).is_degenerate
     assert Affine.scale(-10, 0).is_degenerate
     assert Affine.scale(0, 300).is_degenerate
     assert Affine.scale(0).is_degenerate
     assert Affine.scale(0).is_degenerate
     assert Affine.scale(EPSILON).is_degenerate
예제 #46
0
    def from_geopolygon(cls, geopolygon, resolution, crs=None, align=True):
        """
        :type geopolygon: datacube.model.GeoPolygon
        :param resolution: (x_resolution, y_resolution)
        :param crs: CRS to use, if different from the geopolygon
        :param align: Should the geobox be aligned to pixels of the given resolution. This assumes an origin of (0,0).
        :type align: boolean
        :rtype: GeoBox
        """
        # TODO: currently only flipped Y-axis data is supported
        assert resolution[1] > 0
        assert resolution[0] < 0

        if crs is None:
            crs = geopolygon.crs
        else:
            geopolygon = geopolygon.to_crs(crs)
        
        bounding_box = geopolygon.boundingbox
#        print(bounding_box)
#        print("~~~")
        left, top = float(bounding_box.left), float(bounding_box.top)

        if align:
            left = math.floor(left / resolution[1]) * resolution[1]
            top = math.floor(top / resolution[0]) * resolution[0]
#            print(left)
            #print(top)
        #print(Affine.translation(left, top))
        #print(Affine.scale(resolution[1], resolution[0]))
        affine = (Affine.translation(left, top) * Affine.scale(resolution[1], resolution[0]))
#        print(affine)
        right, bottom = float(bounding_box.right), float(bounding_box.bottom)
        width, height = ~affine * (right, bottom)
        
#        print(right)
        
#        print(width)
        #width = 198
        #height = 288
        #print(height)
        if align:
            width = math.ceil(width)
            height = math.ceil(height)
        return GeoBox(crs=crs,
                      affine=affine,
                      width=int(width),
                      height=int(height))
예제 #47
0
	def transform_from_latlon( lat, lon ):
		''' simple way to make an affine transform from lats and lons coords '''
		from affine import Affine
		lat = np.asarray( lat )
		lon = np.asarray( lon )
		if (np.max( lat ) - 90) < np.abs( np.mean( np.diff( lat ) ) ):
			lat_max = 90.0
		else:
			lat_max = np.max( lat )

		# set the lonmax to the corner. --> this can get you into trouble with non-global data
		# but I am unsure how to make it more dynamic at the moment. [ML]
		lon_arr = np.array([-180.0, 0.0 ])
		idx = (np.abs(lon_arr - np.min( lon ) ) ).argmin()
		lon_max = lon_arr[ idx ]

		trans = Affine.translation(lon_max, lat_max)
		scale = Affine.scale(lon[1] - lon[0], lat[1] - lat[0])
		return trans * scale
예제 #48
0
def test_write_dataset_to_netcdf(tmpnetcdf_filename):
    affine = Affine.scale(0.1, 0.1)*Affine.translation(20, 30)
    geobox = GeoBox(100, 100, affine, CRS(GEO_PROJ))
    dataset = xarray.Dataset(attrs={'extent': geobox.extent, 'crs': geobox.crs})
    for name, coord in geobox.coordinates.items():
        dataset[name] = (name, coord.labels, {'units': coord.units})

    dataset['B10'] = (geobox.dimensions, numpy.arange(10000).reshape(geobox.shape), {'nodata': 0, 'units': '1'})

    write_dataset_to_netcdf(dataset, {'foo': 'bar'}, {'B10': {'attrs': {'abc': 'xyz'}}}, Path(tmpnetcdf_filename))

    with netCDF4.Dataset(tmpnetcdf_filename) as nco:
        nco.set_auto_mask(False)
        assert 'B10' in nco.variables
        var = nco.variables['B10']
        assert (var[:] == dataset['B10'].values).all()

        assert 'foo' in nco.ncattrs()
        assert nco.getncattr('foo') == 'bar'

        assert 'abc' in var.ncattrs()
        assert var.getncattr('abc') == 'xyz'
예제 #49
0
def align_image(affine, infile, outfile=None):
    """
    Create a GDAL VRT referencing the original
    dataset with an aligned georeference.

    If no `outfile` argument is specified, the
    dataset will be created in the same place
    with `.aligned.vrt` appended as an extension.
    """

    trans = get_transform(infile)

    px_size = N.array([trans.a,trans.e])
    s = Affine.scale(*px_size)
    px_trans = ~s*affine
    if outfile is None:
        outfile = splitext(infile)[0] + ".aligned.vrt"

    run("gdal_translate", "-of VRT", infile, outfile)
    if affine != Affine.identity():
        outtrans = trans*px_trans*s
        set_transform(outfile, outtrans)
    return outfile
예제 #50
0
def test_average_slope():
    _lines = [
        geometry.LineString(coordinates=[(0, 5), (10, 5)]),
        geometry.LineString(coordinates=[(5, 0), (5, 10)]),
        geometry.LineString(coordinates=[(0, 0), (10, 10)]),
        geometry.LineString(coordinates=[(0, 0), (0, 10), (10, 10)]),
        geometry.LineString(coordinates=[(0, 0), (5, 5), (5, 0), (0, 0)]),
    ]

    lines = geopandas.GeoDataFrame(geometry=_lines)

    expected = pandas.Series([
        1.000000,
        0.000000,
        0.707107,
        0.500000,
        0.000000,
    ]) * 100

    hill = numpy.mgrid[:11, :11][1]
    trans = Affine.translation(0, 10) * Affine.rotation(0) * Affine.scale(1, -1)
    result = algo.average_slope(lines, hill, trans)

    pdtest.assert_series_equal(result, expected)
예제 #51
0
def test_window_bounds_north_up():
    transform = Affine.translation(0.0, 10.0) * Affine.scale(1.0, -1.0) * Affine.identity()
    assert_window_almost_equals(
        from_bounds(0, 0, 10, 10, transform, 10, 10),
        Window(0, 0, 10, 10))
예제 #52
0
def main(args):
    """Parse arguments and run graticule creation."""
    parser = argparse.ArgumentParser()
    parser.add_argument("output", type=str, help="output vector data")
    parser.add_argument("stepsize", type=int, help="degree step size")
    parser.add_argument(
        "--size_x", type=int, help="model raster x size", default=8192)
    parser.add_argument(
        "--size_y", type=int, help="model raster y size", default=4096)
    parser.add_argument(
        "--driver", type=str, help="output driver", default="ESRI Shapefile")
    parsed = parser.parse_args(args)

    output_file = parsed.output
    stepsize = parsed.stepsize
    size_x = parsed.size_x
    size_y = parsed.size_y

    fieldname = "dd"
    elevation = 0
    bounds = (-180., -90., 180., 90.)
    left, bottom, right, top = bounds
    pixel_x_size = (right - left) / float(size_x)
    pixel_y_size = (top - bottom) / float(size_y)
    affine = Affine.translation(left, top) * Affine.scale(
        pixel_x_size, -pixel_y_size)

    if os.path.isfile(output_file):
        os.remove(output_file)

    lons, lats = np.meshgrid(
        np.linspace(left, right, size_x, endpoint=True),
        np.linspace(top, bottom, size_y, endpoint=True)
    )

    # Geodetic coordinates with elevation above the WGS84 ellipsoid.
    coord_gdt = np.empty((size_y, size_x, 3))
    coord_gdt[:, :, 0] = lats
    coord_gdt[:, :, 1] = lons
    coord_gdt[:, :, 2] = elevation
    decimal_year = np.empty((size_y, size_x))
    decimal_year.fill(2016.1)
    coord_gct = convert(coord_gdt, GEODETIC_ABOVE_WGS84, GEOCENTRIC_SPHERICAL)
    qd_lat, qd_lon = eval_qdlatlon(
        coord_gct[..., 0].ravel(), coord_gct[..., 1].ravel(),
        coord_gct[..., 2].ravel(), decimal_year.ravel())

    # Latitudes
    lat = np.reshape(qd_lat, (size_y, size_x))
    lat_lines = extract_contours(lat, bounds, stepsize, fieldname, 0)

    # Longitudes
    lon = np.reshape(qd_lon, (size_y, size_x))
    lon_lines = extract_contours(
        np.absolute(lon), bounds, stepsize, fieldname, 0)
    meridians = extract_contours(lon, bounds, stepsize, fieldname, 0)
    # for row in range(len(lon)):
    #     diff = lon[row][:-1]-lon[row][1:]
    #     step_idxes = np.argwhere(diff > 180.)
    #     if step_idxes:
    #         lon[row][np.argwhere(diff > 180.)[0]+1:] += 360.
    # lon_lines = extract_contours(lon, bounds, stepsize, fieldname)

    out_schema = dict(
        geometry="LineString",
        properties=dict(
            degrees="int", direction="str", display="str", dd="float",
            scalerank="int"))
    with fiona.open(
        output_file, "w", schema=out_schema, crs={'init': 'epsg:4326'},
        driver=parsed.driver
    ) as dst:
        for feature in lat_lines:
            latitude = feature["properties"]["dd"]
            lat_int = int(round(latitude))
            direction = "N" if lat_int > 0 else "S"
            display_lat = lat_int if lat_int > 0 else -lat_int
            display = "%s %s" % (display_lat, direction)
            if lat_int == 0:
                direction = None
                display = "0"
            feature["properties"].update(
                degrees=lat_int, direction=direction, display=display,
                scalerank=None)
            dst.write(feature)
        for feature in _extract_longitudes(lon_lines, lon, affine):
            dst.write(feature)
            longitude = feature["properties"]["dd"]
            lon_int = int(round(longitude))
            direction = "W" if lon_int > 0 else "E"
            display_lon = lon_int if lon_int > 0 else -lon_int
            display = "%s %s" % (display_lon, direction)
            if lon_int == 0:
                direction = None
                display = "0"
            feature["properties"].update(
                degrees=lon_int, direction=direction, display=display,
                scalerank=None)
            # if longitude > 180.:
            #     feature["properties"].update(dd=longitude-360.)
            # dst.write(feature)

        for feature in meridians:
            longitude = feature["properties"]["dd"]
            if longitude in [0, 180]:
                feature["properties"].update(
                    degrees=0, direction=None, display="0", scalerank=None)
                dst.write(feature)
예제 #53
0
 def test_cant_invert_degenerate(self):
     t = Affine.scale(0)
     with pytest.raises(affine.TransformNotInvertibleError):
         ~t
예제 #54
0
def test_write_plus_model_jpeg():
    with MemoryFile() as memfile:
        with memfile.open(driver='JPEG', dtype='uint8', count=3, height=32, width=32, crs='epsg:3226', transform=Affine.identity() * Affine.scale(0.5, -0.5)) as dst:
            dst.write(numpy.full((32, 32), 255, dtype='uint8'), 1)
            dst.write(numpy.full((32, 32), 204, dtype='uint8'), 2)
            dst.write(numpy.full((32, 32), 153, dtype='uint8'), 3)
            data = dst.read()
            assert (data[0] == 255).all()
            assert (data[1] == 204).all()
            assert (data[2] == 153).all()
예제 #55
0
def base_affine(rotation):
    return Affine.translation(5, 15) * Affine.rotation(rotation) * Affine.scale(3, -3)
예제 #56
0
def test_rotation_improper():
    with pytest.raises(affine.UndefinedRotationError):
        Affine.scale(-1, 1).rotation_angle
예제 #57
0
 def test_mul_transform(self):
     t = Affine.rotation(5) * Affine.rotation(29)
     assert isinstance(t, Affine)
     seq_almost_equal(t, Affine.rotation(34))
     t = Affine.scale(3, 5) * Affine.scale(2)
     seq_almost_equal(t, Affine.scale(6, 10))
예제 #58
0
 def test_cant_invert_degenerate(self):
     from affine import TransformNotInvertibleError
     t = Affine.scale(0)
     self.assertRaises(TransformNotInvertibleError, lambda: ~t)
예제 #59
0
 def test_itransform(self):
     pts = [(4, 1), (-1, 0), (3, 2)]
     r = Affine.scale(-2).itransform(pts)
     assert r is None, r
     assert_equal(pts, [(-8, -2), (2, 0), (-6, -4)])