This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit e88fd77241f423f60c06b504a3b9a9c39e54acb9
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Oct 8 12:57:22 2026 +0200

    Rename GeoTIFF `Localization` class as `ModelTiePoints` and use the class 
added in previous commit for tabular formatting.
---
 .../apache/sis/storage/geotiff/NativeMetadata.java |  9 ++-
 .../geotiff/reader/GridGeometryBuilder.java        |  6 +-
 .../{Localization.java => ModelTiePoints.java}     | 77 +++++++++++++++++++---
 ...calizationTest.java => ModelTiePointsTest.java} | 14 ++--
 4 files changed, 86 insertions(+), 20 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/NativeMetadata.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/NativeMetadata.java
index 39c7a23780..6f7abffbfc 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/NativeMetadata.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/NativeMetadata.java
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.storage.geotiff;
 
-import java.util.Set;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.LinkedHashMap;
@@ -41,6 +40,7 @@ import org.apache.sis.storage.geotiff.base.GeoKeys;
 import org.apache.sis.storage.geotiff.base.Tags;
 import org.apache.sis.storage.geotiff.reader.Type;
 import org.apache.sis.storage.geotiff.reader.GeoKeysLoader;
+import org.apache.sis.storage.geotiff.reader.ModelTiePoints;
 import org.apache.sis.storage.geotiff.reader.XMLMetadata;
 
 
