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

desruisseaux pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sis.git

commit d1adc5678e03d1d04abdd1e832ce08f7aa774599
Merge: f0a1dfadf1 51c67748ee
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Fri Jul 19 18:13:34 2024 +0200

    Merge branch 'geoapi-3.1'

 .../apache/sis/buildtools/gradle/Assembler.java    |   2 +-
 .../org/apache/sis/buildtools/gradle/UnoPkg.java   |   2 +-
 endorsed/build.gradle.kts                          |   3 +
 .../apache/sis/coverage/grid/DimensionReducer.java |   2 +-
 .../main/org/apache/sis/filter/TemporalFilter.java |   2 +-
 .../coverage/grid/ResampledGridCoverageTest.java   |   2 +-
 .../iso/quality/DefaultEvaluationMethod.java       |  16 +-
 .../iso/quality/DefaultMeasureReference.java       |  14 +-
 .../sis/metadata/privy/ImplementationHelper.java   |   2 +-
 .../{internal => privy}/RecordSchemaSIS.java       |   5 +-
 .../sis/metadata/privy/TransformationAccuracy.java |  90 -------
 .../apache/sis/metadata/sql/MetadataSource.java    |   2 +-
 .../org/apache/sis/util/iso/DefaultRecord.java     |   2 +-
 .../org/apache/sis/util/iso/DefaultRecordType.java |   2 +-
 .../main/org/apache/sis/xml/MarshallerPool.java    |   2 +-
 .../org/apache/sis/xml/privy/XmlUtilities.java     |   2 +-
 .../iso/quality/DefaultQuantitativeResultTest.java |   2 +-
 .../sis/openoffice/ReferencingFunctionsTest.java   |   2 +-
 .../apache/sis/io/wkt/GeodeticObjectParser.java    |   4 +-
 .../main/org/apache/sis/referencing/CRS.java       |   2 +-
 .../main/org/apache/sis/referencing/CommonCRS.java |  10 +-
 .../sis/referencing/crs/DefaultGeodeticCRS.java    |   2 +-
 .../apache/sis/referencing/datum/PseudoDatum.java  | 267 ++++++++++++++++++---
 .../referencing/factory/sql/EPSGDataAccess.java    |  42 ++--
 .../sis/referencing/internal/AnnotatedMatrix.java  |   1 -
 .../PositionalAccuracyConstant.java                | 144 ++++++++---
 .../apache/sis/referencing/internal/Resources.java |  10 +
 .../sis/referencing/internal/Resources.properties  |   4 +-
 .../referencing/internal/Resources_fr.properties   |   4 +-
 .../operation/AbstractCoordinateOperation.java     |   2 +-
 .../operation/CoordinateOperationContext.java      |   2 +-
 .../operation/CoordinateOperationFinder.java       |  71 ++++--
 .../operation/CoordinateOperationRegistry.java     |  15 +-
 .../operation/DefaultConcatenatedOperation.java    |   2 +-
 .../DefaultCoordinateOperationFactory.java         |  23 +-
 .../referencing/privy/ReferencingUtilities.java    |  24 --
 .../datum/DefaultGeodeticDatumTest.java            |   2 +-
 .../factory/ConcurrentAuthorityFactoryTest.java    |  49 ++--
 .../internal/PositionalAccuracyConstantTest.java   | 111 +++++++++
 .../operation/CoordinateOperationFinderTest.java   |   4 +-
 .../DefaultCoordinateOperationFactoryTest.java     |   2 +-
 .../privy/PositionalAccuracyConstantTest.java      |  68 ------
 .../sis/storage/geotiff/reader/CRSBuilder.java     |   2 +-
 .../storage/geotiff/writer/CompressionChannel.java |   2 +-
 .../apache/sis/storage/base/MetadataBuilder.java   |   2 +-
 .../sis/util/collection/WeakValueHashMap.java      |  24 ++
 netbeans-project/nbproject/project.properties      |   1 +
 .../main/org/apache/sis/gui/internal/FontGIS.java  |   2 +-
 48 files changed, 664 insertions(+), 388 deletions(-)

