sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1792299 - in /sis/branches/JDK8: core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/ storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/
Date Sat, 22 Apr 2017 16:34:37 GMT
Author: desruisseaux
Date: Sat Apr 22 16:34:37 2017
New Revision: 1792299

URL: http://svn.apache.org/viewvc?rev=1792299&view=rev
Log:
Parsing of GeoTIFF files should be tolerance to duplicated map projection parameters.

Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java?rev=1792299&r1=1792298&r2=1792299&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
[UTF-8] Sat Apr 22 16:34:37 2017
@@ -406,6 +406,8 @@ public final class ReferencingUtilities
      * This method assumes that the identifiers of all parameters defined by that authority
are numeric.
      * Examples of authorities defining numeric parameters are EPSG and GeoTIFF.
      *
+     * <p>The map returned by this method is modifiable. Callers are free to add or
remove entries.</p>
+     *
      * @param  parameters  the parameters for which to get a mapping from identifiers to
names.
      * @param  authority   the authority defining the parameters.
      * @return mapping from parameter identifiers to parameter names defined by the given
authority.

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java?rev=1792299&r1=1792298&r2=1792299&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
[UTF-8] Sat Apr 22 16:34:37 2017
@@ -98,6 +98,12 @@ public final class Resources extends Ind
         public static final short IgnoredTag_1 = 7;
 
         /**
+         * Map projection parameter “{2}” will be ignored because its value ({3}) is
inconsistent with
+         * the “{0} = {1}” parameter.
+         */
+        public static final short InconsistentMapProjParameter_4 = 24;
+
+        /**
          * TIFF image “{0}” shall be either tiled or organized into strips.
          */
         public static final short InconsistentTileStrip_1 = 8;

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties?rev=1792299&r1=1792298&r2=1792299&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties
[ISO-8859-1] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties
[ISO-8859-1] Sat Apr 22 16:34:37 2017
@@ -26,6 +26,7 @@ DefaultValueForAttribute_2        = No v
 DitheringOrHalftoningApplied_2    = An ordered dither or halftone technique has been applied
to the image data. The dithering or halftoning matrix size is {0}\u00d7{1}.
 IgnoredTag_1                      = The \u201c{0}\u201d TIFF tag has been ignored.
 IgnoredGeoKeys_1                  = The following GeoTIFF keys have been ignored: {0}
+InconsistentMapProjParameter_4    = Map projection parameter \u201c{2}\u201d will be ignored
because its value ({3}) is inconsistent with the \u201c{0} = {1}\u201d parameter.
 InconsistentTileStrip_1           = TIFF image \u201c{0}\u201d shall be either tiled or organized
into strips.
 InvalidGeoValue_2                 = \u201c{1}\u201d is not a valid value for the \u201c{0}\u201d
GeoTIFF key.
 ListTooShort_3                    = TIFF tag \u201c{0}\u201d shall contain at least {1} values
but found only {2}.

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties?rev=1792299&r1=1792298&r2=1792299&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties
[ISO-8859-1] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties
[ISO-8859-1] Sat Apr 22 16:34:37 2017
@@ -31,6 +31,7 @@ DefaultValueForAttribute_2        = Aucu
 DitheringOrHalftoningApplied_2    = Un tramage ordonn\u00e9 ou une technique en demi-teinte
a \u00e9t\u00e9 appliqu\u00e9. La taille de la matrice de tramage est {0}\u00d7{1}.
 IgnoredTag_1                      = Le tag TIFF \u00ab\u202f{0}\u202f\u00bb a \u00e9t\u00e9
ignor\u00e9.
 IgnoredGeoKeys_1                  = Les cl\u00e9s GeoTIFF suivantes ont \u00e9t\u00e9 ignor\u00e9es\u2008:
{0}
+InconsistentMapProjParameter_4    = Le param\u00e8tre de projection cartographique \u00ab\u202f{2}\u202f\u00bb
sera ignor\u00e9 car sa valeur ({3}) est incoh\u00e9rente avec le param\u00e8tre \u00ab\u202f{0}
= {1}\u202f\u00bb.
 InconsistentTileStrip_1           = L\u2019image TIFF \u00ab\u202f{0}\u202f\u00bb doit \u00eatre
