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

jsorel 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 5364df70d4 Handle more divers structures in GIMI files
5364df70d4 is described below

commit 5364df70d40967b0511184daed56b53f7be18a36
Author: jsorel <johann.so...@geomatys.com>
AuthorDate: Tue Oct 1 16:50:40 2024 +0200

    Handle more divers structures in GIMI files
---
 .../org/apache/sis/storage/gimi/GimiProvider.java  |   2 +-
 .../org/apache/sis/storage/gimi/GimiStore.java     |  17 ++-
 .../apache/sis/storage/gimi/GimiTileMatrix.java    |   4 +-
 .../org/apache/sis/storage/gimi/ResourceGrid.java  |  64 +++++++---
 .../storage/gimi/ResourceImageUncompressed.java    | 134 ++++++++++++++++-----
 .../apache/sis/storage/gimi/ResourcePyramid.java   |  62 +++++++++-
 .../sis/storage/gimi/internal/ScaleSortedMap.java  |   2 +-
 .../isobmff/gimi/ModelTransformationProperty.java  |   9 ++
 .../gimi/isobmff/gimi/WellKnownText2Property.java  |   9 ++
 .../gimi/isobmff/iso23001_17/TAIClockInfo.java     |   4 +-
 10 files changed, 250 insertions(+), 57 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiProvider.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiProvider.java