diff --cc 
endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/quality/DefaultMeasureReference.java
index 924fa1f2a9,cfd4a3e88c..a92bd391b0
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/quality/DefaultMeasureReference.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/quality/DefaultMeasureReference.java
@@@ -24,12 -24,10 +24,13 @@@ import org.opengis.util.InternationalSt
  import org.opengis.metadata.Identifier;
  import org.opengis.metadata.quality.Element;
  import org.apache.sis.util.privy.CollectionsExt;
+ import org.apache.sis.util.iso.Types;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.metadata.quality.MeasureReference;
 +// Specific to the main branch:
 +import org.opengis.annotation.UML;
 +import static org.opengis.annotation.Obligation.OPTIONAL;
 +import static org.opengis.annotation.Obligation.CONDITIONAL;
 +import static org.opengis.annotation.Specification.UNSPECIFIED;
  
  
  /**
diff --cc 
endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordType.java
index 00789215e4,55bb94d6ef..9e7965f145
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordType.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordType.java
@@@ -42,8 -42,11 +42,8 @@@ import org.apache.sis.util.CharSequence
  import org.apache.sis.util.ObjectConverters;
  import org.apache.sis.util.resources.Errors;
  import org.apache.sis.converter.SurjectiveConverter;
- import org.apache.sis.metadata.internal.RecordSchemaSIS;
+ import org.apache.sis.metadata.privy.RecordSchemaSIS;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.util.NameFactory;
 -
  
  /**
   * An immutable definition of the type of a {@linkplain DefaultRecord record}.
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
index c4ce6961ad,cb5394aeac..e894c0d817
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
@@@ -2086,9 -2084,17 +2086,17 @@@ public enum CommonCRS 
           */
          public boolean datumUsedBy(final CoordinateReferenceSystem crs) {
              for (final SingleCRS component : CRS.getSingleComponents(crs)) {
-                 if (ReferencingUtilities.uses(component, datum)) {
+                 if (Utilities.equalsIgnoreMetadata(datum, 
component.getDatum())) {
                      return true;
                  }
 -                final var ensemble = component.getDatumEnsemble();
++                final var ensemble = getDatumEnsemble(component);
+                 if (ensemble != null) {
+                     for (final Datum member : ensemble.getMembers()) {
+                         if (Utilities.equalsIgnoreMetadata(datum, member)) {
+                             return true;
+                         }
+                     }
+                 }
              }
              return false;
          }
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/PseudoDatum.java
index d5ef3f68e1,ee840991a4..83fd8e8334
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/PseudoDatum.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/PseudoDatum.java
@@@ -26,7 -27,10 +27,8 @@@ import java.util.function.Function
  import java.io.Serializable;
  import org.opengis.util.GenericName;
  import org.opengis.util.InternationalString;
+ import org.opengis.metadata.quality.PositionalAccuracy;
  import org.opengis.referencing.IdentifiedObject;
 -import org.opengis.referencing.ObjectDomain;
  import org.opengis.referencing.datum.*;
  import org.opengis.referencing.crs.*;
  import org.apache.sis.util.Utilities;
@@@ -200,6 -201,224 +182,210 @@@ public abstract class PseudoDatum<D ext
          return datum;
      }
  
