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 89c8fedc900d16ad9db58b314371276f9d435120
Author: jsorel <[email protected]>
AuthorDate: Wed Oct 28 14:53:59 2026 +0100

    feat(DGGS): add ReducedCodedResource, fix errors in cell indexing
---
 .../dggs/DiscreteGlobalGridCoverageProcessor.java  |   2 +-
 .../rs/internal/shared/ArrayCodedCoverage.java     |   7 +-
 .../storage/rs/internal/shared/CodeTransforms.java |   5 +-
 .../rs/internal/shared/ReducedCodedResource.java   | 227 +++++++++++++++++++++
 .../rs/internal/shared/ResampledCodedCoverage.java |   7 +-
 .../internal/shared/ReducedCodedResourceTest.java  | 197 ++++++++++++++++++
 6 files changed, 440 insertions(+), 5 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/dggs/DiscreteGlobalGridCoverageProcessor.java
 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/dggs/DiscreteGlobalGridCoverageProcessor.java
index b12f0eca86..53376a06af 100644
--- 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/dggs/DiscreteGlobalGridCoverageProcessor.java
+++ 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/dggs/DiscreteGlobalGridCoverageProcessor.java
@@ -643,7 +643,7 @@ public final class DiscreteGlobalGridCoverageProcessor {
                 //remove any extra slice information
                 coverage = ad.getSource();
             }
-
+            
             final DiscreteGlobalGridReferenceSystem dggrs = 
dggGrid.getReferenceSystem();
             final DiscreteGlobalGridHierarchy dggh = 
dggrs.getGridSystem().getHierarchy();
             final List<SampleDimension> sampleDimensions = 
coverage.getSampleDimensions();
diff --git 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ArrayCodedCoverage.java
 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ArrayCodedCoverage.java
index cbf3a38153..c95f76f674 100644
--- 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ArrayCodedCoverage.java
+++ 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ArrayCodedCoverage.java
@@ -134,10 +134,15 @@ public final class ArrayCodedCoverage extends 
AbstractCodedCoverage{
             }
         }
 
+        /**
+         * Returns the linear position of given grid position, or -1 if 
outside the extent.
+         */
         private long toLinearPosition(int[] pos) {
             long p = 0;
             for (int i = 0; i < dimension; i++) {
-                p += pos[i] * dimStep[i];
+                final long k = pos[i] - dimOffsets[i];
+                if (k < 0 || k >= dimSize[i]) return -1;
+                p += k * dimStep[i];
             }
             return p;
         }
diff --git 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/CodeTransforms.java
 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/CodeTransforms.java
index 8532c6b383..54cd738511 100644
--- 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/CodeTransforms.java
+++ 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/CodeTransforms.java
@@ -64,7 +64,7 @@ public final class CodeTransforms {
         if (trss.length == 1) return trss[0];
         SubTransform rgt = new Compound((SubTransform)trss[0], 
(SubTransform)trss[1]);
         for (int i = 2; i < trss.length; i++) {
-            rgt = new Compound(rgt, (SubTransform) trss[2]);
+            rgt = new Compound(rgt, (SubTransform) trss[i]);
         }
         return rgt;
     }
@@ -221,7 +221,8 @@ public final class CodeTransforms {
             final double[] gp = new double[dimension];
             for(int i = 0; i < dimension; i++) gp[i] = (double) 
location[offset+i];
             crsToGrid.transform(gp, 0, gp, 0, 1);
-            for(int i = 0; i < dimension; i++) gridPosition[offset+i] = (int) 
gp[i];
+            //transform is cell center based, round to the nearest cell
+            for(int i = 0; i < dimension; i++) gridPosition[offset+i] = (int) 
Math.round(gp[i]);
         }
 
         @Override
diff --git 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ReducedCodedResource.java
 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ReducedCodedResource.java