index 3ec75d1fe1..239e08d1e5 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiProvider.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiProvider.java
@@ -90,7 +90,7 @@ public final class GimiProvider extends DataStoreProvider {
         final Path path = connector.getStorageAs(Path.class);
         if (path != null) {
             final String name = path.getFileName().toString().toLowerCase();
-            if (name.endsWith(".heij") || name.endsWith(".heif")) {
+            if (name.endsWith(".heij") || name.endsWith(".heif") || 
name.endsWith(".heic") || name.endsWith(".avif")) {
                 return new ProbeResult(true, MIME_TYPE, null);
             }
         }
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiStore.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiStore.java
index 74a6aa4039..5490c19cb4 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiStore.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiStore.java
@@ -27,12 +27,14 @@ import java.util.Optional;
 import org.opengis.metadata.Metadata;
 import org.opengis.parameter.ParameterValueGroup;
 import org.apache.sis.io.stream.ChannelDataInput;
+import org.apache.sis.io.stream.IOUtilities;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.storage.Aggregate;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.base.MetadataBuilder;
 import org.apache.sis.storage.gimi.isobmff.Box;
 import org.apache.sis.storage.gimi.isobmff.ISOBMFFReader;
 import org.apache.sis.storage.gimi.isobmff.iso14496_12.GroupList;
@@ -40,6 +42,7 @@ import 
org.apache.sis.storage.gimi.isobmff.iso14496_12.ItemInfo;
 import org.apache.sis.storage.gimi.isobmff.iso14496_12.ItemInfoEntry;
 import org.apache.sis.storage.gimi.isobmff.iso14496_12.Meta;
 import org.apache.sis.storage.gimi.isobmff.iso23008_12.ImagePyramidEntityGroup;
+import org.apache.sis.util.iso.Names;
 
 
 /**
@@ -52,6 +55,7 @@ public final class GimiStore extends DataStore implements 
Aggregate {
 
     private List<Resource> components;
     private Map<Integer,Resource> componentIndex;
+    private Metadata metadata;
 
     //cache the reader
     private ISOBMFFReader reader;
@@ -72,8 +76,13 @@ public final class GimiStore extends DataStore implements 
Aggregate {
     }
 
     @Override
-    public Metadata getMetadata() throws DataStoreException {
-        throw new UnsupportedOperationException("Not supported yet.");
+    public synchronized Metadata getMetadata() throws DataStoreException {
+        if (metadata == null) {
+            final MetadataBuilder builder = new MetadataBuilder();
+            builder.addIdentifier(Names.createLocalName(null, null, 
IOUtilities.filenameWithoutExtension(gimiPath.getFileName().toString())), 
MetadataBuilder.Scope.ALL);
+            metadata = builder.buildAndFreeze();
+        }
+        return metadata;
     }
 
     @Override
@@ -154,6 +163,10 @@ public final class GimiStore extends DataStore implements 
Aggregate {
                         final ResourcePyramid pyramid = new 
ResourcePyramid(this, img);
                         components.add(pyramid);
                         componentIndex.put(pyramid.group.groupId, pyramid);
+
+                        //force initialize now, pyramids may amend existing 
grids
+                        pyramid.getGridGeometry();
+
                     }
                 }
             }
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiTileMatrix.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiTileMatrix.java
index 3ba53d813c..c7e09cf8fd 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiTileMatrix.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/GimiTileMatrix.java
@@ -40,9 +40,9 @@ final class GimiTileMatrix implements TileMatrix {
     private final ResourceGrid grid;
     private final GenericName identifier;
     private final GridGeometry tilingScheme;
-    private final int[] tileSize;
+    private final long[] tileSize;
 
-    public GimiTileMatrix(ResourceGrid grid, GridGeometry tilingScheme, int[] 
tileSize) {
+    public GimiTileMatrix(ResourceGrid grid, GridGeometry tilingScheme, long[] 
tileSize) {
         this.grid = grid;
         this.identifier = Names.createLocalName(null, null, 
grid.getIdentifier().get().tip().toString() + "_tm");
         this.tilingScheme = tilingScheme;
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourceGrid.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourceGrid.java
index 7853028cb5..e617a76823 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourceGrid.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourceGrid.java
@@ -33,11 +33,14 @@ import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.base.StoreResource;
 import org.apache.sis.storage.gimi.internal.MatrixGridRessource;
 import org.apache.sis.storage.gimi.isobmff.Box;
+import org.apache.sis.storage.gimi.isobmff.gimi.ModelTransformationProperty;
+import org.apache.sis.storage.gimi.isobmff.gimi.WellKnownText2Property;
 import org.apache.sis.storage.gimi.isobmff.iso23008_12.ImageSpatialExtents;
 import org.apache.sis.storage.tiling.TileMatrix;
 import org.apache.sis.storage.tiling.TileMatrixSet;
 import org.apache.sis.storage.tiling.TiledResource;
 import org.apache.sis.util.iso.Names;
+import org.opengis.util.FactoryException;
 
 
 /**
@@ -94,6 +97,8 @@ final class ResourceGrid extends MatrixGridRessource 
implements TiledResource, S
     }
 
     private synchronized void initialize() throws DataStoreException {
+        if (tileMatrix != null) return;
+
         final Resource first = 
item.store.getComponent(item.references.get(0).toItemId[0]);
         if (first instanceof GridCoverageResource) {
             this.first = (GridCoverageResource) first;
@@ -101,23 +106,54 @@ final class ResourceGrid extends MatrixGridRessource 
implements TiledResource, S
             throw new DataStoreException("Expecting a GridCoverageResource 
tile but was a " + first.getClass().getName());
         }
         final GridGeometry firstTileGridGeom = this.first.getGridGeometry();
-        this.crs = firstTileGridGeom.getCoordinateReferenceSystem();
+
         final GridExtent tileExtent = firstTileGridGeom.getExtent();
-        final int[] tileSize = new 
int[]{Math.toIntExact(tileExtent.getSize(0)), 
Math.toIntExact(tileExtent.getSize(1))};
-        final MathTransform matrixGridToCrs = 
firstTileGridGeom.derive().subgrid(null, 
tileSize).build().getGridToCRS(PixelInCell.CELL_CENTER);
-        for (Box b : item.properties) {
-            if (b instanceof ImageSpatialExtents) {
-                final ImageSpatialExtents ext = (ImageSpatialExtents) b;
-                final long matrixWidth = ext.imageWidth / 
tileExtent.getSize(0);
-                final long matrixHeight = ext.imageHeight / 
tileExtent.getSize(1);
-                //create tile matrix
-                final GridGeometry tilingScheme = new GridGeometry(new 
GridExtent(matrixWidth, matrixHeight), PixelInCell.CELL_CENTER, 
matrixGridToCrs, crs);
-                tileMatrix = new GimiTileMatrix(this, tilingScheme, tileSize);
-                //create tile matrix set
-                tileMatrixSet = new 
GimiTileMatrixSet(Names.createLocalName(null, null, identifier.tip().toString() 
+ "_tms"), crs);
-                tileMatrixSet.matrices.insertByScale(tileMatrix);
+        final long[] tileSize = new long[]{tileExtent.getSize(0), 
tileExtent.getSize(1)};
+
+        ImageSpatialExtents imageExts = null;
+        ModelTransformationProperty modelTrs = null;
+        WellKnownText2Property modelWkt = null;
+
+        for (Box box : item.properties) {
+            if (box instanceof ImageSpatialExtents) {
+                imageExts = (ImageSpatialExtents) box;
+            } else if (box instanceof ModelTransformationProperty) {
+                modelTrs = (ModelTransformationProperty) box;
+            } else if (box instanceof WellKnownText2Property) {
+                modelWkt = (WellKnownText2Property) box;
+            }
+        }
+
+        if (modelWkt != null) {
+            try {
+                this.crs = modelWkt.toCRS();
+            } catch (FactoryException ex) {
+                throw new DataStoreException(ex.getMessage(), ex);
             }
+        } else {
+            this.crs = null;
+        }
+
+        MathTransform matrixGridToCrs;
+        if (modelTrs != null) {
+            matrixGridToCrs = modelTrs.toMathTransform();
+        } else {
+            matrixGridToCrs = null;
         }
+
+        //create tile matrix
+        GridGeometry tilingScheme = new GridGeometry(new 
GridExtent(imageExts.imageWidth, imageExts.imageHeight), 
PixelInCell.CELL_CENTER, matrixGridToCrs, crs);
+        tilingScheme = tilingScheme.derive().subgrid(null, tileSize).build(); 
//remove tile size from scheme
+        tileMatrix = new GimiTileMatrix(this, tilingScheme, tileSize);
+        //create tile matrix set
+        tileMatrixSet = new GimiTileMatrixSet(Names.createLocalName(null, 
null, identifier.tip().toString() + "_tms"), crs);
+        tileMatrixSet.matrices.insertByScale(tileMatrix);
+    }
+
+    void amendTilingScheme(GridGeometry tilingScheme, long[] tileSize) {
+        tileMatrix = new GimiTileMatrix(this, tilingScheme, tileSize);
+        tileMatrixSet = new GimiTileMatrixSet(Names.createLocalName(null, 
null, identifier.tip().toString() + "_tms"), crs);
+        tileMatrixSet.matrices.insertByScale(tileMatrix);
     }
 
     @Override
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourceImageUncompressed.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourceImageUncompressed.java
index e1d66e52fb..bfd8883b51 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourceImageUncompressed.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourceImageUncompressed.java
@@ -19,6 +19,7 @@ package org.apache.sis.storage.gimi;
 import java.awt.image.BufferedImage;
 import java.awt.image.WritableRaster;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -30,7 +31,6 @@ import org.apache.sis.coverage.grid.GridCoverageBuilder;
 import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.PixelInCell;
-import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.referencing.privy.AffineTransform2D;
 import org.apache.sis.storage.AbstractGridCoverageResource;
@@ -44,7 +44,9 @@ import 
org.apache.sis.storage.gimi.isobmff.gimi.WellKnownText2Property;
 import org.apache.sis.storage.gimi.isobmff.iso23001_17.ComponentDefinition;
 import org.apache.sis.storage.gimi.isobmff.iso23001_17.UncompressedFrameConfig;
 import org.apache.sis.storage.gimi.isobmff.iso23008_12.ImageSpatialExtents;
+import 
org.apache.sis.storage.gimi.isobmff.iso23008_12.PixelInformationProperty;
 import org.apache.sis.util.iso.Names;
+import org.opengis.referencing.operation.MathTransform;
 
 
 /**
@@ -58,8 +60,19 @@ class ResourceImageUncompressed extends 
AbstractGridCoverageResource implements
     protected final GimiStore store;
     protected final Item item;
     private final GenericName identifier;
-    protected ComponentDefinition compDef;
     protected ImageSpatialExtents imageExt;
+    /**
+     * Can be null
+     */
+    protected PixelInformationProperty pixelDef;
+    /**
+    /**
+     * Can be null
+     */
+    protected ComponentDefinition compDef;
+    /**
+     * Can be null
+     */
     protected UncompressedFrameConfig frameConf;
     /**
      * Can be null
@@ -74,6 +87,12 @@ class ResourceImageUncompressed extends 
AbstractGridCoverageResource implements
      */
     protected WellKnownText2Property modelWkt;
 
+
+    //computed values for decoding
+    private final int tileWidth;
+    private final int tileHeight;
+    private final int tileByteArrayLength;
+
     public ResourceImageUncompressed(GimiStore store, Item item) throws 
DataStoreException {
         super(store);
         this.store = store;
@@ -91,6 +110,8 @@ class ResourceImageUncompressed extends 
AbstractGridCoverageResource implements
                 modelTp = (ModelTiePointProperty) box;
             } else if (box instanceof WellKnownText2Property) {
                 modelWkt = (WellKnownText2Property) box;
+            } else if (box instanceof PixelInformationProperty) {
+                pixelDef = (PixelInformationProperty) box;
             }
         }
         if (item.entry.itemName == null || item.entry.itemName.isBlank()) {
@@ -98,6 +119,25 @@ class ResourceImageUncompressed extends 
AbstractGridCoverageResource implements
         } else {
             this.identifier = Names.createLocalName(null, null, 
item.entry.itemName);
         }
+
+        //pre-computed values
+        if (frameConf == null) {
+            //use a dumy one
+            frameConf = new UncompressedFrameConfig();
+            frameConf.numTileColsMinusOne = 0;
+            frameConf.numTileRowsMinusOne = 0;
+        }
+        tileWidth = imageExt.imageWidth / (frameConf.numTileColsMinusOne+1);
+        tileHeight = imageExt.imageHeight / (frameConf.numTileRowsMinusOne+1);
+
+        //TODO handle all kind of component length and subsampling
+        if (pixelDef != null) {
+            tileByteArrayLength = tileWidth * tileHeight * 
pixelDef.bitsPerChannel.length;
+        } else if (compDef != null) {
+            tileByteArrayLength = tileWidth * tileHeight * 
compDef.componentType.length;
+        } else {
+            throw new DataStoreException("Failed to compute tile sizein 
bytes");
+        }
     }
 
     @Override
@@ -114,21 +154,18 @@ class ResourceImageUncompressed extends 
AbstractGridCoverageResource implements
     public GridGeometry getGridGeometry() throws DataStoreException {
         try {
             final GridExtent extent = new GridExtent(imageExt.imageWidth, 
imageExt.imageHeight);
-            final AffineTransform2D gridToCrs;
+            final MathTransform gridToCrs;
             if (modelTrs == null) {
                 gridToCrs = new AffineTransform2D(1, 0, 0, 1, 0, 0);
             } else {
-                gridToCrs = new AffineTransform2D(modelTrs.transform[0], 
modelTrs.transform[3], modelTrs.transform[1], modelTrs.transform[4], 
modelTrs.transform[2], modelTrs.transform[5]);
+                gridToCrs = modelTrs.toMathTransform();
             }
             final CoordinateReferenceSystem crs;
             if (modelWkt == null) {
                 //TODO we should have an Image CRS
-                crs = CommonCRS.defaultGeographic();
+                crs = CommonCRS.Engineering.GRID.crs();
             } else {
-                String wkt = modelWkt.wkt2;
-                //TODO remove this hack when SIS support BASEGEOGCRS
-                wkt = wkt.replace("BASEGEOGCRS", "BASEGEODCRS");
-                crs = CRS.fromWKT(wkt);
+                crs = modelWkt.toCRS();
             }
             return new GridGeometry(extent, PixelInCell.CELL_CENTER, 
gridToCrs, crs);
         } catch (FactoryException ex) {
@@ -139,20 +176,28 @@ class ResourceImageUncompressed extends 
AbstractGridCoverageResource implements
     @Override
     public List<SampleDimension> getSampleDimensions() throws 
DataStoreException {
         final List<SampleDimension> sd = new ArrayList<>();
-        for (int i = 0; i < compDef.componentType.length; i++) {
-            final SampleDimension.Builder sdb = new SampleDimension.Builder();
-            switch (compDef.componentType[i]) {
-                case 4:
-                    sdb.setName("Red");
-                    break;
-                case 5:
-                    sdb.setName("Green");
-                    break;
-                case 6:
-                    sdb.setName("Blue");
-                    break;
+        if (compDef != null) {
+            for (int i = 0; i < compDef.componentType.length; i++) {
+                final SampleDimension.Builder sdb = new 
SampleDimension.Builder();
+                switch (compDef.componentType[i]) {
+                    case 4:
+                        sdb.setName("Red");
+                        break;
+                    case 5:
+                        sdb.setName("Green");
+                        break;
+                    case 6:
+                        sdb.setName("Blue");
+                        break;
+                }
+                sd.add(sdb.build());
+            }
+        } else if (pixelDef != null) {
+            for (int i = 0; i < pixelDef.bitsPerChannel.length; i++) {
+                final SampleDimension.Builder sdb = new 
SampleDimension.Builder();
+                sdb.setName(""+i);
+                sd.add(sdb.build());
             }
-            sd.add(sdb.build());
         }
         return sd;
     }
@@ -160,15 +205,23 @@ class ResourceImageUncompressed extends 
AbstractGridCoverageResource implements
     @Override
     public GridCoverage read(GridGeometry gg, int... ints) throws 
DataStoreException {
         final byte[] data = item.getData();
-        final BufferedImage img = new BufferedImage(2048, 1024, 
BufferedImage.TYPE_3BYTE_BGR);
-        final WritableRaster raster = img.getRaster();
-        for (int y = 0; y < 1024; y++) {
-            for (int x = 0; x < 2048; x++) {
-                int offset = y * 2048 + x;
-                raster.setSample(x, y, 0, data[offset * 3] & 0xFF);
-                raster.setSample(x, y, 1, data[offset * 3 + 1] & 0xFF);
-                raster.setSample(x, y, 2, data[offset * 3 + 2] & 0xFF);
+
+        final BufferedImage img;
+        if ( (compDef != null && Arrays.equals(compDef.componentType, new 
int[]{4,5,6}))
+           || (pixelDef != null && pixelDef.bitsPerChannel.length == 3)
+           ) {
+            // RGB case
+            int width = imageExt.imageWidth;
+            int height = imageExt.imageHeight;
+            img = new BufferedImage(width, height, 
BufferedImage.TYPE_3BYTE_BGR);
+            final WritableRaster raster = img.getRaster();
+            for (int y = 0; y <= frameConf.numTileRowsMinusOne; y++) {
+                for (int x = 0; x <= frameConf.numTileColsMinusOne; x++) {
+                    readTile(data, x, y, raster, x*tileWidth, y*tileHeight);
+                }
             }
+        } else {
+            throw new DataStoreException("Unsupported component model");
         }
         final GridGeometry gridGeometry = getGridGeometry();
         GridCoverageBuilder gcb = new GridCoverageBuilder();
@@ -179,4 +232,25 @@ class ResourceImageUncompressed extends 
AbstractGridCoverageResource implements
         return gcb.build();
     }
 
+    /**
+     *
+     * @param data
+     * @param tileX starting from image left
+     * @param tileY starting from image top
+     */
+    private void readTile(byte[] data, int tileX, int tileY, WritableRaster 
raster, int offsetX, int offsetY) {
+        final int tileOffset = (tileX + tileY * 
(frameConf.numTileColsMinusOne+1)) * tileByteArrayLength;
+        for (int y = 0; y < tileHeight; y++) {
+            for (int x = 0; x < tileWidth; x++) {
+                final int offset = y * tileWidth + x;
+                final int finalX = offsetX + x;
+                final int finalY = offsetY + y;
+                raster.setSample(finalX, finalY, 0, data[tileOffset + offset * 
3] & 0xFF);
+                raster.setSample(finalX, finalY, 1, data[tileOffset + offset * 
3 + 1] & 0xFF);
+                raster.setSample(finalX, finalY, 2, data[tileOffset + offset * 
3 + 2] & 0xFF);
+            }
+        }
+    }
+
+
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourcePyramid.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourcePyramid.java
index 01529ac58c..ffef8b7d67 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourcePyramid.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/ResourcePyramid.java
@@ -17,7 +17,9 @@
 package org.apache.sis.storage.gimi;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -27,6 +29,10 @@ import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.coverage.grid.PixelInCell;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.referencing.privy.AffineTransform2D;
 import org.apache.sis.storage.AbstractGridCoverageResource;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
@@ -41,6 +47,8 @@ import org.apache.sis.storage.tiling.TileMatrix;
 import org.apache.sis.storage.tiling.TileMatrixSet;
 import org.apache.sis.storage.tiling.TiledResource;
 import org.apache.sis.util.iso.Names;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
 
 
 /**
@@ -74,8 +82,11 @@ final class ResourcePyramid extends 
AbstractGridCoverageResource implements Tile
         if (tileMatrixSet != null) {
             return;
         }
-        final GridCoverageResource first = (GridCoverageResource) 
store.getComponent(group.entitiesId[0]);
-        tileMatrixSet = new GimiTileMatrixSet(Names.createLocalName(null, 
null, getIdentifier().get().tip().toString() + "_tms"), 
first.getGridGeometry().getCoordinateReferenceSystem());
+
+        /*
+         * Find all resources of the pyramid
+         */
+        final List<ResourceGrid> candidates = new ArrayList<>();
         for (int i = 0; i < group.matrices.length; i++) {
             Resource res = store.getComponent(group.entitiesId[i]);
             if (res instanceof GridCoverageResource && !(res instanceof 
TiledResource)) {
@@ -97,13 +108,54 @@ final class ResourcePyramid extends 
AbstractGridCoverageResource implements Tile
             }
             if (res instanceof ResourceGrid) {
                 final ResourceGrid tr = (ResourceGrid) res;
-                final TileMatrix tm = tr.getTileMatrix();
-                grids.put(tm.getIdentifier(), tr);
-                tileMatrixSet.matrices.insertByScale(tm);
+                candidates.add(tr);
             } else {
                 throw new DataStoreException("A resource in the pyramid in not 
a coverage, itemId : " + group.entitiesId[i]);
             }
         }
+
+        /*
+         * Sort by scale, lowest resolution at index 0.
+         * Only the most accurate matrix seems to contains georeferencing 
informations
+         */
+        Collections.sort(candidates, (ResourceGrid o1, ResourceGrid o2) -> {
+            return Long.compare(
+                    
o2.getTileMatrix().getTilingScheme().getExtent().getSize(0),
+                    
o1.getTileMatrix().getTilingScheme().getExtent().getSize(0));
+        });
+
+        /*
+         * Define each matrix CRS and transform based on the lowest one.
+         * each level is 2x resolution with the same tope left corner.
+         */
+        final TileMatrix referenceMatrix = candidates.get(0).getTileMatrix();
+        final GridGeometry reference = referenceMatrix.getTilingScheme();
+        final MathTransform referenceTransform = 
reference.isDefined(GridGeometry.GRID_TO_CRS) ? 
reference.getGridToCRS(PixelInCell.CELL_CENTER) : new AffineTransform2D(1, 0, 
0, 1, 0, 0);
+        final CoordinateReferenceSystem crs = 
reference.isDefined(GridGeometry.CRS) ? 
referenceMatrix.getTilingScheme().getCoordinateReferenceSystem() : 
CommonCRS.Engineering.GRID.crs();
+
+        tileMatrixSet = new GimiTileMatrixSet(Names.createLocalName(null, 
null, getIdentifier().get().tip().toString() + "_tms"), crs);
+        grids.put(referenceMatrix.getIdentifier(), candidates.get(0));
+        tileMatrixSet.matrices.insertByScale(referenceMatrix);
+        final long[] tileSize = new long[]{group.tileSizeX, group.tileSizeY};
+
+        for (int i = 1, n = candidates.size(); i < n; i++) {
+            final ResourceGrid resource = candidates.get(i);
+
+            final double scale = Math.pow(2, i);
+            final MathTransform scaleTrs = new AffineTransform2D(scale, 0, 0, 
scale, 0, 0);
+
+            final GridGeometry fixed = new GridGeometry(
+                    resource.getTileMatrix().getTilingScheme().getExtent(),
+                    PixelInCell.CELL_CENTER,
+                    MathTransforms.concatenate(scaleTrs, referenceTransform),
+                    reference.getCoordinateReferenceSystem());
+
+            resource.amendTilingScheme(fixed, tileSize);
+            final TileMatrix matrix = resource.getTileMatrix();
+
+            grids.put(matrix.getIdentifier(), resource);
+            tileMatrixSet.matrices.insertByScale(matrix);
+        }
     }
 
     @Override
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/internal/ScaleSortedMap.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/internal/ScaleSortedMap.java
index e1892d9d24..cb02157a8d 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/internal/ScaleSortedMap.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/internal/ScaleSortedMap.java
@@ -42,7 +42,7 @@ public final class ScaleSortedMap<T extends TileMatrix> 
extends TreeMap<GenericN
         ArgumentChecks.ensureNonNull("identifier", id);
         final ScaleComparator comparator = (ScaleComparator) comparator();
         if (comparator.matricesByScale.containsKey(id)) {
-            throw new IllegalArgumentException("Key " + id + "already exist");
+            throw new IllegalArgumentException("Key already exist : " + id);
         }
         final double resolution = tileMatrix.getResolution()[0];
         comparator.matricesByScale.put(id, resolution);
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/gimi/ModelTransformationProperty.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/gimi/ModelTransformationProperty.java
index c6fc069376..d3f422c45a 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/gimi/ModelTransformationProperty.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/gimi/ModelTransformationProperty.java
@@ -17,8 +17,10 @@
 package org.apache.sis.storage.gimi.isobmff.gimi;
 
 import java.io.IOException;
+import org.apache.sis.referencing.privy.AffineTransform2D;
 import org.apache.sis.storage.gimi.isobmff.ISOBMFFReader;
 import org.apache.sis.storage.gimi.isobmff.iso14496_12.ItemFullProperty;
+import org.opengis.referencing.operation.MathTransform;
 
 
 /**
@@ -42,5 +44,12 @@ public final class ModelTransformationProperty extends 
ItemFullProperty {
         }
     }
 
+    public MathTransform toMathTransform() {
+        if (transform.length == 6) {
+            return new AffineTransform2D(transform[0], transform[3], 
transform[1], transform[4], transform[2], transform[5]);
+        } else {
+            throw new UnsupportedOperationException("3D transform not 
supported yet");
+        }
+    }
 
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/gimi/WellKnownText2Property.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/gimi/WellKnownText2Property.java
index e2c968b29d..2b5560e9fd 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/gimi/WellKnownText2Property.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/gimi/WellKnownText2Property.java
@@ -17,8 +17,11 @@
 package org.apache.sis.storage.gimi.isobmff.gimi;
 
 import java.io.IOException;
+import org.apache.sis.referencing.CRS;
 import org.apache.sis.storage.gimi.isobmff.ISOBMFFReader;
 import org.apache.sis.storage.gimi.isobmff.iso14496_12.ItemFullProperty;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.util.FactoryException;
 
 
 /**
@@ -36,4 +39,10 @@ public final class WellKnownText2Property extends 
ItemFullProperty {
         wkt2 = reader.readUtf8String();
     }
 
+    public CoordinateReferenceSystem toCRS() throws FactoryException {
+        //TODO remove this hack when SIS support BASEGEOGCRS
+        String wkt = this.wkt2.replace("BASEGEOGCRS", "BASEGEODCRS");
+        return CRS.fromWKT(wkt);
+    }
+
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/iso23001_17/TAIClockInfo.java
 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/iso23001_17/TAIClockInfo.java
index ac2254e2f1..0458e6bbce 100644
--- 
a/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/iso23001_17/TAIClockInfo.java
+++ 
b/incubator/src/org.apache.sis.storage.gimi/main/org/apache/sis/storage/gimi/isobmff/iso23001_17/TAIClockInfo.java
@@ -30,7 +30,7 @@ public final class TAIClockInfo extends FullBox {
 
     public static final String FCC = "taic";
 
-    public long timeUncertainty;
+    public int timeUncertainty;
     public int clockResolution;
     public int clockDriftRate;
     public int unknown;
@@ -38,7 +38,7 @@ public final class TAIClockInfo extends FullBox {
 
     @Override
     protected void readProperties(ISOBMFFReader reader) throws IOException {
-        timeUncertainty = reader.channel.readLong();
+        timeUncertainty = reader.channel.readInt();
         clockResolution = reader.channel.readInt();
         clockDriftRate = reader.channel.readInt();
         unknown = reader.channel.readInt();

Reply via email to