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 0e4aa39e36ee487f814cf05be75cae5ee901ee42
Author: jsorel <[email protected]>
AuthorDate: Thu Oct 29 11:46:02 2026 +0100

    fix(DGGRS): fix CompoundCodedResource ignoring additional dimensions
---
 .../rs/internal/shared/CompoundCodedResource.java  | 185 +++++++++++----------
 1 file changed, 101 insertions(+), 84 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/CompoundCodedResource.java
 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/CompoundCodedResource.java
index e72371494c..bc7f993e00 100644
--- 
a/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/CompoundCodedResource.java
+++ 
b/incubator/src/org.apache.sis.referencing.dggs/main/org/apache/sis/storage/rs/internal/shared/CompoundCodedResource.java
@@ -18,18 +18,11 @@ package org.apache.sis.storage.rs.internal.shared;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.Set;
 import java.util.TreeSet;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.crs.VerticalCRS;
-import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.util.FactoryException;
 import org.opengis.util.GenericName;
@@ -38,15 +31,16 @@ 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.dggs.DiscreteGlobalGridReferenceSystem;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.rs.ReferenceSystems;
 import org.apache.sis.storage.AbstractResource;
 import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.dggs.DiscreteGlobalGridGeometry;
 import org.apache.sis.storage.rs.CodedCoverage;
 import org.apache.sis.storage.rs.CodedGeometry;