new file mode 100644
index 0000000000..6887418fbb
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ReducedCodedResource.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.rs.internal.shared;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import org.opengis.referencing.ReferenceSystem;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.util.FactoryException;
+import org.opengis.util.GenericName;
+import org.apache.sis.coverage.SampleDimension;
+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.dggs.DiscreteGlobalGridReferenceSystem;
+import org.apache.sis.referencing.rs.ReferenceSystems;
+import org.apache.sis.storage.AbstractResource;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.rs.CodeIterator;
+import org.apache.sis.storage.rs.CodeTransform;
+import org.apache.sis.storage.rs.CodedCoverage;
+import org.apache.sis.storage.rs.CodedGeometry;
+import org.apache.sis.storage.rs.CodedResource;
+import org.apache.sis.storage.rs.WritableCodeIterator;
+
+
+/**
+ * View of a coded resource with one or more components of its reference 
system hidden.
+ * Each hidden component is fixed at a given grid index; the resulting resource
+ * only exposes the remaining components.
+ *
+ * <p>Hidden components must be one-dimensional (typically vertical or 
temporal components).
+ * The horizontal Discrete Global Grid component cannot be hidden.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public final class ReducedCodedResource extends AbstractResource implements 
CodedResource {
+
+    private final GenericName name;
+    private final CodedResource resource;
+    /**
+     * Single components of the source resource reference system.
+     */
+    private final List<ReferenceSystem> components;
+    /**
+     * For each source component, the source geometry slice if the component 
is kept, null otherwise.
+     */
+    private final CodedGeometry[] keptSlices;
+    /**
+     * For each source component, a single cell geometry at the fixed index if 
the component is hidden, null otherwise.
+     */
+    private final CodedGeometry[] hiddenSlices;
+    private final CodedGeometry geometry;
+
+    /**
+     * Creates a new reduced view.
+     *
+     * @param name      name of the reduced resource.
+     * @param resource  the resource to reduce.
+     * @param hidden    map of source component index to the grid index to use 
in this component.
+     *                  Component indices are those of {@code 
ReferenceSystems.getSingleComponents(rs, true)}.
+     * @throws DataStoreException if the resource geometry cannot be read.
+     * @throws IllegalArgumentException if a component index or grid index is 
invalid.
+     */
+    public ReducedCodedResource(GenericName name, CodedResource resource, 
Map<Integer,Integer> hidden) throws DataStoreException {
+        super(null);
+        this.name = name;
+        this.resource = resource;
+
+        final CodedGeometry resourceGeometry = resource.getGridGeometry();
+        components = 
ReferenceSystems.getSingleComponents(resourceGeometry.getReferenceSystem(), 
true);
+        keptSlices = new CodedGeometry[components.size()];
+        hiddenSlices = new CodedGeometry[components.size()];
+
+        for (Map.Entry<Integer,Integer> entry : hidden.entrySet()) {
+            final int idx = entry.getKey();
+            final int index = entry.getValue();
+            if (idx < 0 || idx >= components.size()) {
+                throw new IllegalArgumentException("Component " + idx + " does 
not exist, reference system has " + components.size() + " components");
+            }
+            final ReferenceSystem component = components.get(idx);
+            if (component instanceof DiscreteGlobalGridReferenceSystem) {
+                throw new IllegalArgumentException("Component " + idx + " is a 
Discrete Global Grid, it can not be hidden");
+            }
+            if (ReferenceSystems.getDimension(component) != 1) {
+                throw new IllegalArgumentException("Component " + idx + " is 
not one-dimensional, it can not be hidden");
+            }
+            final CodedGeometry slice = 
resourceGeometry.slice(component).get();
+            if (slice.isDefined(CodedGeometry.EXTENT) && 
!slice.getExtent().contains(index)) {
+                throw new IllegalArgumentException("Index " + index + " is 
outside of component " + idx + " extent " + slice.getExtent());
+            }
+            final GridExtent cell = new GridExtent(null, new long[] {index}, 
new long[] {index}, true);
+            CodeTransform gridToRS = slice.getGridToRS();
+            if (gridToRS instanceof CodeTransforms.Grid g) {
+                final GridGeometry grid = g.getGrid();
+                gridToRS = CodeTransforms.toTransform(new GridGeometry(cell, 
PixelInCell.CELL_CENTER,
+                        grid.getGridToCRS(PixelInCell.CELL_CENTER), 
grid.getCoordinateReferenceSystem()));
+            }
+            hiddenSlices[idx] = new CodedGeometry(component, cell, gridToRS, 
null);
+        }
+
+        final List<CodedGeometry> kept = new ArrayList<>();
+        for (int i = 0; i < keptSlices.length; i++) {
+            if (hiddenSlices[i] == null) {
+                keptSlices[i] = 
resourceGeometry.slice(components.get(i)).get();
+                kept.add(keptSlices[i]);
+            }
+        }
+        if (kept.isEmpty()) {
+            throw new IllegalArgumentException("At least one component must be 
preserved");
+        }
+        geometry = CodedGeometry.compound(kept.toArray(CodedGeometry[]::new));
+    }
+
+    /**
+     * Returns the resource being reduced.
+     *
+     * @return source resource
+     */
+    public CodedResource getSource() {
+        return resource;
+    }
+
+    @Override
+    public Optional<GenericName> getIdentifier() throws DataStoreException {
+        return Optional.ofNullable(name);
+    }
+
+    @Override
+    public List<SampleDimension> getSampleDimensions() throws 
DataStoreException {
+        return resource.getSampleDimensions();
+    }
+
+    @Override
+    public CodedGeometry getGridGeometry() throws DataStoreException {
+        return geometry;
+    }
+
+    @Override
+    public CodedCoverage read(CodedGeometry query, int... range) throws 
DataStoreException {
+        //rebuild a query on all source components, inserting the fixed slices
+        final CodedGeometry[] parts = new CodedGeometry[components.size()];
+        for (int i = 0; i < parts.length; i++) {
+            parts[i] = (hiddenSlices[i] != null) ? hiddenSlices[i] : 
query.slice(components.get(i)).orElse(keptSlices[i]);
+        }
+        final CodedCoverage baseCoverage = 
resource.read(CodedGeometry.compound(parts), range);
+
+        //map reduced grid dimensions to source grid dimensions
+        final CodedGeometry baseGeometry = baseCoverage.getGeometry();
+        final int[] sourcePosition = new 
int[baseGeometry.getExtent().getDimension()];
+        int[] targetToSource = new int[sourcePosition.length];
+        final List<CodedGeometry> kept = new ArrayList<>();
+        int sourceDim = 0;
+        int targetDim = 0;
+        try {
+            for (ReferenceSystem component : 
ReferenceSystems.getSingleComponents(baseGeometry.getReferenceSystem(), true)) {
+                final CodedGeometry slice = 
baseGeometry.slice(component).get();
+                final int idx = components.indexOf(component);
+                if (idx >= 0 && hiddenSlices[idx] != null) {
+                    sourcePosition[sourceDim++] = locate(slice, 
hiddenSlices[idx]);
+                } else {
+                    kept.add(slice);
+                    for (int i = 0, n = 
ReferenceSystems.getDimension(component); i < n; i++) {
+                        targetToSource[targetDim++] = sourceDim++;
+                    }
+                }
+            }
+        } catch (TransformException ex) {
+            throw new DataStoreException(ex.getMessage(), ex);
+        }
+        targetToSource = Arrays.copyOf(targetToSource, targetDim);
+
+        final CodedCoverage subCoverage;
+        try {
+            subCoverage = new ArrayCodedCoverage(name, 
CodedGeometry.compound(kept.toArray(CodedGeometry[]::new)),
+                    
baseCoverage.getSampleDimensions().toArray(SampleDimension[]::new));
+        } catch (FactoryException ex) {
+            throw new DataStoreException(ex.getMessage(), ex);
+        }
+
+        final CodeIterator source = baseCoverage.createIterator();
+        try (WritableCodeIterator iterator = 
subCoverage.createWritableIterator()) {
+            double[] cell = null;
+            while (iterator.next()) {
+                final int[] position = iterator.getPosition();
+                for (int i = 0; i < targetToSource.length; i++) {
+                    sourcePosition[targetToSource[i]] = position[i];
+                }
+                source.moveTo(sourcePosition);
+                cell = source.getCell(cell);
+                iterator.setCell(cell);
+            }
+        }
+        return subCoverage;
+    }
+
+    /**
+     * Finds the grid index in the given coverage slice matching the hidden 
slice.
+     */
+    private static int locate(CodedGeometry slice, CodedGeometry hidden) 
throws TransformException {
+        final GridExtent extent = slice.getExtent();
+        if (extent.getSize(0) == 1) {
+            //source returned the requested single slice
+            return Math.toIntExact(extent.getLow(0));
+        }
+        //source returned more then the requested slice, search for it
+        final int index = Math.toIntExact(hidden.getExtent().getLow(0));
+        return slice.getGridToRS().toGrid(hidden.getGridToRS().toCode(new 
int[] {index}))[0];
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ResampledCodedCoverage.java
 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ResampledCodedCoverage.java
index e73c7ef2b1..06f31b78bb 100644
--- 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ResampledCodedCoverage.java
+++ 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/ResampledCodedCoverage.java
@@ -84,10 +84,15 @@ public final class ResampledCodedCoverage extends 
AbstractCodedCoverage {
             return base.getSampleDimensions().size();
         }
 
+        /**
+         * Returns the linear position of given grid position, or -1 if 
outside the extent.
+         */
         private long toLinearPosition(int[] pos) {
             long p = 0;
             for (int i = 0; i < dimension; i++) {
-                p += pos[i] * dimStep[i];
+                final long k = pos[i] - dimOffsets[i];
+                if (k < 0 || k >= dimSize[i]) return -1;
+                p += k * dimStep[i];
             }
             return p;
         }
diff --git 
a/incubator/src/org.apache.sis.referencing.dggs/test/org/apache/sis/storage/rs/internal/shared/ReducedCodedResourceTest.java
 
b/incubator/src/org.apache.sis.referencing.dggs/test/org/apache/sis/storage/rs/internal/shared/ReducedCodedResourceTest.java
new file mode 100644
index 0000000000..7d822f7d5a
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.referencing.dggs/test/org/apache/sis/storage/rs/internal/shared/ReducedCodedResourceTest.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.rs.internal.shared;
+
+import java.nio.ByteBuffer;
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import org.opengis.referencing.ReferenceSystem;
+import org.opengis.referencing.crs.VerticalCRS;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.util.GenericName;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.coverage.grid.BufferedGridCoverage;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.coverage.grid.GridOrientation;
+import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.image.DataType;
+import org.apache.sis.image.internal.shared.RasterFactory;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.dggs.DiscreteGlobalGridReferenceSystem;
+import org.apache.sis.referencing.dggs.Zone;
+import org.apache.sis.referencing.dggs.s2.S2Dggrs;
+import org.apache.sis.referencing.rs.ReferenceSystems;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.MemoryGridCoverageResource;
+import org.apache.sis.storage.dggs.DiscreteGlobalGridGeometry;
+import org.apache.sis.storage.rs.CodeIterator;
+import org.apache.sis.storage.rs.CodedCoverage;
+import org.apache.sis.storage.rs.CodedCoverages;
+import org.apache.sis.storage.rs.CodedGeometry;
+import org.apache.sis.storage.rs.CodedResource;
+import org.apache.sis.util.iso.Names;
+
+// Test dependencies
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.Test;
+
+
+/**
+ * Tests {@link ReducedCodedResource}.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public class ReducedCodedResourceTest {
+
+    private static final GenericName NAME = Names.createLocalName(null, null, 
"reduced");
+
+    private final DiscreteGlobalGridReferenceSystem dggrs = new S2Dggrs();
+
+    /**
+     * Hides the temporal component, the vertical component is preserved.
+     */
+    @Test
+    public void testHideTemporal() throws Exception {
+        final CodedResource source = createSource();
+        final ReducedCodedResource reduced = new ReducedCodedResource(NAME, 
source, Map.of(2, 1));
+
+        final CodedGeometry geometry = reduced.getGridGeometry();
+        final List<ReferenceSystem> components = 
ReferenceSystems.getSingleComponents(geometry.getReferenceSystem(), true);
+        assertEquals(2, components.size());
+        assertEquals(dggrs, components.get(0));
+        assertInstanceOf(VerticalCRS.class, components.get(1));
+
+        final List<Object> zoneIds = rootZoneIds();
+        final CodedGeometry query = CodedGeometry.compound(
+                DiscreteGlobalGridGeometry.unstructured(dggrs, zoneIds, null),
+                geometry.slice(components.get(1)).get());
+
+        final CodedCoverage coverage = reduced.read(query);
+        assertEquals(2, coverage.getGeometry().getExtent().getDimension());
+        assertEquals(components, 
ReferenceSystems.getSingleComponents(coverage.getGeometry().getReferenceSystem(),
 true));
+
+        // values at time index 1 are 4, 5, 6 for vertical index 0, 1, 2
+        final CodeIterator iterator = coverage.createIterator();
+        int count = 0;
+        while (iterator.next()) {
+            final int[] position = iterator.getPosition();
+            assertEquals(2, position.length);
+            assertEquals(4.0 + position[1], iterator.getSampleDouble(0), 0.0);
+            count++;
+        }
+        assertEquals(zoneIds.size() * 3, count);
+    }
+
+    /**
+     * Hides both vertical and temporal components, only the DGGRS component 
is preserved.
+     */
+    @Test
+    public void testHideVerticalAndTemporal() throws Exception {
+        final CodedResource source = createSource();
+        final ReducedCodedResource reduced = new ReducedCodedResource(NAME, 
source, Map.of(1, 0, 2, 2));
+
+        final CodedGeometry geometry = reduced.getGridGeometry();
+        assertEquals(dggrs, geometry.getReferenceSystem());
+
+        final List<Object> zoneIds = rootZoneIds();
+        final CodedCoverage coverage = 
reduced.read(DiscreteGlobalGridGeometry.unstructured(dggrs, zoneIds, null));
+        assertEquals(1, coverage.getGeometry().getExtent().getDimension());
+
+        // value at vertical index 0 and time index 2 is 7
+        final CodeIterator iterator = coverage.createIterator();
+        int count = 0;
+        while (iterator.next()) {
+            assertEquals(1, iterator.getPosition().length);
+            assertEquals(7.0, iterator.getSampleDouble(0), 0.0);
+            count++;
+        }
+        assertEquals(zoneIds.size(), count);
+    }
+
+    /**
+     * Tests invalid constructor arguments.
+     */
+    @Test
+    public void testInvalidArguments() throws Exception {
+        final CodedResource source = createSource();
+        // component does not exist
+        assertThrows(IllegalArgumentException.class, () -> new 
ReducedCodedResource(NAME, source, Map.of(3, 0)));
+        // DGGRS component can not be hidden
+        assertThrows(IllegalArgumentException.class, () -> new 
ReducedCodedResource(NAME, source, Map.of(0, 0)));
+        // index outside vertical extent
+        assertThrows(IllegalArgumentException.class, () -> new 
ReducedCodedResource(NAME, source, Map.of(1, 3)));
+    }
+
+    private List<Object> rootZoneIds() throws TransformException {
+        return 
dggrs.getGridSystem().getHierarchy().getGrids().get(1).getZones().map(Zone::getIdentifier).toList();
+    }
+
+    /**
+     * Creates a resource with DGGRS, vertical and temporal components.
+     * Cell values are {@code 1 + vertical index + 3 * temporal index}.
+     */
+    private CodedResource createSource() throws Exception {
+        return CodedCoverages.viewAsDggrs(Names.createLocalName(null, null, 
"coverage4d"), create4D(), dggrs);
+    }
+
+    private static GridCoverageResource create4D() throws Exception {
+        final GeneralEnvelope dataEnv = new GeneralEnvelope(CRS.compound(
+                CommonCRS.WGS84.normalizedGeographic(),
+                CommonCRS.Vertical.ELLIPSOIDAL.crs(),
+                CommonCRS.Temporal.JAVA.crs()
+        ));
+        dataEnv.setRange(0, -180, 180);
+        dataEnv.setRange(1, -90, 90);
+        dataEnv.setRange(2, 100, 300);
+        dataEnv.setRange(3,
+                Instant.parse("2000-06-10T10:00:00Z").toEpochMilli(),
+                Instant.parse("2000-06-10T12:00:00Z").toEpochMilli());
+        final GridGeometry dataGrid = new GridGeometry(
+                new GridExtent(null, new long[4], new long[] { 2, 2, 3, 3 }, 
false),
+                dataEnv,
+                GridOrientation.DISPLAY
+        );
+
+        final ByteBuffer dataBuffer = ByteBuffer.wrap(new byte[] {
+                1, 1, 1, 1,     // v0 t0
+                2, 2, 2, 2,     // v1 t0
+                3, 3, 3, 3,     // v2 t0
+                4, 4, 4, 4,     // v0 t1
+                5, 5, 5, 5,     // v1 t1
+                6, 6, 6, 6,     // v2 t1
+                7, 7, 7, 7,     // v0 t2
+                8, 8, 8, 8,     // v1 t2
+                9, 9, 9, 9      // v2 t2
+        });
+
+        final BufferedGridCoverage coverage = new BufferedGridCoverage(
+                dataGrid,
+                (List) List.of(new 
SampleDimension.Builder().setName("test").build()),
+                RasterFactory.wrap(DataType.BYTE, dataBuffer)
+        );
+        return new MemoryGridCoverageResource(null, null, coverage, null) {
+            @Override
+            public Optional<GenericName> getIdentifier() {
+                return Optional.of(Names.createLocalName(null, null, "test"));
+            }
+        };
+    }
+}

Reply via email to