Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed #31766 -- Made GDALRaster.transform() return a clone for the same SRID and driver. #13365

Merged
merged 1 commit into from Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -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>
Expand Down
24 changes: 24 additions & 0 deletions django/contrib/gis/gdal/raster/source.py
Expand Up @@ -425,6 +425,27 @@ def warp(self, ds_input, resampling='NearestNeighbour', max_error=0.0):

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,
)
bartonip marked this conversation as resolved.
Show resolved Hide resolved

def transform(self, srs, driver=None, name=None, resampling='NearestNeighbour',
max_error=0.0):
"""
Expand All @@ -443,6 +464,9 @@ def transform(self, srs, driver=None, name=None, resampling='NearestNeighbour',
'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(),
Expand Down
83 changes: 83 additions & 0 deletions tests/gis_tests/gdal_tests/test_raster.py
Expand Up @@ -2,6 +2,7 @@
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
Expand Down Expand Up @@ -470,6 +471,40 @@ def test_raster_warp_nodata_zone(self):
# 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,
Expand Down Expand Up @@ -531,6 +566,54 @@ def test_raster_transform(self):
],
)

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')
Expand Down