soit tuil\u00e9e, soit organis\u00e9e par bandes.
 InvalidGeoValue_2                 = La valeur \u00ab\u202f{1}\u202f\u00bb n\u2019est pas
valide pour la cl\u00e9 GeoTIFF \u00ab\u202f{0}\u202f\u00bb.
 ListTooShort_3                    = Le tag TIFF \u00ab\u202f{0}\u202f\u00bb devrait contenir
au moins {1} valeurs alors qu\u2019on n\u2019en a trouv\u00e9 que {2}.

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java?rev=1792299&r1=1792298&r2=1792299&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java
[UTF-8] Sat Apr 22 16:34:37 2017
@@ -71,7 +71,6 @@ import org.apache.sis.internal.util.Util
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.math.Vector;
 import org.apache.sis.measure.Units;
-import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
@@ -82,6 +81,7 @@ import org.apache.sis.referencing.crs.De
 import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
 import org.apache.sis.referencing.factory.GeodeticObjectFactory;
 import org.apache.sis.io.TableAppender;
+import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Characters;
@@ -1188,7 +1188,7 @@ final class CRSBuilder {
     }
 
     /**
-     * Returns the name at the given index if non-null. If that name is null, search for
a name is a sister element
+     * Returns the name at the given index if non-null. If that name is null, search for
a name in a sister element
      * (e.g. the datum name or the geographic CRS name). If none is found, returns {@code
null}.
      */
     private static String getOrDefault(final String[] names, int component) {
@@ -1364,6 +1364,51 @@ final class CRSBuilder {
     //////////////////////////////////////////////////////////////////////////////////////////////////
 
     /**
+     * Map projection parameters to be considered as aliases. This table is used for reading
GeoTIFF files
+     * that are not really well-formed, but for which we can reasonably guess what was the
producer intend
+     * and which parameters were confused. See {@link #aliases(Map)} for more explanation.
+     */
+    private static final short[][] PARAMETER_ALIASES = {
+        {GeoKeys.NatOriginLong, GeoKeys.FalseOriginLong,     GeoKeys.CenterLong},
+        {GeoKeys.NatOriginLat,  GeoKeys.FalseOriginLat,      GeoKeys.CenterLat},
+        {GeoKeys.FalseEasting,  GeoKeys.FalseOriginEasting,  GeoKeys.CenterEasting},
+        {GeoKeys.FalseNorthing, GeoKeys.FalseOriginNorthing, GeoKeys.CenterNorthing},
+        {GeoKeys.ScaleAtNatOrigin,                           GeoKeys.ScaleAtCenter}
+    };
+
+    /**
+     * Updates a mapping from GeoTIFF numerical identifiers to parameter names by adding
parameter aliases.
+     * This method adds to the given map some GeoTIFF keys to be considered synonymous to
an existing key.
+     * Those "synonymous" parameters are strictly speaking not for the map projection that
we are parsing,
+     * but it is common to see GeoTIFF files with "wrong" projection parameter codes. For
example:
+     *
+     * <ul>
+     *   <li>The {@code "CT_LambertConfConic_1SP"} projection uses a {@code "NatOriginLong"}
parameter.</li>
+     *   <li>The {@code "CT_LambertConfConic_2SP"} projection uses a {@code "FalseOriginLong"}
parameter.</li>
+     * </ul>
+     *
+     * but we sometime see {@code "NatOriginLong"} parameter used for the {@code "CT_LambertConfConic_2SP"}
projection.
+     * Semantically those two parameters are for two different things but mathematically
they are used in the same way.
+     * Those "synonymous" will be invisible to the user; the map projection that (s)he will
get uses the names defined
+     * in the descriptor (not in the GeoTIFF file).
+     */
+    private static void aliases(final Map<Integer,String> mapping) {
+        for (final short[] codes : PARAMETER_ALIASES) {
+            for (int i=0; i<codes.length; i++) {
+                final String name = mapping.get(Short.toUnsignedInt(codes[i]));
+                if (name != null) {
+                    for (int j=0; j<codes.length; j++) {
+                        if (j != i) {
+                            mapping.putIfAbsent(Short.toUnsignedInt(codes[j]), name);
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
      * Creates a projected CRS from an EPSG code or from user-defined parameters.
      * Some GeoTIFF values used by this method are:
      *
@@ -1473,11 +1518,13 @@ final class CRSBuilder {
                 final OperationMethod     method      = operationFactory().getOperationMethod(Constants.GEOTIFF
+ ':' + type);
                 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.
+                final Map<Short,Unit<?>>  deferred    = new HashMap<>();
   // Only unknown parameters.
                 final Iterator<Map.Entry<Short,Object>> it = geoKeys.entrySet().iterator();
                 while (it.hasNext()) {
                     final Unit<?> unit;
                     final Map.Entry<Short,?> entry = it.next();
-                    final short key = entry.getKey();
+                    final Short key = entry.getKey();
                     switch (GeoKeys.unitOf(key)) {
                         case GeoKeys.RATIO:   unit = Units.UNITY; break;
                         case GeoKeys.LINEAR:  unit = linearUnit;  break;
@@ -1485,21 +1532,52 @@ final class CRSBuilder {
                         case GeoKeys.AZIMUTH: unit = azimuthUnit; break;
                         default: continue;
                     }
-                    String paramName = toNames.get(Short.toUnsignedInt(key));
-                    if (paramName == null) {
-                        paramName = GeoKeys.name(key);
-                        throw new ParameterNotFoundException(reader.errors().getString(
-                                Errors.Keys.UnexpectedParameter_1, paramName), paramName);
-                    }
-                    final double value = ((Number) entry.getValue()).doubleValue();
+                    final Number value = (Number) entry.getValue();
                     it.remove();
-                    parameters.parameter(paramName).setValue(value, unit);
+                    final String paramName = toNames.get(Short.toUnsignedInt(key));
+                    if (paramName != null) {
+                        paramValues.put(paramName, value);
+                        parameters.parameter(paramName).setValue(value.doubleValue(), unit);
+                    } else {
+                        paramValues.put(key, value);
+                        deferred.put(key, unit);
+                    }
+                }
+                /*
+                 * At this point we finished to set all known map projection parameters.
Sometime GeoTIFF files
+                 * set the same parameter many times using different names as a safety for
GeoTIFF readers that
+                 * expect wrong parameters. If this is the case, verify that the parameter
values are consistent.
+                 * It is also possible that we found new parameters (actually parameters
using the wrong names).
+                 */
+                if (!deferred.isEmpty()) {
+                    aliases(toNames);
+                    for (final Map.Entry<Short,Unit<?>> entry : deferred.entrySet())
{
+                        final Short key = entry.getKey();
+                        String paramName = toNames.get(Short.toUnsignedInt(key));
+                        if (paramName == null) {
+                            paramName = GeoKeys.name(key);
+                            throw new ParameterNotFoundException(reader.errors().getString(
+                                    Errors.Keys.UnexpectedParameter_1, paramName), paramName);
+                        }
+                        final Number value  = paramValues.get(key);
+                        final Number actual = paramValues.putIfAbsent(paramName, value);
+                        if (actual == null) {
+                            parameters.parameter(paramName).setValue(value.doubleValue(),
entry.getValue());
+                        } else if (!actual.equals(value)) {
+                            warning(Resources.Keys.InconsistentMapProjParameter_4, paramName,
actual, GeoKeys.name(key), value);
+                        }
+                    }
                 }
                 final Conversion c = operationFactory().createDefiningConversion(properties(name),
method, parameters);
                 lastName = c.getName();
                 return c;
             }
             default: {
+                /*
+                 * Conversion defined by EPSG code. In principle we should just use the EPSG
code.
+                 * But if the file also defines the components, verify that those components
are
+                 * consistent with what we would expect for a conversion of the given EPSG
code.
+                 */
                 final Conversion projection = (Conversion) epsgFactory().createCoordinateOperation(String.valueOf(epsg));
                 verify(projection, angularUnit, linearUnit);
                 return projection;



Mime
View raw message