sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1772890 [1/2] - in /sis/branches/JDK8: core/sis-metadata/src/main/java/org/apache/sis/io/wkt/ core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ core/sis-referencing/src/main/java/org/apache/sis/referencing/ c...
Date Tue, 06 Dec 2016 13:27:06 GMT
Author: desruisseaux
Date: Tue Dec  6 13:27:05 2016
New Revision: 1772890

URL: http://svn.apache.org/viewvc?rev=1772890&view=rev
Log:
GeoTIFF CRSBuilder shall set map projection parameter values according the GeoKeys found in the file.
This require the addition of GeoTIFF parameter identifiers (in addition of EPSG identifiers) in projection providers.
Some cleaning of a few GeoTIFF metadata were applied as a side effect.

Added:
    sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoKeysTest.java   (with props)
Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertConformal2SP.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator1SP.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator2SP.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicB.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/RegionalMercator.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/EquirectangularTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoKeys.java
    sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoIdentifiers.java
    sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/test/suite/GeoTiffTestSuite.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
    sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/MetadataBuilderTest.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -294,7 +294,7 @@ public enum Convention {
      *   <tr><td>GEOTIFF</td>   <td>CT_Mercator</td></tr>
      * </table></div>
      *
-     * @return The organization, standard or project to look for when fetching Map Projection parameter names.
+     * @return the organization, standard or project to look for when fetching Map Projection parameter names.
      *
      * @see WKTFormat#getNameAuthority()
      * @see Citations#EPSG

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -782,7 +782,7 @@ public class Formatter implements Locali
         }
         if (showIDs) {
             Collection<? extends Identifier> identifiers = object.getIdentifiers();
-            if (identifiers != null) {  // Paranoiac check
+            if (identifiers != null) {                                                  // Paranoiac check
                 if (filterID) {
                     for (final Identifier id : identifiers) {
                         if (Citations.identifierMatches(authority, id.getAuthority())) {

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -66,7 +66,7 @@ import static java.lang.Math.*;
  * @author  John Grange
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
- * @version 0.6
+ * @version 0.8
  * @module
  *
  * @see <a href="http://www.remotesensing.org/geotiff/proj_list/equirectangular.html">Equirectangular on RemoteSensing.org</a>
@@ -125,24 +125,27 @@ public final class Equirectangular exten
 
         STANDARD_PARALLEL = createLatitude(builder
                 .addIdentifier("8823")
+                .addIdentifier(Citations.GEOTIFF, "3078")
                 .addName("Latitude of 1st standard parallel")
                 .addName(Citations.OGC,     Constants.STANDARD_PARALLEL_1)
                 .addName(Citations.ESRI,    "Standard_Parallel_1")
                 .addName(Citations.NETCDF,  Constants.STANDARD_PARALLEL)
-                .addName(Citations.GEOTIFF, "ProjStdParallel1")
+                .addName(Citations.GEOTIFF, "StdParallel1")
                 .addName(Citations.PROJ4,   "lat_ts"), false);
 
         LONGITUDE_OF_ORIGIN = createLongitude(builder
                 .addIdentifier("8802")
+                .addIdentifier(Citations.GEOTIFF, "3088")
                 .addName("Longitude of natural origin")
                 .addName(Citations.OGC,     Constants.CENTRAL_MERIDIAN)
                 .addName(Citations.ESRI,    "Central_Meridian")
                 .addName(Citations.NETCDF,  "longitude_of_projection_origin")
-                .addName(Citations.GEOTIFF, "ProjCenterLong")
+                .addName(Citations.GEOTIFF, "CenterLong")
                 .addName(Citations.PROJ4,   "lon_0"));
 
         FALSE_EASTING = createShift(builder
                 .addIdentifier("8806")
+                .addIdentifier(Citations.GEOTIFF, "3082")
                 .addName("False easting")
                 .addName(Citations.OGC,     Constants.FALSE_EASTING)
                 .addName(Citations.ESRI,    "False_Easting")
@@ -152,6 +155,7 @@ public final class Equirectangular exten
 
         FALSE_NORTHING = createShift(builder
                 .addIdentifier("8807")
+                .addIdentifier(Citations.GEOTIFF, "3083")
                 .addName("False northing")
                 .addName(Citations.OGC,     Constants.FALSE_NORTHING)
                 .addName(Citations.ESRI,    "False_Northing")
@@ -167,11 +171,12 @@ public final class Equirectangular exten
          */
         LATITUDE_OF_ORIGIN = createZeroConstant(builder     // Was used by EPSG:9823 (also EPSG:9842).
                 .addIdentifier("8801")
+                .addIdentifier(Citations.GEOTIFF, "3089")
                 .addName("Latitude of natural origin")
                 .addName(Citations.OGC,     Constants.LATITUDE_OF_ORIGIN)
                 .addName(Citations.ESRI,    "Latitude_Of_Origin")
                 .addName(Citations.NETCDF,  "latitude_of_projection_origin")
-                .addName(Citations.GEOTIFF, "ProjCenterLat")
+                .addName(Citations.GEOTIFF, "CenterLat")
                 .addName(Citations.PROJ4,   "lat_0")
                 .setRemarks(Resources.formatInternational(Resources.Keys.ConstantProjParameterValue_1, 0))
                 .setRequired(false));

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertConformal2SP.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertConformal2SP.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertConformal2SP.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LambertConformal2SP.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -30,7 +30,7 @@ import org.apache.sis.metadata.iso.citat
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Rueben Schulz (UBC)
  * @since   0.6
- * @version 0.6
+ * @version 0.8
  * @module
  *
  * @see <a href="http://www.remotesensing.org/geotiff/proj_list/lambert_conic_conformal_2sp.html">Lambert Conic Conformal 2SP on RemoteSensing.org</a>
@@ -107,10 +107,13 @@ public final class LambertConformal2SP e
          * NetCDF:  longitude_of_central_meridian
          * GeoTIFF: FalseOriginLong
          */
-        LONGITUDE_OF_FALSE_ORIGIN = createLongitude(
-                 rename(LambertConformal1SP.LONGITUDE_OF_ORIGIN, "8822", "Longitude of false origin", builder)
+        LONGITUDE_OF_FALSE_ORIGIN = createLongitude(builder
+                .addNamesAndIdentifiers(LambertConformal1SP.LONGITUDE_OF_ORIGIN)
+                .rename(Citations.EPSG, "Longitude of false origin")
                 .rename(Citations.NETCDF, "longitude_of_central_meridian")
-                .rename(Citations.GEOTIFF, "FalseOriginLong"));
+                .rename(Citations.GEOTIFF, "FalseOriginLong")
+                .replaceIdentifiers(Citations.EPSG, "8822")
+                .replaceIdentifiers(Citations.GEOTIFF, "3084"));
         /*
          * EPSG:    Latitude of 1st standard parallel
          * OGC:     standard_parallel_1
@@ -133,6 +136,7 @@ public final class LambertConformal2SP e
          */
         STANDARD_PARALLEL_2 = createMandatoryLatitude(builder
                 .addIdentifier("8824")
+                .addIdentifier(Citations.GEOTIFF, "3079")
                 .addName("Latitude of 2nd standard parallel")
                 .addName(Citations.OGC,     Constants.STANDARD_PARALLEL_2)
                 .addName(Citations.ESRI,    "Standard_Parallel_2")

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -39,7 +39,9 @@ import org.apache.sis.internal.util.Cons
 import org.apache.sis.measure.MeasurementRange;
 import org.apache.sis.measure.Units;
 import org.apache.sis.referencing.NamedIdentifier;
+import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.operation.projection.NormalizedProjection;
+import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.parameter.DefaultParameterDescriptor;
 import org.apache.sis.parameter.ParameterBuilder;
@@ -71,7 +73,7 @@ public abstract class MapProjection exte
      * All names known to Apache SIS for the <cite>semi-major</cite> parameter.
      * This parameter is mandatory and has no default value. The range of valid values is (0 … ∞).
      *
-     * <p>Some names for this parameter are {@code "semi_major"}, {@code "SemiMajor"} and {@code "a"}.</p>
+     * <p>Some names for this parameter are {@code "semi_major"}, {@code "SemiMajorAxis"} and {@code "a"}.</p>
      */
     public static final DefaultParameterDescriptor<Double> SEMI_MAJOR;
 
@@ -79,7 +81,7 @@ public abstract class MapProjection exte
      * All names known to Apache SIS for the <cite>semi-minor</cite> parameter.
      * This parameter is mandatory and has no default value. The range of valid values is (0 … ∞).
      *
-     * <p>Some names for this parameter are {@code "semi_minor"}, {@code "SemiMinor"} and {@code "b"}.</p>
+     * <p>Some names for this parameter are {@code "semi_minor"}, {@code "SemiMinorAxis"} and {@code "b"}.</p>
      */
     public static final DefaultParameterDescriptor<Double> SEMI_MINOR;
 
@@ -94,13 +96,14 @@ public abstract class MapProjection exte
         final GenericName[] aliases = {
             new NamedIdentifier(Citations.ESRI,    "Semi_Major"),
             new NamedIdentifier(Citations.NETCDF,  "semi_major_axis"),
-            new NamedIdentifier(Citations.GEOTIFF, "SemiMajor"),
+            new NamedIdentifier(Citations.GEOTIFF, "SemiMajorAxis"),
             new NamedIdentifier(Citations.PROJ4,   "a")
         };
         final Map<String,Object> properties = new HashMap<>(4);
-        properties.put(AUTHORITY_KEY, Citations.OGC);
-        properties.put(NAME_KEY,      Constants.SEMI_MAJOR);
-        properties.put(ALIAS_KEY,     aliases);
+        properties.put(AUTHORITY_KEY,  Citations.OGC);
+        properties.put(NAME_KEY,       Constants.SEMI_MAJOR);
+        properties.put(ALIAS_KEY,      aliases);
+        properties.put(IDENTIFIERS_KEY, new ImmutableIdentifier(Citations.GEOTIFF, null, "2057"));
         SEMI_MAJOR = new DefaultParameterDescriptor<>(properties, 1, 1, Double.class, valueDomain, null, null);
         /*
          * Change in-place the name and aliases (we do not need to create new objects)
@@ -109,8 +112,9 @@ public abstract class MapProjection exte
         properties.put(NAME_KEY, Constants.SEMI_MINOR);
         aliases[0] = new NamedIdentifier(Citations.ESRI,    "Semi_Minor");
         aliases[1] = new NamedIdentifier(Citations.NETCDF,  "semi_minor_axis");
-        aliases[2] = new NamedIdentifier(Citations.GEOTIFF, "SemiMinor");
+        aliases[2] = new NamedIdentifier(Citations.GEOTIFF, "SemiMinorAxis");
         aliases[3] = new NamedIdentifier(Citations.PROJ4,   "b");
+        properties.put(IDENTIFIERS_KEY, new ImmutableIdentifier(Citations.GEOTIFF, null, "2058"));
         SEMI_MINOR = new DefaultParameterDescriptor<>(properties, 1, 1, Double.class, valueDomain, null, null);
         /*
          * SIS-specific parameter for debugging purpose only.
@@ -244,25 +248,8 @@ public abstract class MapProjection exte
     }
 
     /**
-     * Rename the primary name and identifier of the given descriptor. Aliases are copied as-is.
-     *
-     * @param  template    the parameter from which to copy the aliases.
-     * @param  identifier  the new EPSG identifier.
-     * @param  name        the new EPSG name.
-     * @param  builder     an initially clean builder where to add the names.
-     * @return the given {@code builder}, for method call chaining.
-     *
-     * @since 0.8
-     */
-    static ParameterBuilder rename(final ParameterDescriptor<?> template, final String identifier, final String name,
-            final ParameterBuilder builder)
-    {
-        return exceptEPSG(template, builder.addIdentifier(identifier).addName(name));
-    }
-
-    /**
-     * Copies name, aliases and identifiers of the given {@code template}, except the alias of the given authority
-     * which is replaced by the alias of the same authority in {@code replacement}.
+     * Copies name, aliases and identifiers of the given {@code template}, except the alias and identifiers of the
+     * given authority which are replaced by the alias and identifiers of the same authority in {@code replacement}.
      *
      * @param  template     the parameter from which to copy names and identifiers.
      * @param  toRename     authority of the alias to rename.
@@ -275,11 +262,8 @@ public abstract class MapProjection exte
     static ParameterBuilder renameAlias(final ParameterDescriptor<Double> template, final Citation toRename,
             final ParameterDescriptor<Double> replacement, final ParameterBuilder builder)
     {
-        copyAliases(template, toRename, sameNameAs(toRename, replacement), builder.addName(template.getName()));
-        for (final Identifier id : template.getIdentifiers()) {
-            builder.addIdentifier(id);
-        }
-        return builder;
+        return copyAliases(template, toRename, sameNameAs(toRename, replacement),
+                IdentifiedObjects.getIdentifier(replacement, toRename), builder.addName(template.getName()));
     }
 
     /**
@@ -291,11 +275,12 @@ public abstract class MapProjection exte
      * @param  template     the parameter from which to copy the aliases.
      * @param  exclude      the authority of the alias to omit. Can not be EPSG.
      * @param  replacement  the alias to use instead of the omitted one, or {@code null} if none.
+     * @param  newCode      the identifier to use instead of the omitted one, or {@code null} if none.
      * @param  builder      where to add the aliases.
      * @return the given {@code builder}, for method call chaining.
      */
     private static ParameterBuilder copyAliases(final ParameterDescriptor<Double> template, final Citation exclude,
-            GenericName replacement, final ParameterBuilder builder)
+            GenericName replacement, Identifier newCode, final ParameterBuilder builder)
     {
         for (GenericName alias : template.getAlias()) {
             if (((Identifier) alias).getAuthority() == exclude) {
@@ -305,17 +290,23 @@ public abstract class MapProjection exte
             }
             builder.addName(alias);
         }
+        for (Identifier id : template.getIdentifiers()) {
+            if (id.getAuthority() == exclude) {
+                if (newCode == null) continue;
+                id = newCode;
+                newCode = null;
+            }
+            builder.addIdentifier(id);
+        }
         return builder;
     }
 
     /**
-     * Copies all aliases and identifiers, but using the alias specified by the given authority as the primary name.
-     * The old primary name (usually the EPSG name) is discarded. Identifier are <strong>not</strong> copied, which
-     * usually implies that only the EPSG identifier is ignored (because it is usually the only parameter identifier).
+     * Copies all aliases and all identifiers except EPSG, but using the alias specified by the given authority
+     * as the primary name. The old primary name (usually the EPSG name) is discarded.
      *
      * <p>This is a convenience method for defining the parameters of an ESRI-specific (or any other authority)
-     * projection using the EPSG parameters as template. Note that in the particular case where the desired
-     * authority is OGC, {@link #exceptEPSG(ParameterDescriptor, ParameterBuilder)} is more efficient.</p>
+     * projection using the EPSG parameters as template.</p>
      *
      * @param  template    the parameter from which to copy the names.
      * @param  authority   the authority to use for the primary name.
@@ -327,25 +318,7 @@ public abstract class MapProjection exte
     static ParameterBuilder alternativeAuthority(final ParameterDescriptor<Double> template,
             final Citation authority, final ParameterBuilder builder)
     {
-        return copyAliases(template, authority, null, builder.addName(sameNameAs(authority, template)));
-    }
-
-    /**
-     * Copies all names except the EPSG one from the given parameter into the builder.
-     * The EPSG information are presumed to be the primary name and the only identifier (this is not verified).
-     *
-     * <p>If this method is invoking with a "clean" builder, then the result is to promote the first alias as
-     * the primary name. The first alias is usually the OGC name.</p>
-     *
-     * @param  template  the parameter from which to copy the names.
-     * @param  builder   where to add the names.
-     * @return the given {@code builder}, for method call chaining.
-     */
-    static ParameterBuilder exceptEPSG(final ParameterDescriptor<?> template, final ParameterBuilder builder) {
-        for (final GenericName alias : template.getAlias()) {
-            builder.addName(alias);
-        }
-        return builder;
+        return copyAliases(template, authority, null, null, builder.addName(sameNameAs(authority, template)));
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator1SP.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator1SP.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator1SP.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator1SP.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -69,14 +69,17 @@ public final class Mercator1SP extends A
     static {
         final ParameterBuilder builder = builder();
         LATITUDE_OF_ORIGIN = createZeroConstant(builder.addNamesAndIdentifiers(Equirectangular.LATITUDE_OF_ORIGIN)
+                .replaceIdentifiers(Citations.GEOTIFF, "3081")
                 .rename(Citations.GEOTIFF, "NatOriginLat")
                 .setRemarks(Equirectangular.LATITUDE_OF_ORIGIN.getRemarks()));
 
         LONGITUDE_OF_ORIGIN = createLongitude(builder.addNamesAndIdentifiers(Equirectangular.LONGITUDE_OF_ORIGIN)
+                .replaceIdentifiers(Citations.GEOTIFF, "3080")
                 .rename(Citations.GEOTIFF, "NatOriginLong"));
 
         SCALE_FACTOR = createScale(builder
                 .addIdentifier("8805")
+                .addIdentifier(Citations.GEOTIFF, "3092")
                 .addName("Scale factor at natural origin")
                 .addName(Citations.OGC,     Constants.SCALE_FACTOR)
                 .addName(Citations.ESRI,    "Scale_Factor")

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator2SP.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator2SP.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator2SP.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator2SP.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -88,7 +88,11 @@ public final class Mercator2SP extends A
          * here would rather be at the standard parallel. We keep the OGC, ESRI and Proj.4 names because they are just
          * "scale_factor" or "k", which is vague enough for the purpose of this non-standard parameter.
          */
-        SCALE_FACTOR = createScale(exceptEPSG(Mercator1SP.SCALE_FACTOR, builder)
+        SCALE_FACTOR = createScale(builder
+                .addNamesAndIdentifiers(Mercator1SP.SCALE_FACTOR)
+                .replaceIdentifiers(Citations.EPSG,    (String[]) null)
+                .replaceIdentifiers(Citations.GEOTIFF, (String[]) null)
+                .rename(Citations.EPSG,    (String[]) null)
                 .rename(Citations.NETCDF,  (String[]) null)  // "scale_factor_at_projection_origin" is too specific.
                 .rename(Citations.GEOTIFF, (String[]) null)  // "ScaleAtNatOrigin" is too specific.
                 .setRemarks(remarks).setDeprecated(true));

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -77,6 +77,7 @@ public final class PolarStereographicA e
         final ParameterBuilder builder = builder();
         LONGITUDE_OF_ORIGIN = createLongitude(builder
                 .addNamesAndIdentifiers(ObliqueStereographic.LONGITUDE_OF_ORIGIN)
+                .replaceIdentifiers(Citations.GEOTIFF, "3095")
                 .rename(Citations.GEOTIFF, "StraightVertPoleLong"));
 
         PARAMETERS = builder

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicB.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicB.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicB.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicB.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -75,8 +75,10 @@ public final class PolarStereographicB e
     private static final ParameterDescriptorGroup PARAMETERS;
     static {
         final ParameterBuilder builder = builder();
-        LONGITUDE_OF_ORIGIN = createLongitude(
-                rename(PolarStereographicA.LONGITUDE_OF_ORIGIN, "8833", "Longitude of origin", builder));
+        LONGITUDE_OF_ORIGIN = createLongitude(builder
+                .addNamesAndIdentifiers(PolarStereographicA.LONGITUDE_OF_ORIGIN)
+                .rename(Citations.EPSG, "Longitude of origin")
+                .replaceIdentifiers(Citations.EPSG, "8833"));
 
         STANDARD_PARALLEL = createMandatoryLatitude(builder
                 .addIdentifier("8832").addName("Latitude of standard parallel")

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/RegionalMercator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/RegionalMercator.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/RegionalMercator.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/RegionalMercator.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -34,7 +34,7 @@ import org.apache.sis.parameter.Paramete
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
- * @version 0.6
+ * @version 0.8
  * @module
  */
 @XmlTransient
@@ -74,17 +74,26 @@ public class RegionalMercator extends Ab
     static {
         final ParameterBuilder builder = builder();
 
-        LATITUDE_OF_FALSE_ORIGIN = createLatitude(
-                 rename(Mercator1SP.LATITUDE_OF_ORIGIN, "8821", "Latitude of false origin", builder)
-                .rename(Citations.GEOTIFF, "FalseOriginLat"), false);
-
-        EASTING_AT_FALSE_ORIGIN = createShift(
-                 rename(FALSE_EASTING, "8826", "Easting at false origin", builder)
-                .rename(Citations.GEOTIFF, "FalseOriginEasting"));
-
-        NORTHING_AT_FALSE_ORIGIN = createShift(
-                 rename(FALSE_NORTHING, "8827", "Northing at false origin", builder)
-                .rename(Citations.GEOTIFF, "FalseOriginNorthing"));
+        LATITUDE_OF_FALSE_ORIGIN = createLatitude(builder
+                .addNamesAndIdentifiers(Mercator1SP.LATITUDE_OF_ORIGIN)
+                .rename(Citations.EPSG, "Latitude of false origin")
+                .rename(Citations.GEOTIFF, "FalseOriginLat")
+                .replaceIdentifiers(Citations.EPSG, "8821")
+                .replaceIdentifiers(Citations.GEOTIFF, "3085"), false);
+
+        EASTING_AT_FALSE_ORIGIN = createShift(builder
+                .addNamesAndIdentifiers(FALSE_EASTING)
+                .rename(Citations.EPSG, "Easting at false origin")
+                .rename(Citations.GEOTIFF, "FalseOriginEasting")
+                .replaceIdentifiers(Citations.EPSG, "8826")
+                .replaceIdentifiers(Citations.GEOTIFF, "3086"));
+
+        NORTHING_AT_FALSE_ORIGIN = createShift(builder
+                .addNamesAndIdentifiers(FALSE_NORTHING)
+                .rename(Citations.EPSG, "Northing at false origin")
+                .rename(Citations.GEOTIFF, "FalseOriginNorthing")
+                .replaceIdentifiers(Citations.EPSG, "8827")
+                .replaceIdentifiers(Citations.GEOTIFF, "3087"));
 
         PARAMETERS = builder
                 .addIdentifier(IDENTIFIER)

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -172,7 +172,7 @@ import static org.apache.sis.util.Argume
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.8
  * @module
  */
 public abstract class Builder<B extends Builder<B>> {
@@ -261,7 +261,7 @@ public abstract class Builder<B extends
      * The properties recognized by this constructor are documented
      * {@linkplain IdentifiedObjects#getProperties(IdentifiedObject, String...) here}.
      *
-     * @param object The identified object from which to inherit properties, or {@code null}.
+     * @param object  the identified object from which to inherit properties, or {@code null}.
      *
      * @since 0.6
      */
@@ -315,6 +315,37 @@ public abstract class Builder<B extends
     }
 
     /**
+     * Creates an identifier for the given authority. If and only if the given authority is the default one,
+     * then the new identifier will also contain the user-supplied code space and version (if any).
+     * The new identifier will be marked as deprecated if {@link #isDeprecated()} returns {@code true}.
+     */
+    private Identifier createIdentifier(final Citation authority, final String identifier) {
+        final String codeSpace;
+        final String version;
+        if (authority == getAuthority()) {
+            codeSpace  = getCodeSpace();
+            version    = getVersion();
+        } else {
+            // Do not use the version information since it applies to the default authority rather than the given one.
+            codeSpace = Citations.getCodeSpace(authority);
+            version   = null;
+        }
+        return createIdentifier(authority, codeSpace, identifier, version);
+    }
+
+    /**
+     * Creates an identifier for the given authority, code space and version.
+     * The new identifier will be marked as deprecated if {@link #isDeprecated()} returns {@code true}.
+     */
+    private Identifier createIdentifier(final Citation authority, final String codeSpace, final String identifier, final String version) {
+        if (isDeprecated()) {
+            return new DeprecatedCode(authority, codeSpace, identifier, version, null, getRemarks());
+        } else {
+            return new ImmutableIdentifier(authority, codeSpace, identifier, version, getDescription());
+        }
+    }
+
+    /**
      * Converts the given name into an identifier. Note that {@link NamedIdentifier}
      * implements both {@link GenericName} and {@link Identifier} interfaces.
      */
@@ -327,8 +358,8 @@ public abstract class Builder<B extends
      * is needed for all keys defined in the {@link Identifier} interface. This check is not needed for other keys,
      * so callers do not need to invoke this method for other keys.
      *
-     * @param  key The key of the property to set.
-     * @param  value The value to set.
+     * @param  key    the key of the property to set.
+     * @param  value  the value to set.
      * @return {@code true} if the property changed as a result of this method call.
      * @throws IllegalStateException if a new value is specified in a phase where the value can not be changed.
      */
@@ -351,7 +382,7 @@ public abstract class Builder<B extends
      * Returns the value of the first argument given by the last call to {@link #setCodeSpace(Citation, String)},
      * or {@code null} if none. The default value is {@code null}.
      *
-     * @return The citation specified by the last call to {@code setCodeSpace(…)}, or {@code null} if none.
+     * @return the citation specified by the last call to {@code setCodeSpace(…)}, or {@code null} if none.
      *
      * @since 0.6
      */
@@ -363,7 +394,7 @@ public abstract class Builder<B extends
      * Returns the value of the last argument given by the last call to {@link #setCodeSpace(Citation, String)},
      * or {@code null} if none. The default value is {@code null}.
      *
-     * @return The string specified by the last call to {@code setCodeSpace(…)}, or {@code null} if none.
+     * @return the string specified by the last call to {@code setCodeSpace(…)}, or {@code null} if none.
      *
      * @since 0.6
      */
@@ -390,8 +421,8 @@ public abstract class Builder<B extends
      * <p><b>Lifetime:</b>
      * this property is kept unchanged until this {@code setCodeSpace(…)} method is invoked again.</p>
      *
-     * @param  authority Bibliographic reference to the authority defining the codes, or {@code null} if none.
-     * @param  codespace The {@code IdentifiedObject} codespace, or {@code null} for inferring it from the authority.
+     * @param  authority  bibliographic reference to the authority defining the codes, or {@code null} if none.
+     * @param  codespace  the {@code IdentifiedObject} codespace, or {@code null} for inferring it from the authority.
      * @return {@code this}, for method call chaining.
      * @throws IllegalStateException if {@code addName(…)} or {@code addIdentifier(…)} has been invoked at least
      *         once since builder construction or since the last call to a {@code createXXX(…)} method.
@@ -411,7 +442,7 @@ public abstract class Builder<B extends
      * Returns the value given by the last call to {@link #setVersion(String)}, or {@code null} if none.
      * The default value is {@code null}.
      *
-     * @return The value specified by the last call to {@code setVersion(…)}, or {@code null} if none.
+     * @return the value specified by the last call to {@code setVersion(…)}, or {@code null} if none.
      *
      * @since 0.6
      */
@@ -431,7 +462,7 @@ public abstract class Builder<B extends
      * <p><b>Lifetime:</b>
      * this property is kept unchanged until this {@code setVersion(…)} method is invoked again.</p>
      *
-     * @param  version The version of code definitions, or {@code null} if none.
+     * @param  version  the version of code definitions, or {@code null} if none.
      * @return {@code this}, for method call chaining.
      * @throws IllegalStateException if {@code addName(…)} or {@code addIdentifier(…)} has been invoked at least
      *         once since builder construction or since the last call to a {@code createXXX(…)} method.
@@ -464,7 +495,7 @@ public abstract class Builder<B extends
      * <p><b>Lifetime:</b>
      * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  name The {@code IdentifiedObject} name as a {@link String} or {@link InternationalString} instance.
+     * @param  name  the {@code IdentifiedObject} name as a {@link String} or {@link InternationalString} instance.
      * @return {@code this}, for method call chaining.
      */
     public B addName(final CharSequence name) {
@@ -500,8 +531,8 @@ public abstract class Builder<B extends
      * <p><b>Lifetime:</b>
      * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  authority Bibliographic reference to the authority defining the codes, or {@code null} if none.
-     * @param  name The {@code IdentifiedObject} alias as a name in the namespace of the given authority.
+     * @param  authority  bibliographic reference to the authority defining the codes, or {@code null} if none.
+     * @param  name       the {@code IdentifiedObject} alias as a name in the namespace of the given authority.
      * @return {@code this}, for method call chaining.
      *
      * @see #addIdentifier(Citation, String)
@@ -547,7 +578,7 @@ public abstract class Builder<B extends
      * <p><b>Lifetime:</b>
      * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  name The {@code IdentifiedObject} name as an identifier.
+     * @param  name  the {@code IdentifiedObject} name as an identifier.
      * @return {@code this}, for method call chaining.
      */
     public B addName(final Identifier name) {
@@ -573,7 +604,7 @@ public abstract class Builder<B extends
      * <p><b>Lifetime:</b>
      * the name and all aliases are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  name The {@code IdentifiedObject} name as an identifier.
+     * @param  name  the {@code IdentifiedObject} name as an identifier.
      * @return {@code this}, for method call chaining.
      */
     public B addName(final GenericName name) {
@@ -602,12 +633,12 @@ public abstract class Builder<B extends
      * <p><b>Lifetime:</b>
      * all identifiers are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  identifier The {@code IdentifiedObject} identifier.
+     * @param  identifier  the {@code IdentifiedObject} identifier.
      * @return {@code this}, for method call chaining.
      */
     public B addIdentifier(final String identifier) {
         ensureNonNull("identifier", identifier);
-        addIdentifier(getAuthority(), getCodeSpace(), identifier, getVersion());
+        identifiers.add(createIdentifier(getAuthority(), getCodeSpace(), identifier, getVersion()));
         return self();
     }
 
@@ -618,42 +649,19 @@ public abstract class Builder<B extends
      * <p><b>Lifetime:</b>
      * all identifiers are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  authority  Bibliographic reference to the authority defining the codes, or {@code null} if none.
-     * @param  identifier The {@code IdentifiedObject} identifier as a code in the namespace of the given authority.
+     * @param  authority   bibliographic reference to the authority defining the codes, or {@code null} if none.
+     * @param  identifier  the {@code IdentifiedObject} identifier as a code in the namespace of the given authority.
      * @return {@code this}, for method call chaining.
      *
      * @see #addName(Citation, CharSequence)
      */
     public B addIdentifier(final Citation authority, final String identifier) {
         ensureNonNull("identifier", identifier);
-        final String codeSpace;
-        final String version;
-        if (authority == getAuthority()) {
-            codeSpace  = getCodeSpace();
-            version    = getVersion();
-        } else {
-            // Do not use the version information since it applies to the default authority rather than the given one.
-            codeSpace = Citations.getCodeSpace(authority);
-            version   = null;
-        }
-        addIdentifier(authority, codeSpace, identifier, version);
+        identifiers.add(createIdentifier(authority, identifier));
         return self();
     }
 
     /**
-     * Implementation of {@link #addIdentifier(String)} and {@link #addIdentifier(Citation, String)}.
-     */
-    private void addIdentifier(final Citation authority, final String codeSpace, final String identifier, final String version) {
-        final Identifier id;
-        if (isDeprecated()) {
-            id = new DeprecatedCode(authority, codeSpace, identifier, version, null, getRemarks());
-        } else {
-            id = new ImmutableIdentifier(authority, codeSpace, identifier, version, getDescription());
-        }
-        identifiers.add(id);
-    }
-
-    /**
      * Adds an {@code IdentifiedObject} identifier fully specified by the given identifier.
      * This method ignores the authority, {@linkplain #setCodeSpace(Citation, String) code space},
      * {@linkplain #setVersion(String) version} and {@linkplain #setDescription(CharSequence) description}
@@ -662,7 +670,7 @@ public abstract class Builder<B extends
      * <p><b>Lifetime:</b>
      * all identifiers are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  identifier The {@code IdentifiedObject} identifier.
+     * @param  identifier  the {@code IdentifiedObject} identifier.
      * @return {@code this}, for method call chaining.
      */
     public B addIdentifier(final Identifier identifier) {
@@ -688,7 +696,7 @@ public abstract class Builder<B extends
      * <p>This is a convenience method for using an existing object as a template, before to modify
      * some names by calls to {@link #rename(Citation, CharSequence[])}.</p>
      *
-     * @param  object The object from which to copy the references to names and identifiers.
+     * @param  object  the object from which to copy the references to names and identifiers.
      * @return {@code this}, for method call chaining.
      *
      * @since 0.6
@@ -731,9 +739,12 @@ public abstract class Builder<B extends
      *   </li>
      * </ul>
      *
-     * @param  authority The authority of the names to replaces.
-     * @param  replacements The new local parts for the names to replace,
-     *         or {@code null} for removing all identifiers associated to the given authority.
+     * This method could also be understood as a {@code setNames(Citation, ...)} method, except that it modifies
+     * only the names associated to the given authority and preserves the same order than previous names.
+     *
+     * @param  authority     the authority of the names to replaces.
+     * @param  replacements  the new local parts for the names to replace,
+     *         or {@code null} or an empty array for removing all names associated to the given authority.
      * @return {@code this}, for method call chaining.
      *
      * @since 0.6
@@ -809,6 +820,63 @@ public abstract class Builder<B extends
     }
 
     /**
+     * Replaces the identifiers associated to the given authority by the given new identifiers.
+     * More specifically:
+     *
+     * <ul>
+     *   <li>The first occurrence of an identifier associated to {@code authority} will be replaced by
+     *       a new identifier with the same authority and the code defined by {@code replacements[0]}.</li>
+     *   <li>The second occurrence of an identifier associated to {@code authority} will be replaced by a
+     *       new identifier with the same authority and the local part defined by {@code replacements[1]}.</li>
+     *   <li><i>etc.</i> until one of the following conditions is meet:
+     *     <ul>
+     *       <li>There is no more identifier associated to the given authority in this {@code Builder}, in which case
+     *           new identifiers are inserted for all remaining elements in the {@code replacements} array.</li>
+     *       <li>There is no more elements in the {@code replacements} array, in which case all remaining
+     *           identifiers associated to the given authority in this {@code Builder} are removed.</li>
+     *     </ul>
+     *   </li>
+     * </ul>
+     *
+     * This method could also be understood as a {@code setIdentifiers(Citation, ...)} method, except that it modifies
+     * only the identifiers associated to the given authority and preserves the same order than previous identifiers.
+     *
+     * @param  authority     the authority of the names to replaces.
+     * @param  replacements  the new local parts for the names to replace,
+     *         or {@code null} or an empty array for removing all names associated to the given authority.
+     * @return {@code this}, for method call chaining.
+     *
+     * @since 0.8
+     */
+    public B replaceIdentifiers(final Citation authority, final String... replacements) {
+        ensureNonNull("authority", authority);
+        final int length = (replacements != null) ? replacements.length : 0;
+        int next = 0;
+        int insertAt = identifiers.size();
+        for (int i = 0; i < identifiers.size(); i++) {
+            final Identifier old = identifiers.get(i);
+            if (authority.equals(old.getAuthority())) {
+                if (next < length) {
+                    final String code;
+                    ensureNonNullElement("replacements", next, code = replacements[next++]);
+                    if (!code.equals(old.getCode())) {
+                        identifiers.set(i, createIdentifier(authority, code));
+                        insertAt = i + 1;
+                    }
+                } else {
+                    identifiers.remove(i--);
+                }
+            }
+        }
+        while (next < length) {
+            final String code;
+            ensureNonNullElement("replacements", next, code = replacements[next++]);
+            identifiers.add(insertAt++, createIdentifier(authority, code));
+        }
+        return self();
+    }
+
+    /**
      * Returns the parameter description specified by the last call to {@link #setDescription(CharSequence)},
      * or {@code null} if none.
      */
@@ -837,7 +905,7 @@ public abstract class Builder<B extends
      * previous descriptions are discarded by calls to {@code setDescription(…)}.
      * Descriptions are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  description The description as a {@link String} or {@link InternationalString} instance, or {@code null} if none.
+     * @param  description  the description as a {@link String} or {@link InternationalString} instance, or {@code null} if none.
      * @return {@code this}, for method call chaining.
      *
      * @see ImmutableIdentifier#getDescription()
@@ -867,7 +935,7 @@ public abstract class Builder<B extends
      * previous remarks are discarded by calls to {@code setRemarks(…)}.
      * Remarks are cleared after a {@code createXXX(…)} method has been invoked.</p>
      *
-     * @param  remarks The remarks as a {@link String} or {@link InternationalString} instance, or {@code null} if none.
+     * @param  remarks  the remarks as a {@link String} or {@link InternationalString} instance, or {@code null} if none.
      * @return {@code this}, for method call chaining.
      */
     public B setRemarks(final CharSequence remarks) {

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -236,7 +236,7 @@ public final strictfp class DefaultProje
 
     /**
      * Tests WKT formatting in "internal" mode.
-     * This mode is similar to WKT 2 but shall include the axes of the base CRS.
+     * This mode is similar to WKT 2 but shall include the axes of the base CRS and more parameter identifiers.
      *
      * @throws FactoryException if the CRS creation failed.
      */
@@ -258,11 +258,11 @@ public final strictfp class DefaultProje
                 "      Unit[“grad”, 0.015707963267948967, Id[“EPSG”, 9105]]],\n" +
                 "  Conversion[“Lambert zone II”,\n" +
                 "    Method[“Lambert Conic Conformal (1SP)”, Id[“EPSG”, 9801], Id[“GeoTIFF”, 9]],\n" +
-                "    Parameter[“Latitude of natural origin”, 52.0, Id[“EPSG”, 8801]],\n" +
-                "    Parameter[“Longitude of natural origin”, 0.0, Id[“EPSG”, 8802]],\n" +
-                "    Parameter[“Scale factor at natural origin”, 0.99987742, Id[“EPSG”, 8805]],\n" +
-                "    Parameter[“False easting”, 600000.0, Id[“EPSG”, 8806]],\n" +
-                "    Parameter[“False northing”, 2200000.0, Id[“EPSG”, 8807]]],\n" +
+                "    Parameter[“Latitude of natural origin”, 52.0, Id[“EPSG”, 8801], Id[“GeoTIFF”, 3081]],\n" +
+                "    Parameter[“Longitude of natural origin”, 0.0, Id[“EPSG”, 8802], Id[“GeoTIFF”, 3080]],\n" +
+                "    Parameter[“Scale factor at natural origin”, 0.99987742, Id[“EPSG”, 8805], Id[“GeoTIFF”, 3092]],\n" +
+                "    Parameter[“False easting”, 600000.0, Id[“EPSG”, 8806], Id[“GeoTIFF”, 3082]],\n" +
+                "    Parameter[“False northing”, 2200000.0, Id[“EPSG”, 8807], Id[“GeoTIFF”, 3083]]],\n" +
                 "  CS[Cartesian, 2],\n" +
                 "    Axis[“Easting (E)”, east],\n" +
                 "    Axis[“Northing (N)”, north],\n" +

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/EquirectangularTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/EquirectangularTest.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/EquirectangularTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/EquirectangularTest.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -71,11 +71,16 @@ public final strictfp class Equirectangu
                 "PARAM_MT[“Equirectangular”,\n" +
                 "  PARAMETER[“semi_major”, 6371007.0],\n" +
                 "  PARAMETER[“semi_minor”, 6371007.0]]");
-
+        /*
+         * MathTransforms are not defined in WKT 2, so the following WKTs do not exist in standards.
+         * Since the semi-major and semi-minor parameters do not have EPSG codes, the ID[…] elements
+         * below show whatever identifier come first for each parameter (currently GeoTIFF identifiers,
+         * but the authority may change in any future SIS version).
+         */
         ReferencingAssert.assertWktEquals(Convention.WKT2,
                 "PARAM_MT[“Equidistant Cylindrical (Spherical)”,\n" +
-                "  PARAMETER[“semi_major”, 6371007.0, LENGTHUNIT[“metre”, 1]],\n" +
-                "  PARAMETER[“semi_minor”, 6371007.0, LENGTHUNIT[“metre”, 1]]]", transform);
+                "  PARAMETER[“semi_major”, 6371007.0, LENGTHUNIT[“metre”, 1], ID[“GeoTIFF”, 2057]],\n" +
+                "  PARAMETER[“semi_minor”, 6371007.0, LENGTHUNIT[“metre”, 1], ID[“GeoTIFF”, 2058]]]", transform);
 
         ReferencingAssert.assertWktEquals(Convention.WKT2_SIMPLIFIED,
                 "Param_MT[“Equidistant Cylindrical (Spherical)”,\n" +

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -120,7 +120,7 @@ public abstract strictfp class MathTrans
      * {@link org.opengis.test.ImplementationDetails#configuration(Factory[])} in order to decide
      * which tests should be enabled.
      *
-     * @param factories The factories to be used by the test.
+     * @param factories  the factories to be used by the test.
      */
     protected MathTransformTestCase(final Factory... factories) {
         super(factories);
@@ -157,10 +157,10 @@ public abstract strictfp class MathTrans
      * The SIS implementation ensures that longitude values are contained in the ±180° range,
      * applying 360° shifts if needed.
      *
-     * @param expected The expected ordinate value provided by the test case.
-     * @param actual   The ordinate value computed by the {@linkplain #transform transform} being tested.
-     * @param mode     Indicates if the coordinates being compared are the result of a direct
-     *                 or inverse transform, or if strict equality is requested.
+     * @param  expected  the expected ordinate value provided by the test case.
+     * @param  actual    the ordinate value computed by the {@linkplain #transform transform} being tested.
+     * @param  mode      indicates if the coordinates being compared are the result of a direct
+     *                   or inverse transform, or if strict equality is requested.
      */
     @Override
     protected final void normalize(final DirectPosition expected, final DirectPosition actual, final CalculationType mode) {
@@ -175,7 +175,7 @@ public abstract strictfp class MathTrans
      * Returns a name for the current math transform. This method is used only for reporting errors.
      * This information is not reliable for the actual tests as the names may not be stable.
      *
-     * @return A name for the current math transform.
+     * @return a name for the current math transform.
      */
     @Debug
     private String getName() {
@@ -227,8 +227,8 @@ public abstract strictfp class MathTrans
      *
      * <p>This method verifies also the consistency of {@code MathTransform.transform(…)} method variants.</p>
      *
-     * @param  coordinates The coordinate points to transform.
-     * @param  expected The expect result of the transformation, or
+     * @param  coordinates  the coordinate points to transform.
+     * @param  expected     the expect result of the transformation, or
      *         {@code null} if {@code coordinates} is expected to be null.
      * @throws TransformException if the transformation failed.
      */
@@ -282,9 +282,9 @@ public abstract strictfp class MathTrans
      * This method does not {@linkplain #validate() validate} the transform; it is caller responsibility
      * to validate if desired.
      *
-     * @param  domain The domain of the numbers to be generated.
-     * @param  randomSeed The seed for the random number generator, or 0 for choosing a random seed.
-     * @throws TransformException If a conversion, transformation or derivative failed.
+     * @param  domain      the domain of the numbers to be generated.
+     * @param  randomSeed  the seed for the random number generator, or 0 for choosing a random seed.
+     * @throws TransformException if a conversion, transformation or derivative failed.
      *
      * @since 0.6
      */
@@ -311,9 +311,9 @@ public abstract strictfp class MathTrans
     /**
      * Generates random numbers that can be used for the current transform.
      *
-     * @param  domain  The domain of the numbers to be generated.
-     * @param  propNaN Approximative percentage of NaN values as a fraction between 0 and 1, or 0 if none.
-     * @return Random  coordinates in the given domain.
+     * @param  domain   the domain of the numbers to be generated.
+     * @param  propNaN  approximative percentage of NaN values as a fraction between 0 and 1, or 0 if none.
+     * @return random coordinates in the given domain.
      */
     final double[] generateRandomCoordinates(final CoordinateDomain domain, final float propNaN) {
         assertNotNull("The 'transform' field shall be assigned a value.", transform);
@@ -332,11 +332,11 @@ public abstract strictfp class MathTrans
      * This method can check the descriptor separately, for easier isolation of mismatch in case of failure.
      *
      * @param descriptor
-     *          The expected parameter descriptor, or {@code null} for bypassing this check.
+     *          the expected parameter descriptor, or {@code null} for bypassing this check.
      *          The descriptor is required to be strictly the same instance, since Apache SIS
      *          implementation returns constant values.
      * @param values
-     *          The expected parameter values, or {@code null} for bypassing this check.
+     *          the expected parameter values, or {@code null} for bypassing this check.
      *          Floating points values are compared in the units of the expected value,
      *          tolerating a difference up to the {@linkplain #tolerance(double) tolerance threshold}.
      */
@@ -355,8 +355,9 @@ public abstract strictfp class MathTrans
 
     /**
      * Asserts that the current {@linkplain #transform transform} produces the given WKT.
+     * This method uses the WKT 1 format, since {@code MathTransform}s are not defined in WKT 2.
      *
-     * @param expected The expected WKT.
+     * @param  expected  the expected WKT.
      *
      * @see #printInternalWKT()
      */
@@ -367,8 +368,9 @@ public abstract strictfp class MathTrans
 
     /**
      * Asserts that the current {@linkplain #transform transform} produces a WKT matching the given regular expression.
+     * This method uses the WKT 1 format, since {@code MathTransform}s are not defined in WKT 2.
      *
-     * @param expected A regular expression for the expected WKT.
+     * @param  expected  a regular expression for the expected WKT.
      *
      * @see #printInternalWKT()
      *
@@ -382,7 +384,7 @@ public abstract strictfp class MathTrans
     /**
      * Asserts that the current {@linkplain #transform transform} produces the given internal WKT.
      *
-     * @param expected The expected internal WKT.
+     * @param  expected  the expected internal WKT.
      *
      * @since 0.7
      */
@@ -395,7 +397,7 @@ public abstract strictfp class MathTrans
      * Asserts that the current {@linkplain #transform transform} produces an internal WKT
      * matching the given regular expression.
      *
-     * @param expected A regular expression for the expected internal WKT.
+     * @param  expected  a regular expression for the expected internal WKT.
      *
      * @since 0.7
      */

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=1772890&r1=1772889&r2=1772890&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] Tue Dec  6 13:27:05 2016
@@ -18,6 +18,7 @@ package org.apache.sis.storage.geotiff;
 
 import java.util.Map;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Collections;
 import java.util.StringJoiner;
 import java.util.logging.Level;
@@ -136,6 +137,11 @@ final class CRSBuilder {
     private static final int ENTRY_LENGTH = 4;
 
     /**
+     * The character used as a separator in {@link String} multi-values.
+     */
+    private static final char SEPARATOR = '|';
+
+    /**
      * Index where to store the name of the geodetic CRS, the datum, the ellipsoid and the prime meridian.
      * The GeoTIFF specification has only one key, {@link GeoKeys#GeogCitation}, for the geographic CRS and
      * its components. But some GeoTIFF files encode the names of all components in the value associated to
@@ -642,9 +648,11 @@ final class CRSBuilder {
                         missingValue(key);
                         continue;
                     }
-                    if (count != 0 && asciiParameters.charAt(upper - 1) == '|') {
+                    upper = CharSequences.skipTrailingWhitespaces(asciiParameters, valueOffset, upper);
+                    while (upper > valueOffset && asciiParameters.charAt(upper - 1) == SEPARATOR) {
                         upper--;    // Skip trailing pipe, interpreted as C/C++ NUL character.
                     }
+                    // Use String.trim() for skipping C/C++ NUL character in addition of whitespaces.
                     final String s = asciiParameters.substring(valueOffset, upper).trim();
                     if (s.isEmpty()) continue;
                     value = s;
@@ -669,7 +677,10 @@ final class CRSBuilder {
         switch (crsType) {
             case GeoCodes.undefined:           return null;
             case GeoCodes.ModelTypeProjected:  return createProjectedCRS();
-            case GeoCodes.ModelTypeGeographic: return createGeographicCRS(true);
+            case GeoCodes.ModelTypeGeographic: {
+                return createGeographicCRS(true,
+                        createUnit(GeoKeys.AngularUnits, GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE));
+            }
             case GeoCodes.ModelTypeGeocentric: // TODO
             default: {
                 warning(Resources.Keys.UnsupportedCoordinateSystemKind_1, crsType);
@@ -694,16 +705,13 @@ final class CRSBuilder {
     final void complete(final MetadataBuilder metadata) {
         /*
          * ASCII reference to published documentation on the overall configuration of the GeoTIFF file.
+         * Often the projected CRS name, despite GeoKeys.PCSCitation being already for that purpose.
          * Checked first because this code is unlikely to throw an exception, while other parsings may
          * interrupt this method with an exception.
          */
         final String title = getAsString(GeoKeys.Citation);
         if (title != null) {
-            if (!metadata.hasTitle()) {
-                metadata.addTitle(title);
-            } else {
-                metadata.setGridToCRS(title);
-            }
+            metadata.setGridToCRS(title);
         }
         /*
          * Whether the pixel value is thought of as filling the cell area or is considered as point measurements at
@@ -788,6 +796,7 @@ final class CRSBuilder {
                 return defaultValue;
             }
             case GeoCodes.userDefined: {
+                if (scaleKey == 0) return defaultValue;
                 return defaultValue.getSystemUnit().multiply(getMandatoryDouble(scaleKey));
             }
             default: {
@@ -797,12 +806,14 @@ final class CRSBuilder {
                  * is consistent with what we would expect for a unit of the given EPSG code.
                  */
                 final Unit<Q> unit = epsgFactory().createUnit(String.valueOf(epsg)).asType(quantity);
-                final double scale = getAsDouble(scaleKey);
-                if (!Double.isNaN(scale)) {
-                    final double expected = unit.getConverterTo(defaultValue.getSystemUnit()).convert(1d);
-                    if (Math.abs(expected - scale) > expected * Numerics.COMPARISON_THRESHOLD) {
-                        warning(Resources.Keys.NotTheEpsgValue_5, (Constants.EPSG + ':') + epsg,
-                                expected, GeoKeys.name(scaleKey), scale, "");
+                if (scaleKey != 0) {
+                    final double scale = getAsDouble(scaleKey);
+                    if (!Double.isNaN(scale)) {
+                        final double expected = unit.getConverterTo(defaultValue.getSystemUnit()).convert(1d);
+                        if (Math.abs(expected - scale) > expected * Numerics.COMPARISON_THRESHOLD) {
+                            warning(Resources.Keys.NotTheEpsgValue_5, (Constants.EPSG + ':') + epsg,
+                                    expected, GeoKeys.name(scaleKey), scale, "");
+                        }
                     }
                 }
                 return unit;
@@ -1065,7 +1076,7 @@ final class CRSBuilder {
      */
     static String[] splitName(final String name) {
         final String[] names = new String[GCRS + 1];
-        final String[] components = (String[]) CharSequences.split(name, '|');
+        final String[] components = (String[]) CharSequences.split(name, SEPARATOR);
         switch (components.length) {
             case 0: break;
             case 1: names[GCRS] = name; break;
@@ -1132,6 +1143,7 @@ final class CRSBuilder {
      * </ul>
      *
      * @param  rightHanded  whether to force longitude before latitude axis.
+     * @param  angularUnit  the angular unit of the latitude and longitude values.
      * @throws NoSuchElementException if a mandatory value is missing.
      * @throws NumberFormatException if a numeric value was stored as a string and can not be parsed.
      * @throws ClassCastException if an object defined by an EPSG code is not of the expected type.
@@ -1139,7 +1151,7 @@ final class CRSBuilder {
      *
      * @see #createGeodeticDatum(String, Unit, Unit)
      */
-    private GeographicCRS createGeographicCRS(final boolean rightHanded) throws FactoryException {
+    private GeographicCRS createGeographicCRS(final boolean rightHanded, final Unit<Angle> angularUnit) throws FactoryException {
         final int epsg = getAsInteger(GeoKeys.GeographicType);
         switch (epsg) {
             case GeoCodes.undefined: {
@@ -1152,8 +1164,7 @@ final class CRSBuilder {
                  */
                 final String[] names = splitName(getAsString(GeoKeys.GeogCitation));
                 final Unit<Length> linearUnit = createUnit(GeoKeys.GeogLinearUnits, GeoKeys.GeogLinearUnitSize, Length.class, Units.METRE);
-                final Unit<Angle> angularUnit = createUnit(GeoKeys.AngularUnits,    GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE);
-                final GeodeticDatum     datum = createGeodeticDatum(names, angularUnit, linearUnit);
+                final GeodeticDatum datum = createGeodeticDatum(names, angularUnit, linearUnit);
                 EllipsoidalCS cs = CommonCRS.defaultGeographic().getCoordinateSystem();
                 if (!Units.DEGREE.equals(angularUnit)) {
                     cs = replaceAngularUnit(cs, angularUnit);
@@ -1172,7 +1183,7 @@ final class CRSBuilder {
                 if (rightHanded) {
                     crs = DefaultGeographicCRS.castOrCopy(crs).forConvention(AxesConvention.RIGHT_HANDED);
                 }
-                verify(crs);
+                verify(crs, angularUnit);
                 return crs;
             }
         }
@@ -1183,15 +1194,15 @@ final class CRSBuilder {
      * matches the given CRS created from the EPSG geodetic dataset.
      * This method does not verify the EPSG code of the given CRS.
      *
-     * @param  crs  the CRS created from the EPSG geodetic dataset.
+     * @param  crs          the CRS created from the EPSG geodetic dataset.
+     * @param  angularUnit  the angular unit of the latitude and longitude values.
      */
-    private void verify(final GeographicCRS crs) throws FactoryException {
+    private void verify(final GeographicCRS crs, final Unit<Angle> angularUnit) throws FactoryException {
         /*
          * Note: current createUnit(…) implementation does not allow us to distinguish whether METRE ou DEGREE units
          * were specified in the GeoTIFF file or if we got the default values. We do not compare units of that reason.
          */
         final Unit<Length> linearUnit = createUnit(GeoKeys.GeogLinearUnits, GeoKeys.GeogLinearUnitSize, Length.class, Units.METRE);
-        final Unit<Angle> angularUnit = createUnit(GeoKeys.AngularUnits,    GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE);
         final GeodeticDatum datum = crs.getDatum();
         verifyIdentifier(datum, GeoKeys.GeodeticDatum);
         verify(datum, angularUnit, linearUnit);
@@ -1241,12 +1252,13 @@ final class CRSBuilder {
                     name = getAsString(GeoKeys.Citation);
                     // Note that Citation has been removed from the map, so it will not be used by 'complete(MetadataBuilder).
                 }
-                final GeographicCRS baseCRS    = createGeographicCRS(false);
-                final Conversion    projection = createConversion(name);
-                final Unit<Length>  unit       = createUnit(GeoKeys.LinearUnits, GeoKeys.LinearUnitSize, Length.class, Units.METRE);
+                final Unit<Length>  linearUnit  = createUnit(GeoKeys.LinearUnits,  GeoKeys.LinearUnitSize, Length.class, Units.METRE);
+                final Unit<Angle>   angularUnit = createUnit(GeoKeys.AngularUnits, GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE);
+                final GeographicCRS baseCRS     = createGeographicCRS(false, angularUnit);
+                final Conversion    projection  = createConversion(name, angularUnit, linearUnit);
                 CartesianCS cs = epsgFactory().createCartesianCS(String.valueOf(Constants.EPSG_PROJECTED_CS));
-                if (!Units.METRE.equals(unit)) {
-                    cs = replaceLinearUnit(cs, unit);
+                if (!Units.METRE.equals(linearUnit)) {
+                    cs = replaceLinearUnit(cs, linearUnit);
                 }
                 final ProjectedCRS crs = objectFactory().createProjectedCRS(properties(name), baseCRS, projection, cs);
                 lastName = crs.getName();
@@ -1273,39 +1285,62 @@ final class CRSBuilder {
      * @param  crs  the CRS created from the EPSG geodetic dataset.
      */
     private void verify(final ProjectedCRS crs) throws FactoryException {
+        final Unit<Length> linearUnit  = createUnit(GeoKeys.LinearUnits,  GeoKeys.LinearUnitSize, Length.class, Units.METRE);
+        final Unit<Angle>  angularUnit = createUnit(GeoKeys.AngularUnits, GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE);
         final GeographicCRS baseCRS = crs.getBaseCRS();
         verifyIdentifier(baseCRS, GeoKeys.GeographicType);
-        verify(baseCRS);
+        verify(baseCRS, angularUnit);
         final Conversion projection = crs.getConversionFromBase();
         verifyIdentifier(projection, GeoKeys.Projection);
-        verify(projection);
+        verify(projection, angularUnit, linearUnit);
     }
 
     /**
      * Creates a defining conversion from an EPSG code or from user-defined parameters.
      *
+     * @param  angularUnit  the angular unit of the latitude and longitude values.
+     * @param  linearUnit   the linear unit of easting and northing values.
      * @throws NoSuchElementException if a mandatory value is missing.
      * @throws NumberFormatException if a numeric value was stored as a string and can not be parsed.
      * @throws ClassCastException if an object defined by an EPSG code is not of the expected type.
      * @throws FactoryException if an error occurred during objects creation with the factories.
      */
-    private Conversion createConversion(final String name) throws FactoryException {
+    private Conversion createConversion(final String name, final Unit<Angle> angularUnit, final Unit<Length> linearUnit)
+            throws FactoryException
+    {
         final int epsg = getAsInteger(GeoKeys.Projection);
         switch (epsg) {
             case GeoCodes.undefined: {
                 throw new NoSuchElementException(missingValue(GeoKeys.Projection));
             }
             case GeoCodes.userDefined: {
-                final String              type       = getMandatoryString(GeoKeys.CoordTrans);
-                final OperationMethod     method     = operationFactory().getOperationMethod(type);
-                final ParameterValueGroup parameters = method.getParameters().createValue();
+                final Unit<Angle>         azimuthUnit = createUnit(GeoKeys.AzimuthUnits, (short) 0, Angle.class, Units.DEGREE);
+                final String              type        = getMandatoryString(GeoKeys.CoordTrans);
+                final OperationMethod     method      = operationFactory().getOperationMethod(type);
+                final ParameterValueGroup parameters  = method.getParameters().createValue();
+                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 code = entry.getKey();
+                    switch (GeoKeys.unitOf(code)) {
+                        case GeoKeys.RATIO:     unit = Units.UNITY; break;
+                        case GeoKeys.LINEAR:    unit = linearUnit;  break;
+                        case GeoKeys.ANGULAR:   unit = angularUnit; break;
+                        case GeoKeys.AZIMUTH:   unit = azimuthUnit; break;
+                        default: continue;
+                    }
+                    final double value = ((Number) entry.getValue()).doubleValue();
+                    it.remove();
+                    parameters.parameter("GeoTIFF" + code).setValue(value, unit);
+                }
                 final Conversion c = operationFactory().createDefiningConversion(properties(name), method, parameters);
                 lastName = c.getName();
                 return c;
             }
             default: {
                 final Conversion projection = (Conversion) epsgFactory().createCoordinateOperation(String.valueOf(epsg));
-                verify(projection);
+                verify(projection, angularUnit, linearUnit);
                 return projection;
             }
         }
@@ -1318,7 +1353,9 @@ final class CRSBuilder {
      *
      * @param  projection  the conversion created from the EPSG geodetic dataset.
      */
-    private void verify(final Conversion projection) throws FactoryException {
+    private void verify(final Conversion projection, final Unit<Angle> angularUnit, final Unit<Length> linearUnit)
+            throws FactoryException
+    {
         // TODO
     }
 

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoKeys.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoKeys.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoKeys.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoKeys.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -67,7 +67,7 @@ final class GeoKeys {
     /** Section 6.3.3.3 codes. */ public static final short CoordTrans           = 3075;
     /** Section 6.3.1.3 codes. */ public static final short LinearUnits          = 3076;
     /** Relative to meters.    */ public static final short LinearUnitSize       = 3077;
-    /** In AngularUnit.        */ public static final short StdParallel1         = 3078;
+    /** In AngularUnit.        */ public static final short StdParallel1         = 3078;    // First projection parameter
     /** In AngularUnit.        */ public static final short StdParallel2         = 3079;
     /** In AngularUnit.        */ public static final short NatOriginLong        = 3080;
     /** In AngularUnit.        */ public static final short NatOriginLat         = 3081;
@@ -84,7 +84,7 @@ final class GeoKeys {
     /** A ratio.               */ public static final short ScaleAtNatOrigin     = 3092;
     /** A ratio.               */ public static final short ScaleAtCenter        = 3093;
     /** In AzimuthUnit.        */ public static final short AzimuthAngle         = 3094;
-    /** In AngularUnit.        */ public static final short StraightVertPoleLong = 3095;
+    /** In AngularUnit.        */ public static final short StraightVertPoleLong = 3095;    // Last projection parameter (for now)
 
     // 6.2.4 Vertical CS Keys
     /** Section 6.3.4.1 codes. */ public static final short VerticalCSType       = 4096;
@@ -93,14 +93,44 @@ final class GeoKeys {
     /** Section 6.3.1.3 codes. */ public static final short VerticalUnits        = 4099;
 
     /**
+     * Enumeration of return values for the {@link #unitOf(short)} method.
+     */
+    static final int RATIO = 0, LINEAR = 1, ANGULAR = 2, AZIMUTH = 3;
+
+    /**
+     * Returns the unit of measurement for the given map projection parameter.
+     *
+     * @param  key  GeoTIFF key for which to get the unit of associated map projection parameter value.
+     * @return one of {@link #RATIO}, {@link #LINEAR}, {@link #ANGULAR}, {@link #AZIMUTH} codes,
+     *         or -1 if the given key is not for a map projection parameter.
+     */
+    static int unitOf(final short key) {
+        if (key < StdParallel1 || key > StraightVertPoleLong) {
+            return -1;
+        }
+        switch (key) {
+            case FalseEasting:
+            case FalseNorthing:
+            case FalseOriginEasting:
+            case FalseOriginNorthing:
+            case CenterEasting:
+            case CenterNorthing:    return LINEAR;
+            case ScaleAtNatOrigin:
+            case ScaleAtCenter:     return RATIO;
+            case AzimuthAngle:      return AZIMUTH;
+            default:                return ANGULAR;
+        }
+    }
+
+    /**
      * Returns the name of the given key. Implementation of this method is inefficient,
      * but it should rarely be invoked (mostly for formatting error messages).
      */
-    static String name(final short tag) {
+    static String name(final short key) {
         try {
             for (final Field field : GeoKeys.class.getFields()) {
                 if (field.getType() == Short.TYPE) {
-                    if (field.getShort(null) == tag) {
+                    if (field.getShort(null) == key) {
                         return field.getName();
                     }
                 }
@@ -108,6 +138,6 @@ final class GeoKeys {
         } catch (IllegalAccessException e) {
             throw new AssertionError(e);        // Should never happen because we asked only for public fields.
         }
-        return Integer.toHexString(Short.toUnsignedInt(tag));
+        return Integer.toHexString(Short.toUnsignedInt(key));
     }
 }

Modified: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoIdentifiers.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoIdentifiers.java?rev=1772890&r1=1772889&r2=1772890&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoIdentifiers.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoIdentifiers.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -75,6 +75,7 @@ final class GeoIdentifiers {
     public static final short CT_VanDerGrinten                  = 25;
     public static final short CT_NewZealandMapGrid              = 26;
     public static final short CT_TransvMercator_SouthOriented   = 27;
+    public static final short CT_CylindricalEqualArea           = 28;
 
     // Aliases:
     public static final short CT_AlaskaConformal              =  CT_TransvMercator_Modified_Alaska;
@@ -153,4 +154,16 @@ final class GeoIdentifiers {
         }
         return Integer.toHexString(Short.toUnsignedInt(tag));
     }
+
+    /**
+     * Returns the numerical value of the given GeoTIFF key name.
+     * This method is the converse of {@link #name(short)}.
+     */
+    static short code(final String name) {
+        try {
+            return GeoIdentifiers.class.getField(name).getShort(null);
+        } catch (ReflectiveOperationException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
 }

Added: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoKeysTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoKeysTest.java?rev=1772890&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoKeysTest.java (added)
+++ sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoKeysTest.java [UTF-8] Tue Dec  6 13:27:05 2016
@@ -0,0 +1,118 @@
+/*
+ * 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.geotiff;
+
+import java.util.Set;
+import org.opengis.metadata.Identifier;
+import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.SingleOperation;
+import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.test.DependsOnMethod;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Compares values declared in the {@link GeoKeys} class with values declared in Apache SIS operations.
+ * Despite its name, this class is actually more a verification of GeoTIFF names and identifiers in the
+ * {@link org.apache.sis.internal.referencing.provider} package than a verification of {@code GeoKeys}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+public final strictfp class GeoKeysTest extends TestCase {
+    /**
+     * Tests {@link GeoKeys#name(short)}.
+     */
+    @Test
+    public void testName() {
+        assertEquals("Ellipsoid",  GeoKeys.name(GeoKeys.Ellipsoid));
+        assertEquals("CenterLong", GeoKeys.name(GeoKeys.CenterLong));
+    }
+
+    /**
+     * Verifies that GeoTIFF projection aliases registered in the {@link org.apache.sis.internal.referencing.provider}
+     * package match the name of fields listed in {@link GeoIdentifiers} and that GeoTIFF numerical codes correspond.
+     * This method verifies only projection names and identifiers, not parameter names.
+     */
+    @Test
+    @DependsOnMethod("testName")
+    public void verifyProjectionNames() {
+        final MathTransformFactory factory = DefaultFactories.forBuildin(MathTransformFactory.class);
+        for (final OperationMethod method : factory.getAvailableMethods(SingleOperation.class)) {
+            final Identifier identifier = IdentifiedObjects.getIdentifier(method, Citations.GEOTIFF);
+            final Set<String> names = IdentifiedObjects.getNames(method, Citations.GEOTIFF);
+            /*
+             * If there is no GeoTIFF identifiers, we should have no GeoTIFF name neither.
+             * However we may have more than one name, since GeoTIFF defines also aliases.
+             */
+            assertEquals(method.getName().getCode(), identifier == null, names.isEmpty());
+            if (identifier != null) {
+                final int code = Short.parseShort(identifier.getCode());
+                for (final String name : names) {
+                    assertEquals(name, code, GeoIdentifiers.code(name));
+                }
+            }
+        }
+    }
+
+    /**
+     * Verifies that parameter names registered in the {@link org.apache.sis.internal.referencing.provider} package
+     * match the name of fields listed in {@link GeoKeys}.
+     */
+    @Test
+    @DependsOnMethod("testName")
+    public void verifyParameterNames() {
+        final MathTransformFactory factory = DefaultFactories.forBuildin(MathTransformFactory.class);
+        for (final OperationMethod method : factory.getAvailableMethods(SingleOperation.class)) {
+            for (final GeneralParameterDescriptor param : method.getParameters().descriptors()) {
+                final Identifier identifier = IdentifiedObjects.getIdentifier(param, Citations.GEOTIFF);
+                final Set<String> names = IdentifiedObjects.getNames(param, Citations.GEOTIFF);
+                /*
+                 * If there is no GeoTIFF identifiers, we should have no GeoTIFF name neither.
+                 */
+                assertEquals(param.getName().getCode(), identifier == null, names.isEmpty());
+                if (identifier != null) {
+                    final int code = Short.parseShort(identifier.getCode());
+                    for (final String name : names) {
+                        assertEquals(name, code(name), code);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the numerical value of the given GeoTIFF key name.
+     * This method is the converse of {@link GeoKeys#name(short)}.
+     */
+    private static short code(final String name) {
+        try {
+            return GeoKeys.class.getField(name).getShort(null);
+        } catch (ReflectiveOperationException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoKeysTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-geotiff/src/test/java/org/apache/sis/storage/geotiff/GeoKeysTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8




Mime
View raw message