diff --git a/python/cog3pio/__init__.pyi b/python/cog3pio/__init__.pyi index e116b80..f2cf22f 100644 --- a/python/cog3pio/__init__.pyi +++ b/python/cog3pio/__init__.pyi @@ -76,7 +76,7 @@ class CogReader: Determined based on an Affine transformation matrix built from the `ModelPixelScaleTag` and `ModelTiepointTag` TIFF tags. Note that non-zero - rotation (set by `ModelTransformationTag` is currently unsupported. + rotation (set by `ModelTransformationTag`) is currently unsupported. Returns ------- @@ -206,6 +206,20 @@ class CudaCogReader: device : (int, int) A tuple (`device_type`, `device_id`) in DLPack format. """ + def xy_coords(self) -> tuple[numpy.typing.NDArray[numpy.float64], numpy.typing.NDArray[numpy.float64]]: + r""" + Get list of x and y coordinates. + + Determined based on an Affine transformation matrix built from the + `ModelPixelScaleTag` and `ModelTiepointTag` TIFF tags. Note that non-zero + rotation (set by `ModelTransformationTag`) is currently unsupported. + + Returns + ------- + coords : (numpy.ndarray, numpy.ndarray) + A tuple (x_coords, y_coords) of numpy.ndarray objects representing the + GeoTIFF's x- and y-coordinates. + """ def read_geotiff(path: builtins.str) -> numpy.typing.NDArray[numpy.float32]: r""" diff --git a/python/tests/test_io_geotiff.py b/python/tests/test_io_geotiff.py index 550532d..084a474 100644 --- a/python/tests/test_io_geotiff.py +++ b/python/tests/test_io_geotiff.py @@ -116,7 +116,7 @@ def test_read_geotiff_unsupported_dtype(): ) -def test_CogReader_to_dlpack(): +def test_cogReader_to_dlpack(): """ Ensure that the CogReader class's `__dlpack__` method produces a dl_tensor that can be read into a numpy.ndarray. @@ -136,3 +136,34 @@ def test_CogReader_to_dlpack(): [[[1.41, 1.23, 0.78], [0.32, -0.23, -1.88]]], dtype=np.float32 ), ) + + +def test_cogreader_xy_coords(): + """ + Ensure that the CogReader class's `xy_coords` method produces two numpy.ndarray + objects representing the GeoTIFF's x- and y- coordinates. + """ + cog = CogReader( + path="https://github.com/blacha/cogeotiff/raw/core-v9.4.0/packages/core/data/DEM_BS28_2016_1000_1141.tif" + ) + x_coords, y_coords = cog.xy_coords() + np.testing.assert_equal( + actual=x_coords, + desired=np.linspace( + start=1679617.031, + stop=1679680.031, + num=63, + endpoint=False, + dtype=np.float64, + ), + ) + np.testing.assert_equal( + actual=y_coords, + desired=np.linspace( + start=5362323.781, + stop=5362079.781, + num=244, + endpoint=False, + dtype=np.float64, + ), + ) diff --git a/python/tests/test_io_nvtiff.py b/python/tests/test_io_nvtiff.py index 91e0021..caf3573 100644 --- a/python/tests/test_io_nvtiff.py +++ b/python/tests/test_io_nvtiff.py @@ -44,6 +44,38 @@ def test_cudacogreader_to_dlpack(): ) +def test_cudacogreader_xy_coords(): + """ + Ensure that the CudaCogReader class's `xy_coords` method produces two numpy.ndarray + objects representing the GeoTIFF's x- and y- coordinates. + """ + cog = CudaCogReader( + path="https://github.com/blacha/cogeotiff/raw/core-v9.4.0/packages/core/data/DEM_BS28_2016_1000_1141.tif", + device_id=0, + ) + x_coords, y_coords = cog.xy_coords() + np.testing.assert_equal( + actual=x_coords, + desired=np.linspace( + start=1679617.031, + stop=1679680.031, + num=63, + endpoint=False, + dtype=np.float64, + ), + ) + np.testing.assert_equal( + actual=y_coords, + desired=np.linspace( + start=5362323.781, + stop=5362079.781, + num=244, + endpoint=False, + dtype=np.float64, + ), + ) + + @pytest.mark.benchmark @pytest.mark.parametrize( "engine", diff --git a/src/python/adapters.rs b/src/python/adapters.rs index ed91319..7356c0a 100644 --- a/src/python/adapters.rs +++ b/src/python/adapters.rs @@ -115,7 +115,7 @@ impl PyCogReader { /// /// Determined based on an Affine transformation matrix built from the /// `ModelPixelScaleTag` and `ModelTiepointTag` TIFF tags. Note that non-zero - /// rotation (set by `ModelTransformationTag` is currently unsupported. + /// rotation (set by `ModelTransformationTag`) is currently unsupported. /// /// Returns /// ------- diff --git a/src/python/cudacog.rs b/src/python/cudacog.rs index 77f4d97..cb80bf6 100644 --- a/src/python/cudacog.rs +++ b/src/python/cudacog.rs @@ -6,13 +6,15 @@ use bytes::Bytes; use cudarc::driver::{CudaContext, CudaStream}; use dlpark::SafeManagedTensorVersioned; use dlpark::ffi::{DLPACK_MAJOR_VERSION, DLPACK_MINOR_VERSION, Device}; +use numpy::{PyArray1, ToPyArray}; use pyo3::exceptions::{PyBufferError, PyNotImplementedError, PyValueError, PyWarning}; -use pyo3::{PyResult, pyclass, pymethods}; +use pyo3::{Bound, PyResult, Python, pyclass, pymethods}; use pyo3_stub_gen::define_stub_info_gatherer; use pyo3_stub_gen_derive::{gen_stub_pyclass, gen_stub_pymethods}; use crate::io::nvtiff::CudaCogReader; use crate::python::adapters::path_to_stream; +use crate::traits::Transform; /// Python class interface to a Cloud-optimized GeoTIFF reader (nvTIFF backend) that /// decodes to GPU (CUDA) memory. @@ -228,6 +230,30 @@ impl PyCudaCogReader { fn __dlpack_device__(&self) -> (i32, i32) { (self.device.device_type as i32, self.device.device_id) } + + /// Get list of x and y coordinates. + /// + /// Determined based on an Affine transformation matrix built from the + /// `ModelPixelScaleTag` and `ModelTiepointTag` TIFF tags. Note that non-zero + /// rotation (set by `ModelTransformationTag`) is currently unsupported. + /// + /// Returns + /// ------- + /// coords : (numpy.ndarray, numpy.ndarray) + /// A tuple (x_coords, y_coords) of numpy.ndarray objects representing the + /// GeoTIFF's x- and y-coordinates. + #[allow(clippy::type_complexity)] + fn xy_coords<'py>( + &self, + py: Python<'py>, + ) -> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { + let (x_coords, y_coords) = self + .inner + .xy_coords() + .map_err(|err| PyValueError::new_err(err.frame().to_string()))?; + + Ok((x_coords.to_pyarray(py), y_coords.to_pyarray(py))) + } } // Define a function to gather stub information.