+import static org.apache.sis.storage.rs.CodedGeometry.compound;
 import org.apache.sis.storage.rs.CodedResource;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
 
 
 /**
@@ -108,98 +102,118 @@ public final class CompoundCodedResource extends 
AbstractResource implements Cod
 
     @Override
     public CodedCoverage read(CodedGeometry geometry, int... range) throws 
DataStoreException {
-        geometry = CodedResources.align(this, geometry);
+        /*
+         * Do not align the query on this resource geometry : it has no extent 
and no transform,
+         * aligning would only add undefined components, resulting in a 
geometry without extent.
+         * Each resource aligns the query on its own geometry.
+         */
         try {
-            final CodedCoverage[] resampled = new 
CodedCoverage[resources.size()];
-            for (int i = 0; i < resampled.length; i++) {
-                final CodedResource resource = resources.get(i);
-                CodedCoverage coverage = resources.get(i).read(geometry);
-                if (!geometry.equals(coverage.getGeometry())) {
-                    coverage = new 
ResampledCodedCoverage(resource.getIdentifier().get(), coverage, geometry);
+            final CodedCoverage[] coverages = new 
CodedCoverage[resources.size()];
+            final CodedGeometry[] geometries = new 
CodedGeometry[coverages.length + 1];
+            geometries[0] = geometry;
+            for (int i = 0; i < coverages.length; i++) {
+                coverages[i] = resources.get(i).read(geometry);
+                geometries[i+1] = coverages[i].getGeometry();
+            }
+            //sources may have added dimensions which are not in the query, 
aggregate them
+            final CodedGeometry target;
+            try {
+                target = aggregate(geometries);
+            } catch (IllegalArgumentException ex) {
+                throw new DataStoreException(ex.getMessage(), ex);
+            }
+            for (int i = 0; i < coverages.length; i++) {
+                if (!target.equals(coverages[i].getGeometry())) {
+                    coverages[i] = new 
ResampledCodedCoverage(resources.get(i).getIdentifier().get(), coverages[i], 
target);
                 }
-                resampled[i] = coverage;
             }
-            return new CompoundCodedCoverage(name, resampled, 
sampleDimensions);
-        } catch (FactoryException ex) {
+            return new CompoundCodedCoverage(name, coverages, 
sampleDimensions);
+        } catch (FactoryException | TransformException ex) {
             throw new DataStoreException(ex.getMessage(), ex);
         }
     }
 
-    private CodedGeometry compound(List<CodedGeometry> geometries) {
-
-        final Map<ReferenceSystem,CodedGeometry> map = new LinkedHashMap();
-
-        //cut each geometry in dimensions slice and try to merge them
-        for (CodedGeometry geom : geometries) {
-            final ReferenceSystem referenceSystem = geom.getReferenceSystem();
-            final List<ReferenceSystem> singleComponents = 
ReferenceSystems.getSingleComponents(referenceSystem, true);
-            sliceLoop:
-            for (ReferenceSystem rs : singleComponents) {
-                final CodedGeometry slice = geom.slice(rs).get();
-
-                //make a more accurate test to find a match
-                for (Entry<ReferenceSystem, CodedGeometry> entry : 
map.entrySet()) {
-                    final ReferenceSystem krs = entry.getKey();
-                    if (rs instanceof DiscreteGlobalGridReferenceSystem && krs 
instanceof DiscreteGlobalGridReferenceSystem) {
-                        final CodedGeometry result = 
mergeDggrs(entry.getValue(), slice);
-                        map.remove(entry.getKey());
-                        map.put(result.getReferenceSystem(), result);
-                        continue sliceLoop;
-                    } else if (rs instanceof CoordinateReferenceSystem crs1 && 
krs instanceof CoordinateReferenceSystem crs2) {
-                        try {
-                            CRS.findOperation(crs2, crs1, null);
-                            final CodedGeometry result = 
mergeGrids(entry.getValue(), slice);
-                            map.remove(entry.getKey());
-                            map.put(result.getReferenceSystem(), result);
-                            continue sliceLoop;
-                        } catch (FactoryException | TransformException ex) {
-                            //do nothing, continue
-                        }
+    /**
+     * Aggregates the given geometries in a single geometry.
+     * The first geometry is the reference, it is copied unchanged at the 
beginning of the result.
+     * The components of the other geometries which can not be mapped from any 
component of the
+     * reference are appended after it. Such components are typically temporal 
or vertical axes.
+     * Equivalent components found in several geometries are merged in a 
single component
+     * containing all their values.
+     *
+     * @param  geometries  geometries to aggregate, the first one is the 
reference.
+     * @return the aggregated geometry, or the reference if no other geometry 
has extra components.
+     * @throws IllegalArgumentException if an extra component can not be 
aggregated.
+     * @throws FactoryException if an operation between equivalent components 
can not be created.
+     * @throws TransformException if the values of equivalent components can 
not be converted.
+     */
+    private static CodedGeometry aggregate(CodedGeometry ... geometries) 
throws FactoryException, TransformException {
+        if (geometries.length == 0) return null;
+        final CodedGeometry reference = geometries[0];
+        final ReferenceSystem referenceRs = reference.getReferenceSystem();
+        if (referenceRs == null) return reference;
+        final List<ReferenceSystem> referenceComponents = 
ReferenceSystems.getSingleComponents(referenceRs, true);
+
+        final List<CodedGeometry> extras = new ArrayList<>();
+        for (int g = 1; g < geometries.length; g++) {
+            final CodedGeometry geometry = geometries[g];
+            if (geometry.getReferenceSystem() == null) continue;
+            componentLoop:
+            for (ReferenceSystem component : 
ReferenceSystems.getSingleComponents(geometry.getReferenceSystem(), true)) {
+                if (isMappable(referenceComponents, component)) continue;
+                if (!(component instanceof CoordinateReferenceSystem crs) || 
ReferenceSystems.getDimension(crs) != 1) {
+                    throw new IllegalArgumentException("Can not aggregate 
component " + component.getName()
+                            + ", only one-dimensional coordinate reference 
systems are supported.");
+                }
+                final CodedGeometry slice = geometry.slice(component).get();
+
+                for (int i = 0, n = extras.size(); i < n; i++) {
+                    final CodedGeometry extra = extras.get(i);
+                    try {
+                        CRS.findOperation(crs, (CoordinateReferenceSystem) 
extra.getReferenceSystem(), null);
+                    } catch (FactoryException ex) {
+                        //not an equivalent axis, continue
+                        continue;
                     }
+                    if (extra.isRegularGrid().isEmpty() || 
slice.isRegularGrid().isEmpty()) {
+                        throw new IllegalArgumentException("Can not aggregate 
component " + component.getName()
+                                + ", only regular grids can be merged.");
+                    }
+                    extras.set(i, mergeGrids(extra, slice));
+                    continue componentLoop;
                 }
 
-                //no equivalent dimension, we can add it
-                map.put(rs, slice);
+                //no equivalent component, we can add it
+                extras.add(slice);
             }
         }
-
-        final List<CodedGeometry> sliceQuery = new ArrayList<>(map.values());
-
-        //place RS in order : horiontal > vertical > others
-        sliceQuery.sort(new Comparator<CodedGeometry>() {
-            @Override
-            public int compare(CodedGeometry o1, CodedGeometry o2) {
-                final ReferenceSystem rs1 = o1.getReferenceSystem();
-                final ReferenceSystem rs2 = o2.getReferenceSystem();
-                if (rs1 instanceof DiscreteGlobalGridReferenceSystem) return 
-1;
-                if (rs2 instanceof DiscreteGlobalGridReferenceSystem) return 
+1;
-
-                final CoordinateReferenceSystem crs1 = 
(CoordinateReferenceSystem) rs1;
-                final CoordinateReferenceSystem crs2 = 
(CoordinateReferenceSystem) rs2;
-                if (CRS.isHorizontalCRS(crs1)) return -1;
-                if (CRS.isHorizontalCRS(crs2)) return +1;
-                if (crs1 instanceof VerticalCRS) return -1;
-                if (crs2 instanceof VerticalCRS) return +1;
-                return 0;
-            }
-        });
-        return 
CodedGeometry.compound(sliceQuery.toArray(CodedGeometry[]::new));
+        if (extras.isEmpty()) return reference;
+        extras.add(0, reference);
+        return compound(extras.toArray(CodedGeometry[]::new));
     }
 
-    private CodedGeometry mergeDggrs(CodedGeometry cg1, CodedGeometry cg2) {
-        final DiscreteGlobalGridReferenceSystem dggrs1 = 
(DiscreteGlobalGridReferenceSystem) cg1.getReferenceSystem();
-        final DiscreteGlobalGridReferenceSystem dggrs2 = 
(DiscreteGlobalGridReferenceSystem) cg2.getReferenceSystem();
-        if (!dggrs1.equals(dggrs2)) {
-            throw new IllegalArgumentException("Two code geometries use 
different DGGRS");
+    /**
+     * Returns true if an operation exists from one of the reference 
components to the given component.
+     */
+    private static boolean isMappable(List<ReferenceSystem> 
referenceComponents, ReferenceSystem component) {
+        for (ReferenceSystem candidate : referenceComponents) {
+            try {
+                ReferenceSystems.findOperation(candidate, component, null);
+                return true;
+            } catch (FactoryException ex) {
+                //not mappable from this component, try next
+            }
         }
-        return DiscreteGlobalGridGeometry.unstructured(dggrs1, null, null);
+        return false;
     }
 
-    private CodedGeometry mergeGrids(CodedGeometry cg1, CodedGeometry cg2) 
throws FactoryException, TransformException {
+    /**
+     * Merges two one-dimensional regular grids in a grid containing the 
values of both.
+     */
+    private static CodedGeometry mergeGrids(CodedGeometry cg1, CodedGeometry 
cg2) throws FactoryException, TransformException {
         final GridGeometry grid1 = cg1.isRegularGrid().get();
         GridGeometry grid2 = cg2.isRegularGrid().get();
         final CoordinateReferenceSystem crs1 = 
grid1.getCoordinateReferenceSystem();
-        final CoordinateReferenceSystem crs2 = 
grid2.getCoordinateReferenceSystem();
 
         if ( grid1.isDefined(GridGeometry.EXTENT | GridGeometry.GRID_TO_CRS)
            && grid2.isDefined(GridGeometry.EXTENT | GridGeometry.GRID_TO_CRS)) 
{
@@ -208,6 +222,10 @@ public final class CompoundCodedResource extends 
AbstractResource implements Cod
             final double[] array1 = allTransformedValues(grid1);
             final double[] array2 = allTransformedValues(grid2);
             final double[] all = merge(array1, array2);
+            if (all.length == array1.length) {
+                //second grid does not add any value, preserve the original 
transform
+                return cg1;
+            }
 
             final MathTransform trs = MathTransforms.interpolate(null, all);
             final GridGeometry result = new GridGeometry(new GridExtent(null, 
0, all.length, false), PixelInCell.CELL_CENTER, trs, crs1);
@@ -220,7 +238,7 @@ public final class CompoundCodedResource extends 
AbstractResource implements Cod
         }
     }
 
-    private GridGeometry toOther(GridGeometry grid, CoordinateReferenceSystem 
target) throws FactoryException {
+    private static GridGeometry toOther(GridGeometry grid, 
CoordinateReferenceSystem target) throws FactoryException {
         final CoordinateReferenceSystem source = 
grid.getCoordinateReferenceSystem();
         final GridExtent sourceExtent = grid.getExtent();
         final MathTransform sourceGridToCRS = 
grid.getGridToCRS(PixelInCell.CELL_CENTER);
@@ -247,10 +265,9 @@ public final class CompoundCodedResource extends 
AbstractResource implements Cod
     }
 
     private static double[] merge(double[] array1, double[] array2) {
-        final Set<Double> all = new TreeSet();
+        final Set<Double> all = new TreeSet<>();
         for (double d : array1) all.add(d);
         for (double d : array2) all.add(d);
         return all.stream().mapToDouble(Double::doubleValue).toArray();
     }
-
 }

Reply via email to