This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push: new f797799d32 Missing translation when writing a GeoTIFF file with grid coordinates that do not start at zero. f797799d32 is described below commit f797799d320ac7249520fdfb822c685343ae9bd4 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Jan 24 16:53:29 2025 +0100 Missing translation when writing a GeoTIFF file with grid coordinates that do not start at zero. --- .../org/apache/sis/coverage/grid/GridGeometry.java | 19 +++++++++++++++++++ .../apache/sis/coverage/grid/GridGeometryTest.java | 14 +++++++++++--- .../apache/sis/storage/geotiff/writer/GeoEncoder.java | 9 +++++---- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java index b8e60e5817..d70c086fac 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java @@ -1669,6 +1669,25 @@ public class GridGeometry implements LenientComparable, Serializable { return new GridGeometry(newExtent, t1, t2, envelope, resolution, nonLinears); } + /** + * Translates the grid to lower coordinate values of zero without changing the "real world" coordinates. + * The returned grid has the same {@linkplain GridExtent#getSize(int) size} than this grid, + * i.e. both low and high grid coordinates are displaced by the same number of cells. + * The "grid to CRS" transforms are adjusted accordingly in order to map to the same + * "real world" coordinates. + * + * @return a grid geometry whose lower coordinates are zeros. + * @throws ArithmeticException if the translation results in upper coordinates that overflow 64-bits integer. + * + * @since 1.5 + */ + public GridGeometry shiftGridToZeros() { + if (extent == null || extent.startsAtZero()) { + return this; + } + return shiftGrid(extent.getLow().getCoordinateValues(), true); + } + /** * Returns a grid geometry with the given grid extent, which implies a new "real world" computation. * The "grid to CRS" transforms and the resolution stay the same as this {@code GridGeometry}. diff --git a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridGeometryTest.java b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridGeometryTest.java index 7798fd1487..603e8c6259 100644 --- a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridGeometryTest.java +++ b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/coverage/grid/GridGeometryTest.java @@ -555,6 +555,7 @@ public final class GridGeometryTest extends TestCase { /** * Tests {@link GridGeometry#shiftGrid(long[])}. + * Also opportunistically tests the closely-related {@link GridGeometry#shiftGridToZeros()} method. */ @Test public void testShiftGrid() { @@ -569,10 +570,17 @@ public final class GridGeometryTest extends TestCase { /* * The "real world" envelope should be unchanged by grid translation. */ + assertSame(grid, grid.shiftGridToZeros()); final Envelope envelope = grid.getEnvelope(); - grid = grid.shiftGrid(12, 15); - assertExtentEquals(new long[] {12, 15}, new long[] {12 + 16, 15 + 9}, grid.getExtent()); - assertEquals(envelope, grid.getEnvelope()); + GridGeometry shifted = grid.shiftGrid(12, 15); + assertExtentEquals(new long[] {12, 15}, new long[] {12 + 16, 15 + 9}, shifted.getExtent()); + assertEquals(envelope, shifted.getEnvelope()); + /* + * Shift back to zero. + */ + assertNotEquals(grid, shifted); + shifted = shifted.shiftGridToZeros(); + assertEquals(grid, shifted); } /** diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java index 3f9f551ae3..fc61bfaef5 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java @@ -243,9 +243,10 @@ public final class GeoEncoder { * @throws IncompleteGridGeometryException if the grid geometry is incomplete. * @throws IncompatibleResourceException if the grid geometry cannot be encoded. */ - public void write(final GridGeometry grid, final MetadataFetcher<?> metadata) + public void write(GridGeometry grid, final MetadataFetcher<?> metadata) throws FactoryException, TransformException, IncommensurableException, IncompatibleResourceException { + grid = grid.shiftGridToZeros(); citation = CollectionsExt.first(metadata.transformationDimension); isPoint = CollectionsExt.first(metadata.cellGeometry) == CellGeometry.POINT; final var anchor = isPoint ? PixelInCell.CELL_CENTER : PixelInCell.CELL_CORNER; @@ -290,8 +291,8 @@ public final class GeoEncoder { final VerticalCRS vertical = CRS.getVerticalComponent(fullCRS, true); if (vertical != null) { final CoordinateSystem cs = vertical.getCoordinateSystem(); - final int vi = AxisDirections.indexOfColinear(fullCRS.getCoordinateSystem(), cs); - if (vi >= 0 && Arrays.binarySearch(dimensions, vi) < 0) { + final int verticalDimension = AxisDirections.indexOfColinear(fullCRS.getCoordinateSystem(), cs); + if (verticalDimension >= 0 && Arrays.binarySearch(dimensions, verticalDimension) < 0) { writeCRS(vertical); axisDirections = Arrays.copyOf(axisDirections, BIDIMENSIONAL+1); axisDirections[BIDIMENSIONAL] = cs.getAxis(0).getDirection(); @@ -302,7 +303,7 @@ public final class GeoEncoder { final int s; switch (i) { default: s = dimensions[i]; break; // Shear from horizontal dimensions. - case BIDIMENSIONAL: s = vi; break; // Scale from vertical dimension. + case BIDIMENSIONAL: s = verticalDimension; break; // Scale from vertical dimension. case MATRIX_SIZE-1: s = more.getNumCol() - 1; break; // Translation. } // Copy the rows of the third dimension.