+     /**
+      * Returns the datum or pseudo-datum of the result of an operation 
between the given geodetic <abbr>CRS</abbr>s.
+      * If the two given coordinate reference systems are associated to the 
same datum, then this method returns
+      * the <var>target</var> datum. Otherwise, this method returns a 
pseudo-datum for the largest ensemble which
+      * fully contains the datum or datum ensemble of the other 
<abbr>CRS</abbr>. If none of the <var>source</var>
+      * or <var>target</var> datum ensembles met that criterion, then this 
method returns an empty value.
+      * A non-empty value means that it is okay, for low accuracy 
requirements, to ignore the datum shift.
+      *
+      * @param  source  the source <abbr>CRS</abbr> of a coordinate operation.
+      * @param  target  the target <abbr>CRS</abbr> of a coordinate operation.
+      * @return datum or pseudo-datum of the coordinate operation result if it 
is okay to ignore datum shift.
+      */
+     public static Optional<GeodeticDatum> ofOperation(final GeodeticCRS 
source, final GeodeticCRS target) {
+         return ofOperation(source, source.getDatum(),
+                            target, target.getDatum(),
+                            Geodetic::new);
+     }
+ 
+     /**
+      * Returns the datum or pseudo-datum of the result of an operation 
between the given vertical <abbr>CRS</abbr>s.
+      * See {@link #ofOperation(GeodeticCRS, GeodeticCRS)} for more 
information.
+      *
+      * @param  source  the source <abbr>CRS</abbr> of a coordinate operation.
+      * @param  target  the target <abbr>CRS</abbr> of a coordinate operation.
+      * @return datum or pseudo-datum of the coordinate operation result if it 
is okay to ignore datum shift.
+      */
+     public static Optional<VerticalDatum> ofOperation(final VerticalCRS 
source, final VerticalCRS target) {
+         return ofOperation(source, source.getDatum(),
+                            target, target.getDatum(),
+                            Vertical::new);
+     }
+ 
+     /**
+      * Returns the datum or pseudo-datum of the result of an operation 
between the given temporal <abbr>CRS</abbr>s.
+      * See {@link #ofOperation(GeodeticCRS, GeodeticCRS)} for more 
information.
+      *
+      * @param  source  the source <abbr>CRS</abbr> of a coordinate operation.
+      * @param  target  the target <abbr>CRS</abbr> of a coordinate operation.
+      * @return datum or pseudo-datum of the coordinate operation result if it 
is okay to ignore datum shift.
+      */
+     public static Optional<TemporalDatum> ofOperation(final TemporalCRS 
source, final TemporalCRS target) {
+         return ofOperation(source, source.getDatum(),
+                            target, target.getDatum(),
+                            Time::new);
+     }
+ 
 -    /**
 -     * Returns the datum or pseudo-datum of the result of an operation 
between the given parametric <abbr>CRS</abbr>s.
 -     * See {@link #ofOperation(GeodeticCRS, GeodeticCRS)} for more 
information.
 -     *
 -     * @param  source  the source <abbr>CRS</abbr> of a coordinate operation.
 -     * @param  target  the target <abbr>CRS</abbr> of a coordinate operation.
 -     * @return datum or pseudo-datum of the coordinate operation result if it 
is okay to ignore datum shift.
 -     */
 -    public static Optional<ParametricDatum> ofOperation(final ParametricCRS 
source, final ParametricCRS target) {
 -        return ofOperation(source, source.getDatum(),
 -                           target, target.getDatum(),
 -                           Parametric::new);
 -    }
 -
+     /**
+      * Returns the datum or pseudo-datum of the result of an operation 
between the given engineering <abbr>CRS</abbr>s.
+      * See {@link #ofOperation(GeodeticCRS, GeodeticCRS)} for more 
information.
+      *
+      * @param  source  the source <abbr>CRS</abbr> of a coordinate operation.
+      * @param  target  the target <abbr>CRS</abbr> of a coordinate operation.
+      * @return datum or pseudo-datum of the coordinate operation result if it 
is okay to ignore datum shift.
+      */
+     public static Optional<EngineeringDatum> ofOperation(final EngineeringCRS 
source, final EngineeringCRS target) {
+         return ofOperation(source, source.getDatum(),
+                            target, target.getDatum(),
+                            Engineering::new);
+     }
+ 
+     /**
+      * Returns the datum or pseudo-datum of a coordinate operation from 
<var>source</var> to <var>target</var>.
+      * If the two given coordinate reference systems are associated to the 
same datum, then this method returns
+      * the <var>target</var> datum. Otherwise, this method returns a 
pseudo-datum for the largest ensemble which
+      * fully contains the datum or datum ensemble of the other 
<abbr>CRS</abbr>. If none of the <var>source</var>
+      * or <var>target</var> datum ensembles met that criterion, then this 
method returns an empty value.
+      * A non-empty value means that it is okay, for low accuracy 
requirements, to ignore the datum shift.
+      *
+      * @param  source       the source <abbr>CRS</abbr> of a coordinate 
operation.
+      * @param  sourceDatum  the datum of the source <abbr>CRS</abbr>.
+      * @param  target       the target <abbr>CRS</abbr> of a coordinate 
operation.
+      * @param  targetDatum  the datum of the target <abbr>CRS</abbr>.
+      * @param  constructor  function to invoke for wrapping a datum ensemble 
in a pseudo-datum.
+      * @return datum or pseudo-datum of the coordinate operation result if it 
is okay to ignore datum shift.
+      */
+     @SuppressWarnings("unchecked")          // Casts are safe because callers 
know the method signature of <D>.
+     private static <C extends SingleCRS, D extends Datum, R extends 
IdentifiedObject> Optional<R> ofOperation(
+             final C source, final R sourceDatum,
+             final C target, final R targetDatum,
 -            final Function<DatumEnsemble<D>, R> constructor)
