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

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

commit 182326f448bca9937b40b15517d074f1842f481c
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Mon Oct 16 05:42:45 2023 +0200

    Fix spurious warnings during the verification of map projection parameters.
---
 .../apache/sis/referencing/IdentifiedObjects.java  |  23 ++--
 .../org/apache/sis/storage/geotiff/CRSBuilder.java | 116 ++++++++++++---------
 2 files changed, 80 insertions(+), 59 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/IdentifiedObjects.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/IdentifiedObjects.java
index db3442e7c3..8bbd779010 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/IdentifiedObjects.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/IdentifiedObjects.java
@@ -174,6 +174,7 @@ public final class IdentifiedObjects extends Static {
      *
      * @see AbstractIdentifiedObject#getName()
      */
+    @OptionalCandidate
     public static String getName(final IdentifiedObject object, final Citation 
authority) {
         return getName(object, authority, null);
     }
@@ -255,6 +256,7 @@ public final class IdentifiedObjects extends Static {
      *
      * @see AbstractIdentifiedObject#getIdentifier()
      */
+    @OptionalCandidate
     public static Identifier getIdentifier(final IdentifiedObject object, 
final Citation authority) {
         if (object != null) {
             String cs = null;
@@ -297,19 +299,16 @@ public final class IdentifiedObjects extends Static {
      * @see #lookupURN(IdentifiedObject, Citation)
      */
     public static String getIdentifierOrName(final IdentifiedObject object) {
-        if (object != null) {
-            for (final Identifier id : nonNull(object.getIdentifiers())) {
-                final String code = toString(id);
-                if (code != null) {                                 // 
Paranoiac check.
-                    return code;
-                }
-            }
-            final String name = toString(object.getName());
-            if (name != null) {                                     // 
Paranoiac check.
-                return name;
+        if (object == null) {
+            return null;
+        }
+        for (final Identifier id : nonNull(object.getIdentifiers())) {
+            final String code = toString(id);
+            if (code != null) {                                 // Paranoiac 
check.
+                return code;
             }
         }
-        return null;
+        return toString(object.getName());
     }
 
     /**
@@ -336,6 +335,7 @@ public final class IdentifiedObjects extends Static {
      *
      * @since 1.0
      */
+    @OptionalCandidate
     public static String getSimpleNameOrIdentifier(final IdentifiedObject 
object) {
         if (object != null) {
             Identifier identifier = object.getName();
@@ -449,6 +449,7 @@ public final class IdentifiedObjects extends Static {
      *
      * @since 0.7
      */
+    @OptionalCandidate
     public static String lookupURN(final IdentifiedObject object, final 
Citation authority) throws FactoryException {
         if (object == null) {
             return null;
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CRSBuilder.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CRSBuilder.java
index c8cc438544..e3643d7088 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CRSBuilder.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CRSBuilder.java
@@ -36,6 +36,8 @@ import javax.measure.quantity.Angle;
 import javax.measure.quantity.Length;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.spatial.CellGeometry;
+import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.referencing.IdentifiedObject;
@@ -56,30 +58,31 @@ import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.util.FactoryException;
-import org.apache.sis.storage.geotiff.internal.Resources;
+import org.apache.sis.parameter.Parameters;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.referencing.cs.AxesConvention;
+import org.apache.sis.referencing.cs.CoordinateSystems;
+import org.apache.sis.referencing.crs.DefaultProjectedCRS;
+import org.apache.sis.referencing.crs.DefaultGeographicCRS;
 import org.apache.sis.referencing.util.WKTKeywords;
 import org.apache.sis.referencing.util.NilReferencingObject;
 import org.apache.sis.referencing.util.ReferencingUtilities;
 import org.apache.sis.referencing.util.ReferencingFactoryContainer;
 import org.apache.sis.referencing.operation.provider.PolarStereographicA;
 import org.apache.sis.referencing.operation.provider.PolarStereographicB;
+import org.apache.sis.io.TableAppender;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Characters;
 import org.apache.sis.util.internal.Constants;
 import org.apache.sis.util.internal.Strings;
 import org.apache.sis.util.internal.Numerics;
+import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.resources.Errors;
 import org.apache.sis.math.Vector;
 import org.apache.sis.measure.Units;
 import org.apache.sis.metadata.iso.citation.Citations;
-import org.apache.sis.referencing.cs.AxesConvention;
-import org.apache.sis.referencing.cs.CoordinateSystems;
-import org.apache.sis.referencing.crs.DefaultProjectedCRS;
-import org.apache.sis.referencing.crs.DefaultGeographicCRS;
-import org.apache.sis.io.TableAppender;
-import org.apache.sis.util.resources.Vocabulary;
-import org.apache.sis.util.resources.Errors;
+import org.apache.sis.storage.geotiff.internal.Resources;
 
 import static org.apache.sis.util.Utilities.equalsIgnoreMetadata;
 
@@ -411,7 +414,7 @@ final class CRSBuilder extends ReferencingFactoryContainer {
      * If the values do not match, a warning is reported and the caller should 
use the EPSG value.
      *
      * @param  epsg      the EPSG object, to be used for formatting the 
warning in case of mismatched values.
-     * @param  expected  the expected value for an object identified by the 
{@code epsg} code.
+     * @param  expected  the expected value for an object identified by the 
{@code epsg} code, or NaN for no comparison.
      * @param  key       the GeoTIFF key of the user-defined value to compare 
with the expected one.
      * @param  unit      the unit of measurement for {@code expected} and 
{@code actual}, or {@code null} if none.
      */
@@ -539,11 +542,13 @@ final class CRSBuilder extends 
ReferencingFactoryContainer {
         }
         /*
          * At this point we finished parsing all GeoTIFF tags, both for 
metadata purpose or for CRS construction.
-         * Emit a warning for unprocessed GeoTIFF tags. A single warning is 
emitted for all ignored tags.
+         * Emits a warning for unprocessed GeoTIFF tags. A single warning is 
emitted for all ignored tags.
          */
         if (!geoKeys.isEmpty()) {
             final StringJoiner joiner = new StringJoiner(", ");
-            for (final short key : remainingKeys()) {
+            final Short[] keys = geoKeys.keySet().toArray(Short[]::new);
+            Arrays.sort(keys);
+            for (final short key : keys) {
                 joiner.add(GeoKeys.name(key));
             }
             warning(Resources.Keys.IgnoredGeoKeys_1, joiner.toString());
@@ -551,15 +556,6 @@ final class CRSBuilder extends ReferencingFactoryContainer 
{
         return crs;
     }
 
-    /**
-     * Returns all remaining keys, sorted in increasing order.
-     */
-    private Short[] remainingKeys() {
-        final Short[] keys = geoKeys.keySet().toArray(Short[]::new);
-        Arrays.sort(keys);
-        return keys;
-    }
-
 
 
 
@@ -1299,15 +1295,18 @@ final class CRSBuilder extends 
ReferencingFactoryContainer {
         final Conversion projection = crs.getConversionFromBase();
         verifyIdentifier(crs, projection, GeoKeys.Projection);
         verify(projection, angularUnit, linearUnit);
+        getAsString(GeoKeys.ProjectedCitation);
     }
 
     /**
      * Returns the code of the operation method to request.
      * This method tries to resolves some ambiguities in the way operation 
methods are defined.
      * For example there is an ambiguity between Polar Stereographic (variant 
A) and (variant B).
+     *
+     * @param  code  value of {@code getMandatoryString(GeoKeys.ProjMethod)}.
+     * @return the method code in the GeoTIFF or EPSG name space.
      */
-    private String methodCode() {
-        final String code = getMandatoryString(GeoKeys.ProjMethod);
+    private String methodCode(final String code) {
         try {
             switch (Integer.parseInt(code)) {
                 case GeoCodes.PolarStereographic: {
@@ -1335,6 +1334,7 @@ final class CRSBuilder extends 
ReferencingFactoryContainer {
                 // More cases may be added in the future.
             }
         } catch (NumberFormatException e) {
+            invalidValue(GeoKeys.ProjMethod, code);
             return code;
         }
         return Constants.GEOTIFF + ':' + code;
@@ -1362,7 +1362,8 @@ final class CRSBuilder extends 
ReferencingFactoryContainer {
             }
             case GeoCodes.userDefined: {
                 final Unit<Angle>         azimuthUnit = 
createAngularUnit(UnitKey.AZIMUTH);
-                final OperationMethod     method      = 
getCoordinateOperationFactory().getOperationMethod(methodCode());
+                final String              code        = 
methodCode(getMandatoryString(GeoKeys.ProjMethod));
+                final OperationMethod     method      = 
getCoordinateOperationFactory().getOperationMethod(code);
                 final ParameterValueGroup parameters  = 
method.getParameters().createValue();
                 final Map<Integer,String> toNames     = 
ReferencingUtilities.identifierToName(parameters.getDescriptor(), 
Citations.GEOTIFF);
                 final Map<Object,Number>  paramValues = new HashMap<>();    // 
Keys: [String|Short] instances for [known|unknown] parameters.
@@ -1444,38 +1445,57 @@ final class CRSBuilder extends 
ReferencingFactoryContainer {
             throws FactoryException
     {
         final Unit<Angle> azimuthUnit = createAngularUnit(UnitKey.AZIMUTH);
-        final String type = getAsString(GeoKeys.ProjMethod);
-        if (type != null) {
+        final String code = getAsString(GeoKeys.ProjMethod);
+        if (code != null) {
             /*
-             * Compare the name of the map projection declared in the GeoTIFF 
file with the name
-             * of the projection used by the EPSG geodetic dataset.
+             * Compare the identifier of the map projection declared in the 
GeoTIFF file with the identifier
+             * of the projection used by the EPSG geodetic dataset. The two 
cases may use different variants
+             * of the same projection (e.g. Mercator variant A, B and C), so 
the GeoTIFF code may be missing
+             * in the projection given in argument.
              */
-            final OperationMethod method = projection.getMethod();
-            if (!IdentifiedObjects.isHeuristicMatchForName(method, type)) {
-                Identifier expected = IdentifiedObjects.getIdentifier(method, 
Citations.GEOTIFF);
-                if (expected == null) {
-                    expected = IdentifiedObjects.getIdentifier(method, null);
+            OperationMethod method = projection.getMethod();
+            Identifier id = IdentifiedObjects.getIdentifier(method, 
Citations.GEOTIFF);
+            final boolean isSameProjection = (id != null) && 
code.equals(id.getCode());
+            if (!isSameProjection) {
+                if (id != null) {
+                    final String key    = GeoKeys.name(GeoKeys.ProjMethod);
+                    final String parent = 
IdentifiedObjects.getIdentifierOrName(projection);
+                    warning(Resources.Keys.NotTheEpsgValue_5, parent, 
id.getCode(), key, code, "");
                 }
-                warning(Resources.Keys.NotTheEpsgValue_5, 
IdentifiedObjects.getIdentifierOrName(projection),
-                        expected.getCode(), GeoKeys.name(GeoKeys.ProjMethod), 
type, "");
+                method = 
getCoordinateOperationFactory().getOperationMethod(methodCode(code));
             }
             /*
              * Compare the parameter values with the ones declared in the EPSG 
geodetic dataset.
              */
-            final ParameterValueGroup parameters = 
projection.getParameterValues();
-            for (final short key : remainingKeys()) {
-                final Unit<?> unit;
-                switch (UnitKey.ofProjectionParameter(key)) {
-                    case RATIO:     unit = Units.UNITY; break;
-                    case PROJECTED: unit = linearUnit;  break;
-                    case ANGULAR:   unit = angularUnit; break;
-                    case AZIMUTH:   unit = azimuthUnit; break;
-                    default: continue;
-                }
-                try {
-                    verify(projection, parameters.parameter("GeoTIFF:" + 
key).doubleValue(unit), key, unit);
-                } catch (ParameterNotFoundException e) {
-                    warning(Resources.Keys.UnexpectedParameter_2, type, 
GeoKeys.name(key));
+            final Parameters parameters = 
Parameters.castOrWrap(projection.getParameterValues());
+            for (final GeneralParameterDescriptor desc : 
method.getParameters().descriptors()) {
+                id = IdentifiedObjects.getIdentifier(desc, Citations.GEOTIFF);
+                if (id != null) {
+                    final short key;
+                    try {
+                        key = Short.parseShort(id.getCode());
+                    } catch (NumberFormatException e) {
+                        continue;
+                    }
+                    final Unit<?> unit;
+                    switch (UnitKey.ofProjectionParameter(key)) {
+                        case RATIO:     unit = Units.UNITY; break;
+                        case PROJECTED: unit = linearUnit;  break;
+                        case ANGULAR:   unit = angularUnit; break;
+                        case AZIMUTH:   unit = azimuthUnit; break;
+                        default: continue;
+                    }
+                    double value = Double.NaN;
+                    try {
+                        @SuppressWarnings("unchecked")                         
 // Because we catch ClassCastException.
+                        var p = (ParameterDescriptor<? extends Number>) desc;
+                        value = parameters.doubleValue(p, unit);
+                    } catch (ClassCastException | ParameterNotFoundException 
e) {
+                        if (isSameProjection) {
+                            warning(Resources.Keys.UnexpectedParameter_2, 
code, GeoKeys.name(key));
+                        }
+                    }
+                    verify(projection, value, key, unit);
                 }
             }
         }

Reply via email to