From b676671056564cf76ef175a0d83ba0163f1368dc Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Tue, 20 Oct 2015 22:39:36 -0600 Subject: [PATCH 01/10] Silence tar and make --- scripts/travis_gdal_install.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/travis_gdal_install.sh b/scripts/travis_gdal_install.sh index e9454922..022dfd8f 100644 --- a/scripts/travis_gdal_install.sh +++ b/scripts/travis_gdal_install.sh @@ -60,30 +60,30 @@ ls -l $GDALINST if [ ! -d $GDALINST/gdal-1.9.2 ]; then cd $GDALBUILD wget http://download.osgeo.org/gdal/gdal-1.9.2.tar.gz - tar -xzvf gdal-1.9.2.tar.gz + tar -xzf gdal-1.9.2.tar.gz cd gdal-1.9.2 ./configure --prefix=$GDALINST/gdal-1.9.2 $GDALOPTS - make -j 2 + make -s -j 2 make install fi if [ ! -d $GDALINST/gdal-1.11.2 ]; then cd $GDALBUILD wget http://download.osgeo.org/gdal/1.11.2/gdal-1.11.2.tar.gz - tar -xzvf gdal-1.11.2.tar.gz + tar -xzf gdal-1.11.2.tar.gz cd gdal-1.11.2 ./configure --prefix=$GDALINST/gdal-1.11.2 $GDALOPTS - make -j 2 + make -s -j 2 make install fi if [ ! -d $GDALINST/gdal-2.0.1 ]; then cd $GDALBUILD wget http://download.osgeo.org/gdal/2.0.1/gdal-2.0.1.tar.gz - tar -xzvf gdal-2.0.1.tar.gz + tar -xzf gdal-2.0.1.tar.gz cd gdal-2.0.1 ./configure --prefix=$GDALINST/gdal-2.0.1 $GDALOPTS - make -j 2 + make -s -j 2 make install fi From dc0b3d815ef8474c58a4c1d50eced21ab4be1089 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Wed, 21 Oct 2015 12:28:46 -0600 Subject: [PATCH 02/10] Restrict numpy<1.10 --- requirements-dev.txt | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 563cdc12..b24675a9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ coveralls>=0.4 cython>=0.23.1 delocate enum34 -numpy>=1.8.0 +numpy>=1.8, <1.10 snuggs>=1.2 pytest pytest-cov diff --git a/requirements.txt b/requirements.txt index 0b59530e..53c1b91c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ affine cligj enum34 -numpy>=1.8.0 +numpy>=1.8, <1.10 snuggs>=1.2 setuptools From c67382404aac6e5d4b956fcf93fed3f1b2567e06 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Wed, 21 Oct 2015 16:50:47 -0600 Subject: [PATCH 03/10] Dump out numpy version --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 67b96685..f1061851 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,8 @@ install: - "pip install --upgrade --force-reinstall --global-option=build_ext --global-option='-I$GDALINST/gdal-$GDALVERSION/include' --global-option='-L$GDALINST/gdal-$GDALVERSION/lib' --global-option='-R$GDALINST/gdal-$GDALVERSION/lib' -e ." - "pip install coveralls" - "pip install -e ." -script: + - python -c "import numpy; print numpy.__version__" +script: - py.test --cov rasterio --cov-report term-missing after_success: - coveralls From fd9ea904cc5df130af83d54128d51b12941fafa8 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Wed, 21 Oct 2015 21:50:47 -0600 Subject: [PATCH 04/10] Fill results for numpy>1.10 as well as <1.9 --- rasterio/rio/calc.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rasterio/rio/calc.py b/rasterio/rio/calc.py index 7018174e..b9df4ff3 100644 --- a/rasterio/rio/calc.py +++ b/rasterio/rio/calc.py @@ -123,8 +123,9 @@ def calc(ctx, command, files, output, name, dtype, masked, creation_options): res = snuggs.eval(command, **ctxkwds) - if (isinstance(res, np.ma.core.MaskedArray) and - tuple(LooseVersion(np.__version__).version) < (1, 9, 0)): + if (isinstance(res, np.ma.core.MaskedArray) and ( + tuple(LooseVersion(np.__version__).version) < (1, 9) or + tuple(LooseVersion(np.__version__).version) > (1, 10))): res = res.filled(kwargs['nodata']) if len(res.shape) == 3: From 4d79175b6c32092c441d4598223312f940a27630 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Wed, 21 Oct 2015 22:22:16 -0600 Subject: [PATCH 05/10] Remove numpy debugging, unpin versions --- .travis.yml | 1 - requirements-dev.txt | 2 +- requirements.txt | 2 +- setup.py | 7 +------ 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index f1061851..dbe6503a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,6 @@ install: - "pip install --upgrade --force-reinstall --global-option=build_ext --global-option='-I$GDALINST/gdal-$GDALVERSION/include' --global-option='-L$GDALINST/gdal-$GDALVERSION/lib' --global-option='-R$GDALINST/gdal-$GDALVERSION/lib' -e ." - "pip install coveralls" - "pip install -e ." - - python -c "import numpy; print numpy.__version__" script: - py.test --cov rasterio --cov-report term-missing after_success: diff --git a/requirements-dev.txt b/requirements-dev.txt index b24675a9..b9e2dd1a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ coveralls>=0.4 cython>=0.23.1 delocate enum34 -numpy>=1.8, <1.10 +numpy>=1.8 snuggs>=1.2 pytest pytest-cov diff --git a/requirements.txt b/requirements.txt index 53c1b91c..90718100 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ affine cligj enum34 -numpy>=1.8, <1.10 +numpy>=1.8 snuggs>=1.2 setuptools diff --git a/setup.py b/setup.py index ed3b07f1..0cefec97 100755 --- a/setup.py +++ b/setup.py @@ -193,12 +193,7 @@ with open('README.rst') as f: readme = f.read() # Runtime requirements. -inst_reqs = [ - 'affine>=1.0', - 'cligj>=0.2.0', - 'Numpy>=1.7', - 'snuggs>=1.3.1', - 'click-plugins'] +inst_reqs = ['affine', 'cligj', 'numpy', 'snuggs', 'click-plugins'] if sys.version_info < (3, 4): inst_reqs.append('enum34') From 49938067bc2a60a8bb370e7e2955d064d0d0ccc3 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Thu, 22 Oct 2015 12:30:22 -0600 Subject: [PATCH 06/10] No blocksizes in untiled profiles Closes #502 --- rasterio/_base.pyx | 15 +++++++++++---- rasterio/rio/merge.py | 1 + rasterio/rio/options.py | 2 ++ tests/data/shade.tif | Bin 1050093 -> 1050234 bytes tests/test_options.py | 2 +- tests/test_profile.py | 21 ++++++++++++++++++--- 6 files changed, 33 insertions(+), 8 deletions(-) diff --git a/rasterio/_base.pyx b/rasterio/_base.pyx index a5ef3697..04f454d0 100644 --- a/rasterio/_base.pyx +++ b/rasterio/_base.pyx @@ -448,6 +448,10 @@ cdef class DatasetReader(object): else: return None + @property + def is_tiled(self): + return self.block_shapes[0][1] != self.width + property profile: """Basic metadata and creation options of this dataset. @@ -457,10 +461,13 @@ cdef class DatasetReader(object): def __get__(self): m = self.meta m.update(self.tags(ns='rio_creation_kwds')) - m.update( - blockxsize=self.block_shapes[0][1], - blockysize=self.block_shapes[0][0], - tiled=self.block_shapes[0][1] != self.width) + if self.is_tiled: + m.update( + blockxsize=self.block_shapes[0][1], + blockysize=self.block_shapes[0][0], + tiled=True) + else: + m.update(tiled=False) if self.compression: m['compress'] = self.compression.name if self.interleaving: diff --git a/rasterio/rio/merge.py b/rasterio/rio/merge.py index d816ac74..5e637c87 100644 --- a/rasterio/rio/merge.py +++ b/rasterio/rio/merge.py @@ -73,6 +73,7 @@ def merge(ctx, files, output, driver, bounds, res, nodata, force_overwrite, profile['height'] = dest.shape[1] profile['width'] = dest.shape[2] profile['driver'] = driver + profile.update(**creation_options) with rasterio.open(output, 'w', **profile) as dst: diff --git a/rasterio/rio/options.py b/rasterio/rio/options.py index 0e5aeb82..dfccd54f 100644 --- a/rasterio/rio/options.py +++ b/rasterio/rio/options.py @@ -73,6 +73,8 @@ def _cb_key_val(ctx, param, value): raise click.BadParameter("Invalid syntax for KEY=VAL arg: {}".format(pair)) else: k, v = pair.split('=', 1) + k = k.lower() + v = v.lower() out[k] = v return out diff --git a/tests/data/shade.tif b/tests/data/shade.tif index 6a5a226262e55195dc162a0cfc6560c3e145272c..9ea0f3f0abefbd17e8c6efee26886b66c23055b9 100644 GIT binary patch literal 1050234 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
;Tns;3fvUs-%lBLbPL^ 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%0D4nNnWxUS5aH2U5PE8#ncBlN^zfXcXee*DA}Hgw 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%0DcPe<= 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 diff --git a/tests/test_options.py b/tests/test_options.py index 38ee698b..03bb15d2 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -7,7 +7,7 @@ def test_cb_key_val(): pairs = ['KEY=val', '1=='] expected = { - 'KEY': 'val', + 'key': 'val', '1': '=', } assert options._cb_key_val(None, None, pairs) == expected diff --git a/tests/test_profile.py b/tests/test_profile.py index 32979c4d..07cc2cf3 100644 --- a/tests/test_profile.py +++ b/tests/test_profile.py @@ -79,11 +79,26 @@ def test_profile_overlay(): assert kwds['count'] == 3 -def test_dataset_profile_property(data): +def test_dataset_profile_property_tiled(data): + """An tiled dataset's profile has block sizes""" + with rasterio.open('tests/data/shade.tif') as src: + assert src.profile['blockxsize'] == 256 + assert src.profile['blockysize'] == 256 + assert src.profile['tiled'] == True + + +def test_dataset_profile_property_untiled(data): + """An untiled dataset's profile has no block sizes""" + with rasterio.open('tests/data/RGB.byte.tif') as src: + assert 'blockxsize' not in src.profile + assert 'blockysize' not in src.profile + assert src.profile['tiled'] == False + + +def test_dataset_profile_creation_kwds(data): + """Updated creation keyword tags appear in profile""" tiffile = str(data.join('RGB.byte.tif')) with rasterio.open(tiffile, 'r+') as src: src.update_tags(ns='rio_creation_kwds', foo='bar') - assert src.profile['blockxsize'] == 791 - assert src.profile['blockysize'] == 3 assert src.profile['tiled'] == False assert src.profile['foo'] == 'bar' From 579213ba02089d1ca6942a1d747caa381a179f0c Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Thu, 22 Oct 2015 21:43:56 -0600 Subject: [PATCH 07/10] Update change log and version --- CHANGES.txt | 9 +++++++++ rasterio/__init__.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 03326b60..4f283416 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,15 @@ Changes ======= +0.29.0 (2015-10-22) +------------------- +- Fill masked arrays in rio-calc when using Numpy 1.10.x as well as with 1.8.x + (#500). +- When a raster dataset is not tiled, blockxszie and blockysize items are no + longer included in its `profile` property. This prevents meaningless block + size parameters from stripped, not tiled, datasets from being used when + creating new datasets (#503). + 0.28.0 (2015-10-06) ------------------- - Ensure that tools module is packaged (#489, #490). The rio-merge command was diff --git a/rasterio/__init__.py b/rasterio/__init__.py index 04601256..43a7b26c 100644 --- a/rasterio/__init__.py +++ b/rasterio/__init__.py @@ -23,7 +23,7 @@ from rasterio import _err, coords, enums __all__ = [ 'band', 'open', 'drivers', 'copy', 'pad'] -__version__ = "0.28.0" +__version__ = "0.29.0" log = logging.getLogger('rasterio') class NullHandler(logging.Handler): From 92bfde52c0da877cdbf15e6fac12b749c4cd4c22 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Fri, 23 Oct 2015 15:54:18 -0600 Subject: [PATCH 08/10] Add GDAL 2.0.1 to the matrix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index dbe6503a..5d86f82c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ env: matrix: - GDALVERSION = "1.9.2" - GDALVERSION = "1.11.2" - #- GDALVERSION = "2.0.1" + - GDALVERSION = "2.0.1" addons: apt: packages: From c0483c57f7ad8a48f9cf600cb6f3c807eeb12ffe Mon Sep 17 00:00:00 2001 From: Brendan Ward Date: Mon, 26 Oct 2015 22:10:33 -0700 Subject: [PATCH 09/10] Added Cython coverage reporting --- .coveragerc | 13 +++++++++++++ .travis.yml | 3 ++- requirements-dev.txt | 5 ++--- setup.cfg | 10 ++-------- setup.py | 19 +++++++++++++++---- 5 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..d3a89f1d --- /dev/null +++ b/.coveragerc @@ -0,0 +1,13 @@ +[run] +plugins = Cython.Coverage +source = rasterio +omit = *.pxd + +[report] +show_missing = True +exclude_lines = + pragma: no cover + def __repr__ + raise AssertionError + raise NotImplementedError + if __name__ == .__main__.: diff --git a/.travis.yml b/.travis.yml index 5d86f82c..73017285 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ env: - PIP_FIND_LINKS=file://$HOME/.cache/pip/wheels - GDALINST=$HOME/gdalinstall - GDALBUILD=$HOME/gdalbuild + - CYTHON_COVERAGE=1 matrix: - GDALVERSION = "1.9.2" - GDALVERSION = "1.11.2" @@ -37,7 +38,7 @@ install: - "pip wheel -r requirements-dev.txt" - "pip install -r requirements-dev.txt" - "pip install --upgrade --force-reinstall --global-option=build_ext --global-option='-I$GDALINST/gdal-$GDALVERSION/include' --global-option='-L$GDALINST/gdal-$GDALVERSION/lib' --global-option='-R$GDALINST/gdal-$GDALVERSION/lib' -e ." - - "pip install coveralls" + - "pip install coveralls>=1.1" - "pip install -e ." script: - py.test --cov rasterio --cov-report term-missing diff --git a/requirements-dev.txt b/requirements-dev.txt index b9e2dd1a..12ad0fda 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,12 +1,11 @@ affine cligj -coveralls>=0.4 -cython>=0.23.1 +cython>=0.23.4 delocate enum34 numpy>=1.8 snuggs>=1.2 pytest -pytest-cov +pytest-cov>=2.2.0 setuptools>=0.9.8 wheel diff --git a/setup.cfg b/setup.cfg index 5eea52d4..5ee64771 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,8 +1,2 @@ -[nosetests] -tests=rasterio/tests -nocapture=True -verbosity=3 -logging-filter=rasterio -logging-level=DEBUG -with-coverage=1 -cover-package=rasterio +[pytest] +testpaths = tests diff --git a/setup.py b/setup.py index 0cefec97..60789fd8 100755 --- a/setup.py +++ b/setup.py @@ -19,12 +19,10 @@ import sys from setuptools import setup from setuptools.extension import Extension + logging.basicConfig() log = logging.getLogger() -# python -W all setup.py ... -if 'all' in sys.warnoptions: - log.level = logging.DEBUG def check_output(cmd): # since subprocess.check_output doesn't exist in 2.6 @@ -39,6 +37,7 @@ def check_output(cmd): out, err = p.communicate() return out + def copy_data_tree(datadir, destdir): try: shutil.rmtree(destdir) @@ -46,6 +45,11 @@ def copy_data_tree(datadir, destdir): pass shutil.copytree(datadir, destdir) + +# python -W all setup.py ... +if 'all' in sys.warnoptions: + log.level = logging.DEBUG + # Parse the version from the rasterio module. with open('rasterio/__init__.py') as f: for line in f: @@ -135,6 +139,13 @@ if not os.name == "nt": ext_options['extra_compile_args'] = ['-Wno-unused-parameter', '-Wno-unused-function'] +cythonize_options = {} +if os.environ.get('CYTHON_COVERAGE'): + cythonize_options['compiler_directives'] = {'linetrace': True} + cythonize_options['annotate'] = True + ext_options['define_macros'] = [('CYTHON_TRACE', '1'), + ('CYTHON_TRACE_NOGIL', '1')] + log.debug('ext_options:\n%s', pprint.pformat(ext_options)) # When building from a repo, Cython is required. @@ -164,7 +175,7 @@ if os.path.exists("MANIFEST.in") and "clean" not in sys.argv: 'rasterio._err', ['rasterio/_err.pyx'], **ext_options), Extension( 'rasterio._example', ['rasterio/_example.pyx'], **ext_options), - ], quiet=True) + ], quiet=True, **cythonize_options) # If there's no manifest template, as in an sdist, we just specify .c files. else: From 7e69b225d450395d9111a9655421d76f5c314f60 Mon Sep 17 00:00:00 2001 From: Brendan Ward Date: Thu, 22 Oct 2015 22:51:04 -0700 Subject: [PATCH 10/10] Add more windows utilities: get_data_window, window_union, window_intersection, windows_intersect --- docs/windowed-rw.rst | 49 ++++++++++++++++ rasterio/__init__.py | 80 +++++++++++++++++++++++++ rasterio/_io.pyx | 130 +++++++++++++++++++++++++++++++++++++++++ tests/test_indexing.py | 125 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 384 insertions(+) diff --git a/docs/windowed-rw.rst b/docs/windowed-rw.rst index d91f5a98..fe5d4979 100644 --- a/docs/windowed-rw.rst +++ b/docs/windowed-rw.rst @@ -161,6 +161,55 @@ This example also demonstrates decimation. :width: 500 :height: 300 + +Data windows +------------ + +Sometimes it is desirable to crop off an outer boundary of NODATA values around +a dataset: + +.. code-block:: python + + from rasterio import get_data_window + + with rasterio.open('tests/data/RGB.byte.tif') as src: + window = get_data_window(src.read(1, masked=True)) + # window = ((3, 714), (13, 770)) + + kwargs = src.meta.copy() + del kwargs['transform'] + kwargs.update({ + 'height': window[0][1] - window[0][0], + 'width': window[1][1] - window[1][0], + 'affine': src.window_transform(window) + }) + + with rasterio.open('/tmp/cropped.tif', 'w', **kwargs) as dst: + dst.write(src.read(window=window)) + + +Window utilities +---------------- + +Basic union and intersection operations are available for windows, to streamline +operations across dynamically created windows for a series of bands or datasets +with the same full extent. + +.. code-block:: python + + from rasterio import window_union, window_intersection + + # Full window is ((0, 1000), (0, 500)) + window1 = ((100, 500), (10, 500)) + window2 = ((10, 150), (50, 250)) + + outer = window_union([window1, window2]) + # outer = ((10, 500), (10, 500)) + + inner = window_intersection([window1, window2]) + # inner = ((100, 150), (50, 250)) + + Blocks ------ diff --git a/rasterio/__init__.py b/rasterio/__init__.py index 04601256..2b8d162d 100644 --- a/rasterio/__init__.py +++ b/rasterio/__init__.py @@ -167,3 +167,83 @@ def pad(array, transform, pad_width, mode=None, **kwargs): padded_trans[2] -= pad_width*padded_trans[0] padded_trans[5] -= pad_width*padded_trans[4] return padded_array, Affine(*padded_trans[:6]) + + +def get_data_window(arr, nodata=None): + """ + Returns a window for the non-nodata pixels within the input array. + + Parameters + ---------- + arr: numpy ndarray, <= 3 dimensions + nodata: number + If None, will either return a full window if arr is not a masked + array, or will use the mask to determine non-nodata pixels. + If provided, it must be a number within the valid range of the dtype + of the input array. + + Returns + ------- + ((row_start, row_stop), (col_start, col_stop)) + + """ + + from rasterio._io import get_data_window + return get_data_window(arr, nodata) + + +def window_union(windows): + """ + Union windows and return the outermost extent they cover. + + Parameters + ---------- + windows: list-like of window objects + ((row_start, row_stop), (col_start, col_stop)) + + Returns + ------- + ((row_start, row_stop), (col_start, col_stop)) + """ + + from rasterio._io import window_union + return window_union(windows) + + +def window_intersection(windows): + """ + Intersect windows and return the innermost extent they cover. + + Will raise ValueError if windows do not intersect. + + Parameters + ---------- + windows: list-like of window objects + ((row_start, row_stop), (col_start, col_stop)) + + Returns + ------- + ((row_start, row_stop), (col_start, col_stop)) + """ + + from rasterio._io import window_intersection + return window_intersection(windows) + + +def windows_intersect(windows): + """ + Test if windows intersect. + + Parameters + ---------- + windows: list-like of window objects + ((row_start, row_stop), (col_start, col_stop)) + + Returns + ------- + boolean: + True if all windows intersect. + """ + + from rasterio._io import windows_intersect + return windows_intersect(windows) diff --git a/rasterio/_io.pyx b/rasterio/_io.pyx index 1d42712c..44afff77 100644 --- a/rasterio/_io.pyx +++ b/rasterio/_io.pyx @@ -2041,3 +2041,133 @@ def virtual_file_to_buffer(filename): log.debug("Buffer length: %d bytes", n) cdef np.uint8_t[:] buff_view = buff return buff_view + + +def get_data_window(arr, nodata=None): + """ + Returns a window for the non-nodata pixels within the input array. + + Parameters + ---------- + arr: numpy ndarray, <= 3 dimensions + nodata: number + If None, will either return a full window if arr is not a masked + array, or will use the mask to determine non-nodata pixels. + If provided, it must be a number within the valid range of the dtype + of the input array. + + Returns + ------- + ((row_start, row_stop), (col_start, col_stop)) + + """ + + num_dims = len(arr.shape) + if num_dims > 3: + raise ValueError('get_data_window input array must have no more than ' + '3 dimensions') + + if nodata is None: + if not hasattr(arr, 'mask'): + return ((0, arr.shape[-2]), (0, arr.shape[-1])) + else: + arr = np.ma.masked_array(arr, arr == nodata) + + if num_dims == 2: + data_rows, data_cols = np.where(arr.mask == False) + else: + data_rows, data_cols = np.where( + np.any(np.rollaxis(arr.mask, 0, 3) == False, axis=2) + ) + + if data_rows.size: + row_range = (data_rows.min(), data_rows.max() + 1) + else: + row_range = (0, 0) + + if data_cols.size: + col_range = (data_cols.min(), data_cols.max() + 1) + else: + col_range = (0, 0) + + return (row_range, col_range) + + +def window_union(windows): + """ + Union windows and return the outermost extent they cover. + + Parameters + ---------- + windows: list-like of window objects + ((row_start, row_stop), (col_start, col_stop)) + + Returns + ------- + ((row_start, row_stop), (col_start, col_stop)) + """ + + + stacked = np.dstack(windows) + return ( + (stacked[0, 0].min(), stacked[0, 1].max()), + (stacked[1, 0].min(), stacked[1, 1]. max()) + ) + + +def window_intersection(windows): + """ + Intersect windows and return the innermost extent they cover. + + Will raise ValueError if windows do not intersect. + + Parameters + ---------- + windows: list-like of window objects + ((row_start, row_stop), (col_start, col_stop)) + + Returns + ------- + ((row_start, row_stop), (col_start, col_stop)) + """ + + if not windows_intersect(windows): + raise ValueError('windows do not intersect') + + stacked = np.dstack(windows) + return ( + (stacked[0, 0].max(), stacked[0, 1].min()), + (stacked[1, 0].max(), stacked[1, 1]. min()) + ) + + +def windows_intersect(windows): + """ + Test if windows intersect. + + Parameters + ---------- + windows: list-like of window objects + ((row_start, row_stop), (col_start, col_stop)) + + Returns + ------- + boolean: + True if all windows intersect. + """ + + from itertools import combinations + + def intersects(range1, range2): + return not ( + range1[0] > range2[1] or range1[1] < range2[0] + ) + + windows = np.array(windows) + + for i in (0, 1): + for c in combinations(windows[:, i], 2): + if not intersects(*c): + return False + + return True diff --git a/tests/test_indexing.py b/tests/test_indexing.py index 257e7dcc..d42ca164 100644 --- a/tests/test_indexing.py +++ b/tests/test_indexing.py @@ -1,4 +1,13 @@ +import numpy +import pytest + import rasterio +from rasterio import ( + get_data_window, window_intersection, window_union, windows_intersect +) + + +DATA_WINDOW = ((3, 5), (2, 6)) def test_index(): @@ -67,3 +76,119 @@ def test_window_full_cover(): win = src.window(*bounds) bounds_calc = list(src.window_bounds(win)) assert bound_covers(bounds_calc, bounds) + + +@pytest.fixture +def data(): + data = numpy.zeros((10, 10), dtype='uint8') + data[slice(*DATA_WINDOW[0]), slice(*DATA_WINDOW[1])] = 1 + return data + + +def test_data_window_unmasked(data): + window = get_data_window(data) + assert window == ((0, data.shape[0]), (0, data.shape[1])) + + +def test_data_window_masked(data): + data = numpy.ma.masked_array(data, data == 0) + window = get_data_window(data) + assert window == DATA_WINDOW + + +def test_data_window_nodata(data): + window = get_data_window(data, nodata=0) + assert window == DATA_WINDOW + + window = get_data_window(numpy.ones_like(data), nodata=0) + assert window == ((0, data.shape[0]), (0, data.shape[1])) + + +def test_data_window_nodata_disjunct(): + data = numpy.zeros((3, 10, 10), dtype='uint8') + data[0, :4, 1:4] = 1 + data[1, 2:5, 2:8] = 1 + data[2, 1:6, 1:6] = 1 + window = get_data_window(data, nodata=0) + assert window == ((0, 6), (1, 8)) + + +def test_data_window_empty_result(): + data = numpy.zeros((3, 10, 10), dtype='uint8') + window = get_data_window(data, nodata=0) + assert window == ((0, 0), (0, 0)) + + +def test_data_window_masked_file(): + with rasterio.open('tests/data/RGB.byte.tif') as src: + window = get_data_window(src.read(1, masked=True)) + assert window == ((3, 714), (13, 770)) + + window = get_data_window(src.read(masked=True)) + assert window == ((3, 714), (13, 770)) + + +def test_window_union(): + assert window_union([ + ((0, 6), (3, 6)), + ((2, 4), (1, 5)) + ]) == ((0, 6), (1, 6)) + + +def test_window_intersection(): + assert window_intersection([ + ((0, 6), (3, 6)), + ((2, 4), (1, 5)) + ]) == ((2, 4), (3, 5)) + + assert window_intersection([ + ((0, 6), (3, 6)), + ((6, 10), (1, 5)) + ]) == ((6, 6), (3, 5)) + + assert window_intersection([ + ((0, 6), (3, 6)), + ((2, 4), (1, 5)), + ((3, 6), (0, 6)) + ]) == ((3, 4), (3, 5)) + + +def test_window_intersection_disjunct(): + with pytest.raises(ValueError): + window_intersection([ + ((0, 6), (3, 6)), + ((100, 200), (0, 12)), + ((7, 12), (7, 12)) + ]) + + +def test_windows_intersect(): + assert windows_intersect([ + ((0, 6), (3, 6)), + ((2, 4), (1, 5)) + ]) == True + + assert windows_intersect([ + ((0, 6), (3, 6)), + ((2, 4), (1, 5)), + ((3, 6), (0, 6)) + ]) == True + + +def test_windows_intersect_disjunct(): + assert windows_intersect([ + ((0, 6), (3, 6)), + ((10, 20), (0, 6)) + ]) == False + + assert windows_intersect([ + ((0, 6), (3, 6)), + ((2, 4), (1, 5)), + ((5, 6), (0, 6)) + ]) == False + + assert windows_intersect([ + ((0, 6), (3, 6)), + ((2, 4), (1, 3)), + ((3, 6), (4, 6)) + ]) == False \ No newline at end of file