++            final Function<DefaultDatumEnsemble<D>, R> constructor)
+     {
+         if (sourceDatum != null && 
Utilities.equalsIgnoreMetadata(sourceDatum, targetDatum)) {
+             return Optional.of(targetDatum);
+         }
 -        DatumEnsemble<D> sourceEnsemble;
 -        DatumEnsemble<D> targetEnsemble;
 -        DatumEnsemble<D> selected;
 -        if ((isMember(selected = targetEnsemble = (DatumEnsemble<D>) 
target.getDatumEnsemble(), sourceDatum)) ||
 -            (isMember(selected = sourceEnsemble = (DatumEnsemble<D>) 
source.getDatumEnsemble(), targetDatum)))
++        DefaultDatumEnsemble<D> sourceEnsemble;
++        DefaultDatumEnsemble<D> targetEnsemble;
++        DefaultDatumEnsemble<D> selected;
++        if ((isMember(selected = targetEnsemble = (DefaultDatumEnsemble<D>) 
getDatumEnsemble(target), sourceDatum)) ||
++            (isMember(selected = sourceEnsemble = (DefaultDatumEnsemble<D>) 
getDatumEnsemble(source), targetDatum)))
+         {
+             return Optional.of(constructor.apply(selected));
+         }
+         if (sourceEnsemble != null && targetEnsemble != null) {
+             selected = targetEnsemble;
+             Collection<D> large = targetEnsemble.getMembers();
+             Collection<D> small = sourceEnsemble.getMembers();
+             if (small.size() > large.size()) {
+                 selected = sourceEnsemble;
+                 var t = large;
+                 large = small;
+                 small = t;
+             }
+             small = new ArrayDeque<>(small);
+             for (final Datum member : large) {
+                 final Iterator<D> it = small.iterator();
+                 while (it.hasNext()) {
+                     if (Utilities.equalsIgnoreMetadata(member, it.next())) {
+                         it.remove();
+                         if (small.isEmpty()) {
+                             /*
+                              * Found all members of the smaller ensemble. 
Take the larger ensemble,
+                              * as it contains both ensembles and should have 
conservative accuracy.
+                              */
+                             return Optional.of(constructor.apply(selected));
+                         }
+                         break;      // For removing only the first match.
+                     }
+                 }
+             }
+         }
+         return Optional.empty();
+     }
+ 
+     /**
+      * Returns whether the given datum is a member of the given ensemble.
+      *
+      * @param  datum     the datum to test, or {@code null}.
+      * @param  ensemble  the ensemble to test, or {@code null}.
+      * @return whether the ensemble contains the given datum.
+      */
 -    private static boolean isMember(final DatumEnsemble<?> ensemble, final 
IdentifiedObject datum) {
++    private static boolean isMember(final DefaultDatumEnsemble<?> ensemble, 
final IdentifiedObject datum) {
+         if (ensemble != null) {
+             for (final Datum member : ensemble.getMembers()) {
+                 if (Utilities.equalsIgnoreMetadata(datum, member)) {
+                     return true;
+                 }
+             }
+         }
+         return false;
+     }
+ 
+     /**
+      * Returns the datum or ensemble of a coordinate operation from 
<var>source</var> to <var>target</var>.
+      * If the two given coordinate reference systems are associated to the 
same datum, then this method returns
+      * the <var>target</var> datum. Otherwise, this method returns the 
largest ensemble which fully contains the
+      * datum or datum ensemble of the other <abbr>CRS</abbr>. If none of the 
<var>source</var> or <var>target</var>
+      * datum ensembles met that criterion, then this method returns an empty 
value.
+      * A non-empty value means that it is okay, for low accuracy 
requirements, to ignore the datum shift.
+      *
+      * <p>This is an alternative to the {@code ofOperation(…)} methods when 
the caller does not need to view
+      * the returned object as a datum.</p>
+      *
+      * @param  source  the source <abbr>CRS</abbr> of a coordinate operation, 
or {@code null}.
+      * @param  target  the target <abbr>CRS</abbr> of a coordinate operation, 
or {@code null}.
+      * @return datum or datum ensemble of the coordinate operation result if 
it is okay to ignore datum shift.
+      */
+     public static Optional<IdentifiedObject> getDatumOrEnsemble(final 
SingleCRS source, final SingleCRS target) {
+         if (source == null) return 
Optional.ofNullable(getDatumOrEnsemble(target));
+         if (target == null) return 
Optional.ofNullable(getDatumOrEnsemble(source));
+         return ofOperation(source, source.getDatum(),
+                            target, target.getDatum(),
+                            (ensemble) -> ensemble);
+     }
+ 
+     /**
+      * Returns the datum of the given <abbr>CRS</abbr> if presents, or the 
datum ensemble otherwise.
+      * This is an alternative to the {@code of(…)} methods when the caller 
does not need to view the
+      * returned object as a datum.
+      *
+      * @param  crs  the <abbr>CRS</abbr> from which to get the datum or 
ensemble, or {@code null}.
+      * @return the datum if present, or the datum ensemble otherwise, or 
{@code null}.
+      */
+     public static IdentifiedObject getDatumOrEnsemble(final SingleCRS crs) {
+         if (crs == null) return null;
+         final Datum datum = crs.getDatum();
+         if (datum != null) {
+             if (datum instanceof PseudoDatum<?>) {
+                 return ((PseudoDatum) datum).ensemble;
+             }
+             return datum;
+         }
 -        return crs.getDatumEnsemble();
++        return getDatumEnsemble(crs);
+     }
+ 
+     /**
+      * If the given object is a datum ensemble or a wrapper for a datum 
ensemble, returns its accuracy.
 -     * This method recognizes the {@link DatumEnsemble} and {@link 
PseudoDatum} types.
++     * This method recognizes the {@link DefaultDatumEnsemble} and {@link 
PseudoDatum} types.
+      *
+      * @param  object  the object from which to get the ensemble accuracy, or 
{@code null}.
+      * @return the datum ensemble accuracy if the given object is a datum 
ensemble or a wrapper.
+      * @throws NullPointerException if the given object should provide an 
accuracy but didn't.
+      */
+     public static Optional<PositionalAccuracy> getEnsembleAccuracy(final 
IdentifiedObject object) {
 -        final DatumEnsemble<?> ensemble;
 -        if (object instanceof DatumEnsemble<?>) {
 -            ensemble = (DatumEnsemble<?>) object;
++        final DefaultDatumEnsemble<?> ensemble;
++        if (object instanceof DefaultDatumEnsemble<?>) {
++            ensemble = (DefaultDatumEnsemble<?>) object;
+         } else if (object instanceof PseudoDatum<?>) {
+             ensemble = ((PseudoDatum<?>) object).ensemble;
+         } else {
+             return Optional.empty();
+         }
+         return Optional.of(ensemble.getEnsembleAccuracy());     // 
Intentional NullPointerException if this property is null.
+     }
+ 
      /**
       * Returns the GeoAPI interface of the ensemble members.
       * It should also be the interface implemented by this class.
@@@ -241,14 -460,27 +427,16 @@@
          return ensemble.getIdentifiers();
      }
  
 -    /**
 -     * Returns the usage of the datum ensemble.
 -     *
 -     * @return {@code ensemble.getDomains()}.
 -     * @hidden
 -     */
 -    @Override
 -    public Collection<ObjectDomain> getDomains() {
 -        return ensemble.getDomains();
 -    }
 -
      /**
-      * Returns the anchor point common to all datum members, if any.
+      * Returns the domain of validity common to all datum members, if any.
       *
       * @return value common to all ensemble members, or {@code null} if none.
+      * @hidden
       */
      @Override
-     public InternationalString getAnchorPoint() {
-         return getCommonNullableValue(Datum::getAnchorPoint);
+     @Deprecated
+     public Extent getDomainOfValidity() {
+         return getCommonNullableValue(Datum::getDomainOfValidity);
      }
  
      /**
@@@ -262,25 -496,78 +452,29 @@@
      }
  
      /**
-      * Returns the domain of validity common to all datum members, if any.
+      * Returns the anchor point common to all datum members, if any.
       *
       * @return value common to all ensemble members, or {@code null} if none.
+      * @hidden
       */
      @Override
-     public Extent getDomainOfValidity() {
-         return getCommonNullableValue(Datum::getDomainOfValidity);
+     @Deprecated
+     public InternationalString getAnchorPoint() {
+         return getCommonNullableValue(Datum::getAnchorPoint);
      }
  
 -    /**
 -     * Returns an anchor definition which is common to all members of the 
datum ensemble.
 -     * If the value is not the same for all members (including the case where 
a member
 -     * has an empty value), then this method returns an empty value.
 -     *
 -     * @return the common anchor definition, or empty if there is no common 
value.
 -     */
 -    @Override
 -    public Optional<InternationalString> getAnchorDefinition() {
 -        return getCommonOptionalValue(Datum::getAnchorDefinition);
 -    }
 -
 -    /**
 -     * Returns an anchor epoch which is common to all members of the datum 
ensemble.
 -     * If the value is not the same for all members (including the case where 
a member
 -     * has an empty value), then this method returns an empty value.
 -     *
 -     * @return the common anchor epoch, or empty if there is no common value.
 -     */
 -    @Override
 -    public Optional<Temporal> getAnchorEpoch() {
 -        return getCommonOptionalValue(Datum::getAnchorEpoch);
 -    }
 -
      /**
-      * Returns the scope common to all datum members, if any.
+      * Returns the realization epoch common to all datum members, if any.
       *
       * @return value common to all ensemble members, or {@code null} if none.
+      * @hidden
       */
      @Override
-     public InternationalString getScope() {
-         return getCommonNullableValue(Datum::getScope);
+     @Deprecated
+     public Date getRealizationEpoch() {
+         return getCommonNullableValue(Datum::getRealizationEpoch);
      }
  
 -    /**
 -     * Returns a publication date which is common to all members of the datum 
ensemble.
 -     * If the value is not the same for all members (including the case where 
a member
 -     * has an empty value), then this method returns an empty value.
 -     *
 -     * @return the common publication date, or empty if there is no common 
value.
 -     */
 -    @Override
 -    public Optional<Temporal> getPublicationDate() {
 -        return getCommonOptionalValue(Datum::getPublicationDate);
 -    }
 -
 -    /**
 -     * Returns a conventional reference system which is common to all members 
of the datum ensemble.
 -     * The returned value should never be empty, because it is illegal for a 
datum ensemble to have
 -     * members with different conventional reference system. If this case 
nevertheless happens,
 -     * this method returns an empty value.
 -     *
 -     * @return the common conventional reference system, or empty if there is 
no common value.
 -     */
 -    @Override
 -    public Optional<IdentifiedObject> getConventionalRS() {
 -        return getCommonOptionalValue(Datum::getConventionalRS);
 -    }
 -
      /**
       * Returns an optional value which is common to all ensemble members.
       * If all members do not have the same value, returns {@code null}.
@@@ -495,14 -782,25 +689,13 @@@ check:  if (it.hasNext()) 
              return VerticalDatum.class;
          }
  
 -        /**
 -         * Returns a realization method which is common to all members of the 
datum ensemble.
 -         * If the value is not the same for all members (including the case 
where a member
 -         * has an empty value), then this method returns an empty value.
 -         *
 -         * @return the common realization method, or empty if there is no 
common value.
 -         */
 -        @Override
 -        public Optional<RealizationMethod> getRealizationMethod() {
 -            return 
getCommonOptionalValue(VerticalDatum::getRealizationMethod);
 -        }
 -
          /**
-          * Returns a datum type which is common to all members of the datum 
ensemble.
-          *
-          * @return the common datum type.
+          * @deprecated Replaced by {@link #getRealizationMethod()}.
           */
          @Override
+         @Deprecated
          public VerticalDatumType getVerticalDatumType() {
-             return 
getCommonMandatoryValue(VerticalDatum::getVerticalDatumType);
+             return 
getCommonNullableValue(VerticalDatum::getVerticalDatumType);
          }
      }
  
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 12423894d1,039ae92ea8..ae85930faa
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@@ -117,16 -120,10 +120,13 @@@ import org.apache.sis.measure.Measureme
  import org.apache.sis.measure.NumberRange;
  import org.apache.sis.measure.Units;
  import org.apache.sis.pending.jdk.JDK16;
- import static org.apache.sis.util.privy.Constants.UTC;
- import static org.apache.sis.util.Utilities.equalsIgnoreMetadata;
- import static 
org.apache.sis.referencing.internal.ServicesForMetadata.CONNECTION;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.metadata.Identifier;
 -import org.opengis.referencing.ObjectDomain;
 +// Specific to the main branch:
 +import org.apache.sis.referencing.internal.ServicesForMetadata;
 +import org.apache.sis.temporal.TemporalDate;
 +import org.apache.sis.referencing.cs.DefaultParametricCS;
 +import org.apache.sis.referencing.datum.DefaultParametricDatum;
 +import org.apache.sis.referencing.factory.GeodeticObjectFactory;
  
  
  /**
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
index ad2cc220c3,fc23726ebe..c2b71822c6
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
@@@ -743,9 -753,9 +749,9 @@@ public class CoordinateOperationFinder 
          CoordinateSystem interpolationCS = 
interpolationCRS.getCoordinateSystem();
          if (!(interpolationCS instanceof EllipsoidalCS)) {
              final EllipsoidalCS cs = 
CommonCRS.WGS84.geographic3D().getCoordinateSystem();
-             if (!equalsIgnoreMetadata(interpolationCS, cs)) {
+             if (!Utilities.equalsIgnoreMetadata(interpolationCS, cs)) {
                  final GeographicCRS stepCRS = factorySIS.crsFactory
 -                        .createGeographicCRS(derivedFrom(sourceCRS), 
sourceCRS.getDatum(), sourceCRS.getDatumEnsemble(), cs);
 +                        .createGeographicCRS(derivedFrom(sourceCRS), 
PseudoDatum.of(sourceCRS), cs);
                  step1 = createOperation(sourceCRS, 
toAuthorityDefinition(GeographicCRS.class, stepCRS));
                  interpolationCRS = step1.getTargetCRS();
                  interpolationCS  = interpolationCRS.getCoordinateSystem();
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java
index 036fb14c51,8c97dcf7c4..384290d9da
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java
@@@ -212,75 -206,6 +212,51 @@@ public final class ReferencingUtilitie
          return (types.length != 0) ? types[0] : type;
      }
  
 +    /**
 +     * Copies all {@link SingleCRS} components from the given source to the 
given collection.
 +     * For each {@link CompoundCRS} element found in the iteration, this 
method replaces the
 +     * {@code CompoundCRS} by its {@linkplain CompoundCRS#getComponents() 
components}, which
 +     * may themselves have other {@code CompoundCRS}. Those replacements are 
performed recursively
 +     * until we obtain a flat view of CRS components.
 +     *
 +     * @param  source  the collection of single or compound CRS.
 +     * @param  addTo   where to add the single CRS in order to obtain a flat 
view of {@code source}.
 +     * @return {@code true} if this method found only single CRS in {@code 
source}, in which case {@code addTo}
 +     *         got the same content (assuming that {@code addTo} was empty 
prior this method call).
 +     * @throws NoSuchElementException if a CRS component is missing.
 +     * @throws ClassCastException if a CRS is neither a {@link SingleCRS} or 
a {@link CompoundCRS}.
 +     *
 +     * @see 
org.apache.sis.referencing.CRS#getSingleComponents(CoordinateReferenceSystem)
 +     */
 +    public static boolean getSingleComponents(final Iterable<? extends 
CoordinateReferenceSystem> source,
 +            final Collection<? super SingleCRS> addTo) throws 
ClassCastException
 +    {
 +        boolean sameContent = true;
 +        for (final CoordinateReferenceSystem candidate : source) {
 +            if (candidate instanceof CompoundCRS) {
 +                getSingleComponents(((CompoundCRS) 
candidate).getComponents(), addTo);
 +                sameContent = false;
 +            } else if (candidate instanceof SingleCRS) {
 +                addTo.add((SingleCRS) candidate);
 +            } else {
 +                /*
 +                 * Illegal class. Try to provide a better error message, in 
particular when the CRS component
 +                 * is nil because it is an unresolved xlink in a GML 
document. Nil objects are proxies, which
 +                 * have hard to understand class names.
 +                 */
 +                final String message;
 +                if (candidate instanceof NilObject) {
 +                    message = Errors.format(Errors.Keys.NilObject_1, 
Identifiers.getNilReason((NilObject) candidate));
 +                    throw new NoSuchElementException(message);
 +                } else {
 +                    message = 
Errors.format(Errors.Keys.NestedElementNotAllowed_1, getInterface(candidate));
 +                    throw new ClassCastException(message);
 +                }
 +            }
 +        }
 +        return sameContent;
 +    }
 +
-     /**
-      * Returns whether the given <abbr>CRS</abbr> uses the given datum.
-      *
-      * @param  crs    the <abbr>CRS</abbr>, or {@code null}.
-      * @param  datum  the datum to compare with the <abbr>CRS</abbr> datum or 
datum ensemble.
-      * @return whether the given CRS <abbr>CRS</abbr> uses the specified 
datum.
-      */
-     public static boolean uses(final SingleCRS crs, final Datum datum) {
-         if (crs != null && datum != null) {
-             if (Utilities.equalsIgnoreMetadata(crs.getDatum(), datum)) {
-                 return true;
-             }
-             final var ensemble = MissingMethods.getDatumEnsemble(crs);
-             if (ensemble != null) {
-                 for (final Datum member : ensemble.getMembers()) {
-                     if (Utilities.equalsIgnoreMetadata(member, datum)) {
-                         return true;
-                     }
-                 }
-             }
-         }
-         return false;
-     }
- 
      /**
       * Returns {@code true} if the type of the given datum is ellipsoidal. A 
vertical datum is not allowed
       * to be ellipsoidal according ISO 19111, but Apache SIS relaxes this 
restriction in some limited cases,
diff --cc netbeans-project/nbproject/project.properties
index 028958f6db,46801fed4b..da94918e12
--- a/netbeans-project/nbproject/project.properties
+++ b/netbeans-project/nbproject/project.properties
@@@ -110,8 -110,10 +110,9 @@@ test.options = --add-modules jama,Geogr
                 --add-exports 
org.apache.sis.metadata/org.apache.sis.xml.privy=org.apache.sis.storage.geotiff 
\
                 --add-exports 
org.apache.sis.metadata/org.apache.sis.xml.bind.gcx=org.apache.sis.referencing \
                 --add-exports 
org.apache.sis.metadata/org.apache.sis.metadata.privy=org.apache.sis.referencing.gazetteer
 \
+                --add-exports 
org.apache.sis.referencing/org.apache.sis.referencing.internal=org.apache.sis.openoffice
 \
                 --add-exports 
org.apache.sis.feature/org.apache.sis.feature.privy=org.apache.sis.storage.sql \
 -               --add-exports 
org.apache.sis.feature/org.apache.sis.geometry.wrapper.jts=org.apache.sis.storage.sql,org.apache.sis.portrayal.map
 \
 -               --add-exports 
org.apache.sis.storage/org.apache.sis.storage.base=org.apache.sis.portrayal.map 
\
 +               --add-exports 
org.apache.sis.feature/org.apache.sis.geometry.wrapper.jts=org.apache.sis.storage.sql
 \
                 --add-exports 
org.apache.sis.storage/org.apache.sis.storage.test=${modules.list}
  
  #

Reply via email to