@@ -116,7 +116,7 @@ final class NativeMetadata extends GeoKeysLoader {
         input.mark();
         try {
             input.seek(isClassic ? 2*Short.BYTES : 4*Short.BYTES);
-            final Set<Long> doneIFD = new HashSet<>();
+            final var doneIFD = new HashSet<Long>();
             long nextIFD;
             /*
              * Following loop is a simplified copy of 
`Reader.getImageFileDirectory(int)` method,
@@ -187,6 +187,10 @@ final class NativeMetadata extends GeoKeysLoader {
                                 }
                                 break;
                             }
+                            case (short) TAG_MODEL_TIE_POINT: {
+                                value = new 
ModelTiePoints(type.readAsVector(input, count));
+                                break;
+                            }
                             default: {
                                 value = type.readAsObject(input, count);
                                 if (value instanceof Vector) {
@@ -278,6 +282,7 @@ final class NativeMetadata extends GeoKeysLoader {
                                             }
                                             return String.join(", ", items);
                                         });
+                                        break;
                                     }
                                 }
                             }
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java
index cf6abb4b17..7e779168f7 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java
@@ -228,7 +228,7 @@ public final class GridGeometryBuilder extends 
GeoKeysLoader {
             int nearest = 0;                                // Index of the 
record nearest to origin.
             double distance = Double.POSITIVE_INFINITY;     // Distance 
squared of the nearest record.
             final int size = modelTiePoints.size();
-            for (int i=0; i<size; i += Localization.RECORD_LENGTH) {
+            for (int i=0; i<size; i += ModelTiePoints.RECORD_LENGTH) {
                 double t;
                 final double d = (t = modelTiePoints.doubleValue(i    )) * t
                                + (t = modelTiePoints.doubleValue(i + 1)) * t
@@ -252,7 +252,7 @@ public final class GridGeometryBuilder extends 
GeoKeysLoader {
                 final int trCol  = affine.getNumCol() - 1;
                 for (int j=0; j<numDim; j++) {
                     final double src = -modelTiePoints.doubleValue(nearest + 
j);
-                    final double tgt =  modelTiePoints.doubleValue(nearest + j 
+ Localization.RECORD_LENGTH / BIDIMENSIONAL);
+                    final double tgt =  modelTiePoints.doubleValue(nearest + j 
+ ModelTiePoints.RECORD_LENGTH / BIDIMENSIONAL);
                     var t = DoubleDouble.of(src, 
decimal).multiply(affine.getNumber(j,j), decimal).add(tgt, decimal);
                     affine.setNumber(j, trCol, t);
                 }
@@ -362,7 +362,7 @@ public final class GridGeometryBuilder extends 
GeoKeysLoader {
                 gridToCRS = factory.createAffineTransform(m);
             } else if (modelTiePoints != null) {
                 anchor    = PixelInCell.CELL_CENTER;
-                gridToCRS = Localization.nonLinear(modelTiePoints);
+                gridToCRS = new ModelTiePoints(modelTiePoints).nonLinear();
                 gridToCRS = factory.createPassThroughTransform(0, gridToCRS, 
spatialDimension - BIDIMENSIONAL);
                 if (temporalCRS != null) {
                     gridToCRS = MathTransforms.compound(gridToCRS, 
MathTransforms.linear(Double.NaN, timeCoordinate));
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/Localization.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ModelTiePoints.java
similarity index 83%
rename from 
endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/Localization.java
rename to 
endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ModelTiePoints.java
index 731c24b302..c65aaa000b 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/Localization.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ModelTiePoints.java
@@ -21,6 +21,9 @@ import java.util.Set;
 import java.util.Map;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.Objects;
+import java.util.Locale;
+import java.text.Format;
 import org.opengis.geometry.Envelope;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.MathTransform;
@@ -29,20 +32,19 @@ import 
org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.operation.transform.LinearTransform;
 import org.apache.sis.referencing.operation.builder.LocalizationGridBuilder;
 import org.apache.sis.referencing.factory.InternalFactoryException;
+import org.apache.sis.util.internal.shared.TableRowList;
 import org.apache.sis.math.Vector;
 
 
 /**
  * The conversion or transformation from pixel coordinates to model 
coordinates.
+ * Used for analyzing the {@code TAG_MODEL_TIE_POINT} data from a GeoTIFF file.
  * The target CRS may be the image CRS if the image is "georeferenceable" 
instead of georeferenced.
  *
- * This code is provided in a separated class for making easier to move it to 
some shared location
- * if another data store needs similar functionality in the future.
- *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Jonatas Fischer
  */
-final class Localization {
+public final class ModelTiePoints extends TableRowList<Vector, Double> {
     /**
      * Number of floating point values in each (I,J,K,X,Y,Z) record.
      */
@@ -57,9 +59,68 @@ final class Localization {
     private static final double PRECISION = 1E-6;
 
     /**
-     * Do not allow instantiation of this class.
+     * Coordinates of the model tie points read from GeoTIFF file.
+     */
+    private final Vector coordinates;
+
+    /**
+     * Creates a new localization grid.
+     *
+     * @param  coordinates  the model tie points read from GeoTIFF file.
+     */
+    public ModelTiePoints(final Vector coordinates) {
+        this.coordinates = coordinates;
+    }
+
+    /**
+     * Returns the number of rows in the model tie points.
+     *
+     * @return number of (I,J,K,X,Y,Z) records.
+     */
+    @Override
+    public int size() {
+        return coordinates.size() / RECORD_LENGTH;
+    }
+
+    /**
+     * Returns the column headers.
+     * The returned array length is {@link #RECORD_LENGTH}.
+     */
+    @Override
+    public String[] columns() {
+        return new String[] {"i", "j", "k", "x", "y", "z"};
+    }
+
+    /**
+     * Returns the value in the specified row and column.
+     */
+    @Override
+    public Double get(final int row, final int column) {
+        Objects.checkIndex(row, size());
+        Objects.checkIndex(column, RECORD_LENGTH);
+        return coordinates.doubleValue(row * RECORD_LENGTH + column);
+    }
+
+    /**
+     * Returns the source and (I,J,K,X,Y,Z) record in the given row.
+     */
+    @Override
+    public Vector get(int row) {
+        Objects.checkIndex(row, size());
+        row *= RECORD_LENGTH;
+        return coordinates.subList(row, row + RECORD_LENGTH);
+    }
+
+    /**
+     * Returns the format to use for the given column.
+     *
+     * @param  locale  the locale of the format to create.
+     * @param  column  the column for which to get a format.
      */
-    private Localization() {
+    @Override
+    public Format createFormat(final Locale locale, final int column) {
+        return coordinates.subSampling(Objects.checkIndex(column, 
RECORD_LENGTH), RECORD_LENGTH, size())
+                          .createNumberFormat(locale);
     }
 
     /**
@@ -69,8 +130,8 @@ final class Localization {
      * @param  modelTiePoints  the tie points to use for computing {@code 
gridToCRS}.
      * @return the grid geometry created from above properties. Never null.
      */
-    static MathTransform nonLinear(final Vector modelTiePoints) throws 
FactoryException, TransformException {
-        return localizationGrid(modelTiePoints, null);
+    final MathTransform nonLinear() throws FactoryException, 
TransformException {
+        return localizationGrid(coordinates, null);
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/LocalizationTest.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/ModelTiePointsTest.java
similarity index 95%
rename from 
endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/LocalizationTest.java
rename to 
endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/ModelTiePointsTest.java
index 111ea6a9a9..f95781e93e 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/LocalizationTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/ModelTiePointsTest.java
@@ -38,7 +38,7 @@ import org.apache.sis.test.TestCase;
  *
  * @author  Jonatas Fischer
  */
-public final class LocalizationTest extends TestCase {
+public final class ModelTiePointsTest extends TestCase {
     /**
      * Tolerance threshold, in degrees, when comparing tie point coordinates.
      * This is about one metre, while the tie points of the grids tested here
@@ -55,7 +55,7 @@ public final class LocalizationTest extends TestCase {
     /**
      * Creates a new test case.
      */
-    public LocalizationTest() {
+    public ModelTiePointsTest() {
     }
 
     /**
@@ -95,7 +95,7 @@ public final class LocalizationTest extends TestCase {
     /**
      * Returns the pixel coordinates of {@value #GRID_SIZE} tie points spaced 
by the given step,
      * except the last point which is closer to its predecessor. This is the 
spacing of Sentinel 1
-     * images, and the reason why {@link Localization} splits irregular grids 
in four parts.
+     * images, and the reason why {@link ModelTiePoints} splits irregular 
grids in four parts.
      *
      * @param  step  step between two consecutive tie points, except the last 
two.
      * @param  last  step between the two last tie points.
@@ -121,7 +121,7 @@ public final class LocalizationTest extends TestCase {
      * @return the (I,J,K,X,Y,Z) records of the tie points.
      */
     private static Vector tiePoints(final double[] columns, final double[] 
rows) {
-        final double[] records = new double[columns.length * rows.length * 
Localization.RECORD_LENGTH];
+        final double[] records = new double[columns.length * rows.length * 
ModelTiePoints.RECORD_LENGTH];
         int p = 0;
         for (final double y : rows) {
             for (final double x : columns) {
@@ -147,11 +147,11 @@ public final class LocalizationTest extends TestCase {
      */
     private static void verify(final double[] columns, final double[] rows) 
throws Exception {
         final Vector tiePoints = tiePoints(columns, rows);
-        final MathTransform gridToCRS = Localization.nonLinear(tiePoints);
+        final MathTransform gridToCRS = new 
ModelTiePoints(tiePoints).nonLinear();
         assertNotNull(gridToCRS);
         final double[] source = new double[2];
         final double[] target = new double[2];
-        for (int i=0; i<tiePoints.size(); i += Localization.RECORD_LENGTH) {
+        for (int i=0; i<tiePoints.size(); i += ModelTiePoints.RECORD_LENGTH) {
             source[0] = tiePoints.doubleValue(i);
             source[1] = tiePoints.doubleValue(i+1);
             gridToCRS.transform(source, 0, target, 0, 1);
@@ -194,7 +194,7 @@ public final class LocalizationTest extends TestCase {
 
     /**
      * Tests a grid where the steps differ by one pixel on a single axis. Only 
two of the four parts
-     * in which {@code Localization} would split such a grid receive points; 
the empty parts shall
+     * in which {@code ModelTiePoints} would split such a grid receive points; 
the empty parts shall
      * not cause an {@link IndexOutOfBoundsException}.
      *
      * <p>This is the case of ICEYE Single Look Complex images of 114644 × 
16714 pixels:

Reply via email to