summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarton Ip <bartoni@daughterlycare.com.au>2020-08-30 11:35:11 +0000
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-09-11 10:31:38 +0200
commit12d6cae7c0401baa70c934f465bad856afecc847 (patch)
treebdb275ccad0721e5081896e0deae6d0e57eda58c
parent5362e08624c6745181944a10979da876934ea136 (diff)
Fixed #31766 -- Made GDALRaster.transform() return a clone for the same SRID and driver.
Thanks Daniel Wiesmann for the review.
-rw-r--r--AUTHORS1
-rw-r--r--django/contrib/gis/gdal/raster/source.py24
-rw-r--r--tests/gis_tests/gdal_tests/test_raster.py83
3 files changed, 108 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
index 386837aee6..7e316cd739 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -110,6 +110,7 @@ answer newbie questions, and generally made Django that much better:
Baptiste Mispelon <bmispelon@gmail.com>
Barry Pederson <bp@barryp.org>
Bartolome Sanchez Salado <i42sasab@uco.es>
+ Barton Ip <notbartonip@gmail.com>
Bartosz Grabski <bartosz.grabski@gmail.com>
Bashar Al-Abdulhadi
Bastian Kleineidam <calvin@debian.org>
diff --git a/django/contrib/gis/gdal/raster/source.py b/django/contrib/gis/gdal/raster/source.py
index 05bbe49372..d3129368e2 100644
--- a/django/contrib/gis/gdal/raster/source.py
+++ b/django/contrib/gis/gdal/raster/source.py
@@ -425,6 +425,27 @@ class GDALRaster(GDALRasterBase):
return target
+ def clone(self, name=None):
+ """Return a clone of this GDALRaster."""
+ if name:
+ clone_name = name
+ elif self.driver.name != 'MEM':
+ clone_name = self.name + '_copy.' + self.driver.name
+ else:
+ clone_name = os.path.join(VSI_FILESYSTEM_BASE_PATH, str(uuid.uuid4()))
+ return GDALRaster(
+ capi.copy_ds(
+ self.driver._ptr,
+ force_bytes(clone_name),
+ self._ptr,
+ c_int(),
+ c_char_p(),
+ c_void_p(),
+ c_void_p(),
+ ),
+ write=self._write,
+ )
+
def transform(self, srs, driver=None, name=None, resampling='NearestNeighbour',
max_error=0.0):
"""
@@ -443,6 +464,9 @@ class GDALRaster(GDALRasterBase):
'Transform only accepts SpatialReference, string, and integer '
'objects.'
)
+
+ if target_srs.srid == self.srid and (not driver or driver == self.driver.name):
+ return self.clone(name)
# Create warped virtual dataset in the target reference system
target = capi.auto_create_warped_vrt(
self._ptr, self.srs.wkt.encode(), target_srs.wkt.encode(),
diff --git a/tests/gis_tests/gdal_tests/test_raster.py b/tests/gis_tests/gdal_tests/test_raster.py
index 98ac9d6340..7f690759f6 100644
--- a/tests/gis_tests/gdal_tests/test_raster.py
+++ b/tests/gis_tests/gdal_tests/test_raster.py
@@ -2,6 +2,7 @@ import os
import shutil
import struct
import tempfile
+from unittest import mock
from django.contrib.gis.gdal import GDAL_VERSION, GDALRaster, SpatialReference
from django.contrib.gis.gdal.error import GDALException
@@ -470,6 +471,40 @@ class GDALRasterTests(SimpleTestCase):
# The result is an empty raster filled with the correct nodata value.
self.assertEqual(result, [23] * 16)
+ def test_raster_clone(self):
+ rstfile = tempfile.NamedTemporaryFile(suffix='.tif')
+ tests = [
+ ('MEM', '', 23), # In memory raster.
+ ('tif', rstfile.name, 99), # In file based raster.
+ ]
+ for driver, name, nodata_value in tests:
+ with self.subTest(driver=driver):
+ source = GDALRaster({
+ 'datatype': 1,
+ 'driver': driver,
+ 'name': name,
+ 'width': 4,
+ 'height': 4,
+ 'srid': 3086,
+ 'origin': (500000, 400000),
+ 'scale': (100, -100),
+ 'skew': (0, 0),
+ 'bands': [{
+ 'data': range(16),
+ 'nodata_value': nodata_value,
+ }],
+ })
+ clone = source.clone()
+ self.assertNotEqual(clone.name, source.name)
+ self.assertEqual(clone._write, source._write)
+ self.assertEqual(clone.srs.srid, source.srs.srid)
+ self.assertEqual(clone.width, source.width)
+ self.assertEqual(clone.height, source.height)
+ self.assertEqual(clone.origin, source.origin)
+ self.assertEqual(clone.scale, source.scale)
+ self.assertEqual(clone.skew, source.skew)
+ self.assertIsNot(clone, source)
+
def test_raster_transform(self):
tests = [
3086,
@@ -531,6 +566,54 @@ class GDALRasterTests(SimpleTestCase):
],
)
+ def test_raster_transform_clone(self):
+ with mock.patch.object(GDALRaster, 'clone') as mocked_clone:
+ # Create in file based raster.
+ rstfile = tempfile.NamedTemporaryFile(suffix='.tif')
+ source = GDALRaster({
+ 'datatype': 1,
+ 'driver': 'tif',
+ 'name': rstfile.name,
+ 'width': 5,
+ 'height': 5,
+ 'nr_of_bands': 1,
+ 'srid': 4326,
+ 'origin': (-5, 5),
+ 'scale': (2, -2),
+ 'skew': (0, 0),
+ 'bands': [{
+ 'data': range(25),
+ 'nodata_value': 99,
+ }],
+ })
+ # transform() returns a clone because it is the same SRID and
+ # driver.
+ source.transform(4326)
+ self.assertEqual(mocked_clone.call_count, 1)
+
+ def test_raster_transform_clone_name(self):
+ # Create in file based raster.
+ rstfile = tempfile.NamedTemporaryFile(suffix='.tif')
+ source = GDALRaster({
+ 'datatype': 1,
+ 'driver': 'tif',
+ 'name': rstfile.name,
+ 'width': 5,
+ 'height': 5,
+ 'nr_of_bands': 1,
+ 'srid': 4326,
+ 'origin': (-5, 5),
+ 'scale': (2, -2),
+ 'skew': (0, 0),
+ 'bands': [{
+ 'data': range(25),
+ 'nodata_value': 99,
+ }],
+ })
+ clone_name = rstfile.name + '_respect_name.GTiff'
+ target = source.transform(4326, name=clone_name)
+ self.assertEqual(target.name, clone_name)
+
class GDALBandTests(SimpleTestCase):
rs_path = os.path.join(os.path.dirname(__file__), '../data/rasters/raster.tif')