From eb910a4c86964b9354643a699c9231ea894b4924 Mon Sep 17 00:00:00 2001 From: Matthew Perry Date: Wed, 16 Mar 2016 14:19:51 -0400 Subject: [PATCH 01/11] integrate gdal calcs and res handling --- rasterio/warp.py | 61 +++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/rasterio/warp.py b/rasterio/warp.py index 0c0f3527..6f3df7b0 100644 --- a/rasterio/warp.py +++ b/rasterio/warp.py @@ -1,6 +1,7 @@ """Raster warping and reprojection""" from __future__ import absolute_import +from __future__ import division from math import ceil import warnings @@ -8,8 +9,10 @@ import warnings from affine import Affine import numpy as np +import rasterio from rasterio._base import _transform -from rasterio._warp import _transform_geom, _reproject, Resampling +from rasterio._warp import (_transform_geom, _reproject, Resampling, + _calculate_default_transform) from rasterio.transform import guard_transform @@ -250,8 +253,7 @@ def calculate_default_transform( bottom, right, top, - resolution=None, - densify_pts=21): + resolution=None): """ Transforms bounds to destination coordinate system, calculates resolution if not provided, and returns destination transform and dimensions. @@ -259,13 +261,8 @@ def calculate_default_transform( Destination transform is anchored from the left, top coordinate. - Destination width and height are calculated from the number of pixels on - each dimension required to fit the destination bounds. - - If resolution is not provided, it is calculated using a weighted average - of the relative sizes of source width and height compared to the transformed - bounds (pixels are assumed to be square). - + Destination width and height (and resolution if not provided), are + calculated using GDAL's method for suggest warp output. Parameters ---------- @@ -280,39 +277,35 @@ def calculate_default_transform( Source raster height. left, bottom, right, top: float Bounding coordinates in src_crs, from the bounds property of a raster. - resolution: tuple (x resolution, y resolution) or float, optional + resolution: tuple (x resolution, y resolution), optional Target resolution, in units of target coordinate reference system. - densify_pts: uint, optional - Number of points to add to each edge to account for nonlinear - edges produced by the transform process. Large numbers will produce - worse performance. Default: 21 (gdal default). Returns ------- tuple of destination affine transform, width, and height """ + with rasterio.drivers(): + dst_affine, dst_width, dst_height = _calculate_default_transform( + src_crs, dst_crs, + width, height, + left, bottom, right, top) - xmin, ymin, xmax, ymax = transform_bounds( - src_crs, dst_crs, left, bottom, right, top, densify_pts) + # If resolution is specified, Keep upper-left anchored + # adjust the transform resolutions + # adjust the width/height by the ratio of estimated:specified res (ceil'd) + if resolution: + # Assume yres is provided as positive, + # needs to be negative for north-up affine + xres = resolution[0] + yres = -resolution[1] - x_dif = xmax - xmin - y_dif = ymax - ymin - size = float(width + height) + xratio = dst_affine.a / xres + yratio = dst_affine.e / yres - if resolution is None: - # TODO: compare to gdalwarp default (see - # _calculate_default_transform() in _warp.pyx. - avg_resolution = ( - (x_dif / float(width)) * (float(width) / size) + - (y_dif / float(height)) * (float(height) / size) - ) - resolution = (avg_resolution, avg_resolution) + dst_affine = Affine(xres, dst_affine.b, dst_affine.c, + dst_affine.d, yres, dst_affine.f) - elif not isinstance(resolution, (tuple, list)): - resolution = (resolution, resolution) - - dst_affine = Affine(resolution[0], 0, xmin, 0, -resolution[1], ymax) - dst_width = max(int(ceil(x_dif / resolution[0])), 1) - dst_height = max(int(ceil(y_dif / resolution[1])), 1) + dst_width = ceil(dst_width * xratio) + dst_height = ceil(dst_height * yratio) return dst_affine, dst_width, dst_height From 2289a228620e194f5c74d935fc9ff87b5534a117 Mon Sep 17 00:00:00 2001 From: Matthew Perry Date: Wed, 16 Mar 2016 15:19:41 -0400 Subject: [PATCH 02/11] float or tuple res --- rasterio/warp.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rasterio/warp.py b/rasterio/warp.py index 6f3df7b0..4768ddab 100644 --- a/rasterio/warp.py +++ b/rasterio/warp.py @@ -244,6 +244,14 @@ def reproject( **kwargs) +def res_tuple(res): + try: + resolution = (float(res), float(res)) + except TypeError: + resolution = (res[0], res[0]) if len(res) == 1 else res[0:2] + return resolution + + def calculate_default_transform( src_crs, dst_crs, @@ -277,7 +285,7 @@ def calculate_default_transform( Source raster height. left, bottom, right, top: float Bounding coordinates in src_crs, from the bounds property of a raster. - resolution: tuple (x resolution, y resolution), optional + resolution: tuple (x resolution, y resolution) or float, optional Target resolution, in units of target coordinate reference system. Returns @@ -294,6 +302,7 @@ def calculate_default_transform( # adjust the transform resolutions # adjust the width/height by the ratio of estimated:specified res (ceil'd) if resolution: + resolution = res_tuple(resolution) # Assume yres is provided as positive, # needs to be negative for north-up affine xres = resolution[0] From d037a151574f5be7824b52400c7031b81ee14b73 Mon Sep 17 00:00:00 2001 From: Matthew Perry Date: Wed, 16 Mar 2016 15:20:13 -0400 Subject: [PATCH 03/11] update tests to new gdal-calculated resolutions --- tests/test_rio_warp.py | 9 +++++---- tests/test_warp.py | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/test_rio_warp.py b/tests/test_rio_warp.py index 62ced43b..24bbb643 100644 --- a/tests/test_rio_warp.py +++ b/tests/test_rio_warp.py @@ -114,11 +114,12 @@ def test_warp_reproject_dst_crs(runner, tmpdir): with rasterio.open(outputname) as output: assert output.count == src.count assert output.crs == {'init': 'epsg:4326'} - assert output.width == 824 - assert output.height == 686 + assert output.width == 835 + assert output.height == 696 assert numpy.allclose(output.bounds, - [-78.95864996545055, 23.564424693996177, - -76.57259451863895, 25.550873767433984]) + [-78.95864996545055, 23.564787976164418, + -76.5759177302349, 25.550873767433984]) + def test_warp_reproject_dst_crs_error(runner, tmpdir): srcname = 'tests/data/RGB.byte.tif' diff --git a/tests/test_warp.py b/tests/test_warp.py index f6fbfaec..3c1a4b80 100644 --- a/tests/test_warp.py +++ b/tests/test_warp.py @@ -131,9 +131,9 @@ def test_transform_bounds_densify_out_of_bounds(): def test_calculate_default_transform(): target_transform = Affine( - 0.0028956983577810586, 0.0, -78.95864996545055, - 0.0, -0.0028956983577810586, 25.550873767433984 - ) + 0.0028535715391804096, 0.0, -78.95864996545055, + 0.0, -0.0028535715391804096, 25.550873767433984) + with rasterio.drivers(): with rasterio.open('tests/data/RGB.byte.tif') as src: wgs84_crs = {'init': 'EPSG:4326'} @@ -141,8 +141,8 @@ def test_calculate_default_transform(): src.crs, wgs84_crs, src.width, src.height, *src.bounds) assert dst_transform.almost_equals(target_transform) - assert width == 824 - assert height == 686 + assert width == 835 + assert height == 696 def test_calculate_default_transform_single_resolution(): @@ -270,9 +270,9 @@ def test_reproject_nodata(): dst_nodata=nodata ) - assert (out == 1).sum() == 4461 + assert (out == 1).sum() == 6215 assert (out == nodata).sum() == (params.dst_width * - params.dst_height - 4461) + params.dst_height - 6215) def test_reproject_nodata_nan(): @@ -296,9 +296,9 @@ def test_reproject_nodata_nan(): dst_nodata=numpy.nan ) - assert (out == 1).sum() == 4461 + assert (out == 1).sum() == 6215 assert numpy.isnan(out).sum() == (params.dst_width * - params.dst_height - 4461) + params.dst_height - 6215) @@ -325,9 +325,9 @@ def test_reproject_dst_nodata_default(): dst_crs=params.dst_crs ) - assert (out == 1).sum() == 4461 + assert (out == 1).sum() == 6215 assert (out == 0).sum() == (params.dst_width * - params.dst_height - 4461) + params.dst_height - 6215) def test_reproject_invalid_dst_nodata(): From 46de77f3cd630cbeaa8640b6bf7fbd5fb8e46353 Mon Sep 17 00:00:00 2001 From: Matthew Perry Date: Wed, 16 Mar 2016 15:38:29 -0400 Subject: [PATCH 04/11] test for right-edge data loss --- tests/data/world.byte.tif | Bin 0 -> 54885 bytes tests/test_rio_warp.py | 15 +++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 tests/data/world.byte.tif diff --git a/tests/data/world.byte.tif b/tests/data/world.byte.tif new file mode 100644 index 0000000000000000000000000000000000000000..17f420bd4d5982f76a398a806de6e57571d9f28a GIT binary patch literal 54885 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 literal 0 HcmV?d00001 diff --git a/tests/test_rio_warp.py b/tests/test_rio_warp.py index 24bbb643..8aa779bb 100644 --- a/tests/test_rio_warp.py +++ b/tests/test_rio_warp.py @@ -302,3 +302,18 @@ def test_warp_reproject_like(runner, tmpdir): assert numpy.allclose([0.001, 0.001], [output.affine.a, -output.affine.e]) assert output.width == 10 assert output.height == 10 + + +def test_warp_reproject_nolostdata(runner, tmpdir): + srcname = 'tests/data/world.byte.tif' + outputname = str(tmpdir.join('test.tif')) + result = runner.invoke(warp.warp, [srcname, outputname, + '--dst-crs', 'EPSG:3857']) + assert result.exit_code == 0 + assert os.path.exists(outputname) + + with rasterio.open(outputname) as output: + arr = output.read() + # 50 column swath on the right edge should have some ones (gdalwarped has 7223) + assert arr[0, :, -50:].sum() > 7000 + assert output.crs == {'init': 'epsg:3857'} From c4e9a266a4dd939597fc6546aebaa5752e233932 Mon Sep 17 00:00:00 2001 From: Matthew Perry Date: Thu, 17 Mar 2016 13:04:42 -0400 Subject: [PATCH 05/11] inline res arg handling to avoid polluting namespace --- rasterio/warp.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/rasterio/warp.py b/rasterio/warp.py index 4768ddab..7064a594 100644 --- a/rasterio/warp.py +++ b/rasterio/warp.py @@ -244,14 +244,6 @@ def reproject( **kwargs) -def res_tuple(res): - try: - resolution = (float(res), float(res)) - except TypeError: - resolution = (res[0], res[0]) if len(res) == 1 else res[0:2] - return resolution - - def calculate_default_transform( src_crs, dst_crs, @@ -302,11 +294,18 @@ def calculate_default_transform( # adjust the transform resolutions # adjust the width/height by the ratio of estimated:specified res (ceil'd) if resolution: - resolution = res_tuple(resolution) + + # resolutions argument into tuple + try: + res = (float(resolution), float(resolution)) + except TypeError: + res = (resolution[0], resolution[0]) \ + if len(resolution) == 1 else resolution[0:2] + # Assume yres is provided as positive, # needs to be negative for north-up affine - xres = resolution[0] - yres = -resolution[1] + xres = res[0] + yres = -res[1] xratio = dst_affine.a / xres yratio = dst_affine.e / yres From fe98d28c0b0b8604fed4f3f1e05face51c3cb553 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 21 Mar 2016 19:07:14 +0200 Subject: [PATCH 06/11] fix command --- docs/cli.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli.rst b/docs/cli.rst index 66d5ca30..a1366edc 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -317,7 +317,7 @@ option. .. code-block:: console - $ rio info tests/data/RGB.byte.tif --indent 2 + $ rio info tests/data/RGB.byte.tif --indent 2 --verbose { "count": 3, "crs": "EPSG:32618", From 10b27168eab5134f408a12370e514f97d1704c74 Mon Sep 17 00:00:00 2001 From: Matthew Perry Date: Tue, 22 Mar 2016 08:13:28 -0400 Subject: [PATCH 07/11] check invert proj in rasterio env --- rasterio/rio/warp.py | 9 ++++++--- rasterio/warp.py | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/rasterio/rio/warp.py b/rasterio/rio/warp.py index 09f01734..338ba910 100644 --- a/rasterio/rio/warp.py +++ b/rasterio/rio/warp.py @@ -70,12 +70,14 @@ def x_dst_bounds_handler(ctx, param, value): show_default=True) @click.option('--threads', type=int, default=2, help='Number of processing threads.') +@click.option('--check-invert-proj', type=bool, default=True, + help='Constrain output extent to valid coordinate region in dst-crs') @options.force_overwrite_opt @options.creation_options @click.pass_context def warp(ctx, files, output, driver, like, dst_crs, dimensions, src_bounds, - x_dst_bounds, bounds, res, resampling, threads, force_overwrite, - creation_options): + x_dst_bounds, bounds, res, resampling, threads, check_invert_proj, + force_overwrite, creation_options): """ Warp a raster dataset. @@ -132,7 +134,8 @@ def warp(ctx, files, output, driver, like, dst_crs, dimensions, src_bounds, # Expand one value to two if needed res = (res[0], res[0]) if len(res) == 1 else res - with rasterio.drivers(CPL_DEBUG=verbosity > 2): + with rasterio.drivers(CPL_DEBUG=verbosity > 2, + CHECK_WITH_INVERT_PROJ=check_invert_proj): with rasterio.open(files[0]) as src: l, b, r, t = src.bounds out_kwargs = src.meta.copy() diff --git a/rasterio/warp.py b/rasterio/warp.py index 7064a594..55f1d8a5 100644 --- a/rasterio/warp.py +++ b/rasterio/warp.py @@ -283,12 +283,21 @@ def calculate_default_transform( Returns ------- tuple of destination affine transform, width, and height + + Note + ---- + Must be called within a raster.drivers() context + + Some behavior determined by the + CHECK_WITH_INVERT_PROJ environment variable + YES: constrain output raster to extents that can be inverted + avoids visual artifacts and coordinate discontinuties. + NO: reproject coordinates beyond valid bound limits """ - with rasterio.drivers(): - dst_affine, dst_width, dst_height = _calculate_default_transform( - src_crs, dst_crs, - width, height, - left, bottom, right, top) + dst_affine, dst_width, dst_height = _calculate_default_transform( + src_crs, dst_crs, + width, height, + left, bottom, right, top) # If resolution is specified, Keep upper-left anchored # adjust the transform resolutions From 6a8671021a30e8e732fd59c6fc86398696158512 Mon Sep 17 00:00:00 2001 From: Matthew Perry Date: Tue, 22 Mar 2016 17:27:41 -0400 Subject: [PATCH 08/11] temporarily set default threads to 1 to avoid threading env errors --- rasterio/rio/warp.py | 4 ++-- rasterio/warp.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rasterio/rio/warp.py b/rasterio/rio/warp.py index 338ba910..b65f8e87 100644 --- a/rasterio/rio/warp.py +++ b/rasterio/rio/warp.py @@ -68,10 +68,10 @@ def x_dst_bounds_handler(ctx, param, value): @click.option('--resampling', type=click.Choice([r.name for r in Resampling]), default='nearest', help="Resampling method.", show_default=True) -@click.option('--threads', type=int, default=2, +@click.option('--threads', type=int, default=1, help='Number of processing threads.') @click.option('--check-invert-proj', type=bool, default=True, - help='Constrain output extent to valid coordinate region in dst-crs') + help='Constrain output to valid coordinate region in dst-crs') @options.force_overwrite_opt @options.creation_options @click.pass_context diff --git a/rasterio/warp.py b/rasterio/warp.py index 55f1d8a5..ed9bdc77 100644 --- a/rasterio/warp.py +++ b/rasterio/warp.py @@ -288,7 +288,7 @@ def calculate_default_transform( ---- Must be called within a raster.drivers() context - Some behavior determined by the + Some behavior of this function is determined by the CHECK_WITH_INVERT_PROJ environment variable YES: constrain output raster to extents that can be inverted avoids visual artifacts and coordinate discontinuties. From 9fbc22b754f2462ab6374ce24445a0028cdad940 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Tue, 22 Mar 2016 15:41:53 -0600 Subject: [PATCH 09/11] Add tests to shake up warp transformer creation Also rename an error class Closes #595 --- rasterio/_io.pyx | 4 ++-- rasterio/_warp.pyx | 6 +++--- rasterio/errors.py | 2 +- tests/test_warp_transform.py | 27 ++++++++++++++++++++++++++- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/rasterio/_io.pyx b/rasterio/_io.pyx index d4ada0fb..1b5b2e7d 100644 --- a/rasterio/_io.pyx +++ b/rasterio/_io.pyx @@ -20,7 +20,7 @@ from rasterio._drivers import driver_count, GDALEnv from rasterio._err import cpl_errs, GDALError from rasterio import dtypes from rasterio.coords import BoundingBox -from rasterio.errors import RasterioDriverRegistrationError +from rasterio.errors import DriverRegistrationError from rasterio.five import text_type, string_types from rasterio.transform import Affine from rasterio.enums import ColorInterp, MaskFlags, Resampling @@ -1851,7 +1851,7 @@ cdef class InMemoryRaster: cdef void *memdriver = _gdal.GDALGetDriverByName("MEM") if memdriver == NULL: - raise RasterioDriverRegistrationError( + raise DriverRegistrationError( "MEM driver is not registered.") self.dataset = _gdal.GDALCreate( diff --git a/rasterio/_warp.pyx b/rasterio/_warp.pyx index 8965dbd3..e2ad9402 100644 --- a/rasterio/_warp.pyx +++ b/rasterio/_warp.pyx @@ -10,7 +10,7 @@ from rasterio cimport _base, _gdal, _ogr, _io, _features from rasterio import dtypes from rasterio._err import cpl_errs, GDALError from rasterio._io cimport InMemoryRaster -from rasterio.errors import RasterioDriverRegistrationError +from rasterio.errors import DriverRegistrationError from rasterio.transform import Affine, from_bounds @@ -269,7 +269,7 @@ def _reproject( hrdriver = _gdal.GDALGetDriverByName("MEM") if hrdriver == NULL: - raise RasterioDriverRegistrationError( + raise DriverRegistrationError( "'MEM' driver not found. Check that this call is contained " "in a `with rasterio.drivers()` or `with rasterio.open()` " "block.") @@ -317,7 +317,7 @@ def _reproject( hrdriver = _gdal.GDALGetDriverByName("MEM") if hrdriver == NULL: - raise RasterioDriverRegistrationError( + raise DriverRegistrationError( "'MEM' driver not found. Check that this call is contained " "in a `with rasterio.drivers()` or `with rasterio.open()` " "block.") diff --git a/rasterio/errors.py b/rasterio/errors.py index 4cfbddc3..3a4f34e7 100644 --- a/rasterio/errors.py +++ b/rasterio/errors.py @@ -7,7 +7,7 @@ class RasterioIOError(IOError): """A failure to open a dataset using the presently registered drivers.""" -class RasterioDriverRegistrationError(ValueError): +class DriverRegistrationError(ValueError): """To be raised when, eg, _gdal.GDALGetDriverByName("MEM") returns NULL.""" diff --git a/tests/test_warp_transform.py b/tests/test_warp_transform.py index c1c3396f..8019df64 100644 --- a/tests/test_warp_transform.py +++ b/tests/test_warp_transform.py @@ -3,7 +3,7 @@ from rasterio._warp import _calculate_default_transform from rasterio.transform import Affine, from_bounds -def test_indentity(): +def test_identity(): """Get the same transform and dimensions back for same crs.""" # Tile: [53, 96, 8] # [-11740727.544603072, 4852834.0517692715, -11584184.510675032, 5009377.085697309] @@ -36,3 +36,28 @@ def test_gdal_transform_notnull(): right=-80, top=70) assert True + + +def test_gdal_transform_fail_dst_crs(): + with rasterio.drivers(): + dt, dw, dh = _calculate_default_transform( + {'init': 'EPSG:4326'}, + '+proj=foobar', + width=80, + height=80, + left=-120, + bottom=30, + right=-80, + top=70) + +def test_gdal_transform_fail_src_crs(): + with rasterio.drivers(): + dt, dw, dh = _calculate_default_transform( + '+proj=foobar', + {'init': 'EPSG:32610'}, + width=80, + height=80, + left=-120, + bottom=30, + right=-80, + top=70) From 9bebd39e1fc2d72195de9a6dbe46366486cdcd68 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Tue, 22 Mar 2016 16:48:19 -0600 Subject: [PATCH 10/11] Update change log and version --- CHANGES.txt | 35 +++++++++++++++++++++++++++++++++++ rasterio/__init__.py | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 66f00187..74411eef 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,41 @@ Changes ======= +0.32.0 (2016-03-22) +------------------- +- Bug fix: geometry factories and warp operations are properly deallocated + in normal and error situations (#494, #568). +- Bug fix: a code block in rio-merge's help has been better formatted (#535). +- Bug fix: the rasterio.vfs module is imported in __init__.py to assist + cx_Freeze (#536). +- Bug fix: old usage of `read_band()` has been replaced by `read()` throughout + the docs (#537). +- Bug fix: accidental overwriting of existing files is now prevented by the + `resolve_inout()` function in `rasterio.rio.helpers`. Commands that take + one or more input files plus an output file should use this helper and force + overwrite either by using a `--force-overwrite` option or by using the + `-o output` option, which implicitly forces overwriting (#539, #540). +- Bug fix: missing support for NaN nodata value in rio-warp added (#542, #544). +- Bug fix: missing documentation of `rasterize()`'s `fill` parameter added + (#543). +- Bug fix: raster dataset bounds are densified before transforming so that + the projected output of rio-bounds is correct (#556, #557). +- Bug fix: add 'line' to the `Interleaving` enum (#560). +- Bug fix: convert `matplotlib` import errors to a `RuntimeWarning` (#562). +- Bug fix: deallocate CPL strings in error cases (#573). +- Bug fix: non-invertable affine transforms are prevented using + `__future__.division` *#580). +- Bug fix: rio-warp clips output regions to the limits of the destination + CRS unless disabled with `--no-check-invert-proj` (#597). +- New feature: the functionality previously available only in rio-mask is now + available as `rasterio.tools.mask.mask()` (#552). +- New feature: raster bounds are used to label axes in `rasterio.tool.show()` + (#553). +- New feature: GDAL's suggested warp bounds algorithm is wrapped and exposed + for use in `warp()` and rio-warp (#574). +- Breaking change: align rio-warp's `--bounds` option with rio-merge's: these + are in destination CRS units (#541, #545). + 0.31.0 (2015-12-18) ------------------- - Warn when rasters have no georeferencing and when the default identity diff --git a/rasterio/__init__.py b/rasterio/__init__.py index 5b3fb890..1ae488f5 100644 --- a/rasterio/__init__.py +++ b/rasterio/__init__.py @@ -23,7 +23,7 @@ from rasterio import _err, coords, enums, vfs __all__ = [ 'band', 'open', 'drivers', 'copy', 'pad'] -__version__ = "0.31.0" +__version__ = "0.32.0" log = logging.getLogger('rasterio') class NullHandler(logging.Handler): From 9085c301f06676f76f89e31bd7f9ca11cf014b7c Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Tue, 22 Mar 2016 16:54:56 -0600 Subject: [PATCH 11/11] Update authors --- AUTHORS.txt | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/AUTHORS.txt b/AUTHORS.txt index 50508787..3e35b11f 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -1,25 +1,34 @@ Authors ======= -Sean Gillies -Brendan Ward +Aldo Culquicondor +Alessandro Amici +Alexander Amit Kapadia +AsgerPetersen +Bas Couwenberg +Brendan Ward +Etienne B. Racine +Even Rouault +Jacques Tardie +James McBride +James Seppi +Jeffrey Gerard +Johan Van de Wauw +Joshua Arnott Kelsey Jordahl Kevin Wurster -Maxim Dubinin -Ryan Grout -Mike Toews -AsgerPetersen -Joshua Arnott -Alessandro Amici -Johan Van de Wauw -James Seppi -Jacques Tardie -Etienne B. Racine -Christoph Gohlke Martijn Visser -Aldo Culquicondor -Robin Wilson +Matt Savoie +Matthew Perry +Maxim Dubinin +Mike Toews +Nat Wilson Patrick Young +Robin Wilson +Ryan Grout +Sean Gillies +Trevor R.H. Clarke +cgohlke See also https://github.com/mapbox/rasterio/graphs/contributors.