sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1671939 - in /sis/branches/JDK8/core: sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ sis-referencing/src/main/java/org/apache/sis/referenci...
Date Tue, 07 Apr 2015 20:28:43 GMT
Author: desruisseaux
Date: Tue Apr  7 20:28:42 2015
New Revision: 1671939

URL: http://svn.apache.org/r1671939
Log:
Referencing: complete the implementation of Equirectangular projection (actually implemented by an affine transform).
As a side effect, tuned again the way we manage parameters, especially the calculation of radius of conformal sphere.

Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.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/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/MercatorSpherical.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/MapProjectionTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/parameter/MapProjectionParametersTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -21,7 +21,6 @@ import java.awt.geom.AffineTransform;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.referencing.operation.MathTransform;
-import org.apache.sis.parameter.Parameterized;
 
 
 /**
@@ -54,9 +53,9 @@ public final class ParameterizedAffine e
     private static final long serialVersionUID = 906346920928432466L;
 
     /**
-     * An object capable to provide the parameters used for creating this transform.
+     * The (presumed immutable) parameters used for creating this transform.
      */
-    public final Parameterized parameters;
+    private final ParameterValueGroup parameters;
 
     /**
      * {@code true} if {@link #parameters} provides an accurate description of this transform, or
@@ -70,11 +69,11 @@ public final class ParameterizedAffine e
      * Creates a new transform from the given affine and parameters.
      *
      * @param transform    The affine transform to copy.
-     * @param parameters   The parameters to remember.
+     * @param parameters   The parameters to remember. It is caller's responsibility to provide an immutable instance.
      * @param isDefinitive {@code true} if {@code parameters} provides an accurate description of {@code transform}, or
      *                     {@code false} if the transform may be different than the one described by {@code parameters}.
      */
-    public ParameterizedAffine(final AffineTransform transform, final Parameterized parameters, final boolean isDefinitive) {
+    public ParameterizedAffine(final AffineTransform transform, final ParameterValueGroup parameters, final boolean isDefinitive) {
         super(transform);
         this.parameters   = parameters;
         this.isDefinitive = isDefinitive;
@@ -104,7 +103,7 @@ public final class ParameterizedAffine e
      */
     @Override
     public ParameterDescriptorGroup getParameterDescriptors() {
-        return isDefinitive ? parameters.getParameterDescriptors() : super.getParameterDescriptors();
+        return isDefinitive ? parameters.getDescriptor() : super.getParameterDescriptors();
     }
 
     /**
@@ -115,7 +114,7 @@ public final class ParameterizedAffine e
      */
     @Override
     public ParameterValueGroup getParameterValues() {
-        return isDefinitive ? parameters.getParameterValues() : super.getParameterValues();
+        return isDefinitive ? parameters : super.getParameterValues();
     }
 
     /**

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=1671939&r1=1671938&r2=1671939&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 Apr  7 20:28:42 2015
@@ -16,22 +16,34 @@
  */
 package org.apache.sis.internal.referencing.provider;
 
+import java.awt.geom.AffineTransform;
+import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.operation.CylindricalProjection;
-
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
+import org.apache.sis.parameter.Parameters;
 import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.referencing.operation.transform.ContextualParameters;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.internal.referencing.j2d.ParameterizedAffine;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.resources.Messages;
 
+import static java.lang.Math.*;
+
 
 /**
  * The provider for "<cite>Equidistant Cylindrical (Spherical)</cite>" projection
  * (EPSG:1029, <span class="deprecated">EPSG:9823</span>).
  *
+ * At the difference of most other map projection providers, this class does not extend {@link MapProjection}
+ * because it does not create non-liner kernel. Instead, the projection created by this class is implemented
+ * by an affine transform.
+ *
  * <div class="note"><b>Note:</b>
  * EPSG defines two codes for this projection, 1029 being the spherical case and 1028 the ellipsoidal case.
  * However the formulas are the same in both cases, with an additional adjustment of Earth radius in the
@@ -104,7 +116,7 @@ public final class Equirectangular exten
         STANDARD_PARALLEL = createLatitude(builder
                 .addIdentifier("8823")
                 .addName("Latitude of 1st standard parallel")
-                .addName(Citations.OGC,     "standard_parallel_1")
+                .addName(Citations.OGC,     Constants.STANDARD_PARALLEL_1)
                 .addName(Citations.ESRI,    "Standard_Parallel_1")
                 .addName(Citations.NETCDF,  "standard_parallel")
                 .addName(Citations.GEOTIFF, "ProjStdParallel1")
@@ -113,7 +125,7 @@ public final class Equirectangular exten
         CENTRAL_MERIDIAN = createLongitude(builder
                 .addIdentifier("8802")
                 .addName("Longitude of natural origin")
-                .addName(Citations.OGC,     "central_meridian")
+                .addName(Citations.OGC,     Constants.CENTRAL_MERIDIAN)
                 .addName(Citations.ESRI,    "Central_Meridian")
                 .addName(Citations.NETCDF,  "longitude_of_projection_origin")
                 .addName(Citations.GEOTIFF, "ProjCenterLong")
@@ -122,7 +134,7 @@ public final class Equirectangular exten
         FALSE_EASTING = createShift(builder
                 .addIdentifier("8806")
                 .addName("False easting")
-                .addName(Citations.OGC,     "false_easting")
+                .addName(Citations.OGC,     Constants.FALSE_EASTING)
                 .addName(Citations.ESRI,    "False_Easting")
                 .addName(Citations.NETCDF,  "false_easting")
                 .addName(Citations.GEOTIFF, "FalseEasting")
@@ -131,7 +143,7 @@ public final class Equirectangular exten
         FALSE_NORTHING = createShift(builder
                 .addIdentifier("8807")
                 .addName("False northing")
-                .addName(Citations.OGC,     "false_northing")
+                .addName(Citations.OGC,     Constants.FALSE_NORTHING)
                 .addName(Citations.ESRI,    "False_Northing")
                 .addName(Citations.NETCDF,  "false_northing")
                 .addName(Citations.GEOTIFF, "FalseNorthing")
@@ -165,7 +177,7 @@ public final class Equirectangular exten
             .addIdentifier(Citations.GEOTIFF, "17")
             .createGroupForMapProjection(
                     STANDARD_PARALLEL,
-                    LATITUDE_OF_ORIGIN,
+                    LATITUDE_OF_ORIGIN,     // Not formally an Equirectangular parameter.
                     CENTRAL_MERIDIAN,
                     FALSE_EASTING,
                     FALSE_NORTHING);
@@ -189,12 +201,70 @@ public final class Equirectangular exten
     }
 
     /**
-     * {@inheritDoc}
+     * Creates an Equirectangular projection from the specified group of parameter values.
      *
+     * @param  factory The factory to use if this constructor needs to create other math transforms.
+     * @param  parameters The parameter values that define the transform to create.
      * @return The map projection created from the given parameter values.
+     * @throws FactoryException if an error occurred while creating the math transform.
      */
     @Override
-    public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup parameters) {
-        return null;
+    public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup parameters)
+            throws FactoryException
+    {
+        return createMathTransform(this, factory, Parameters.castOrWrap(parameters));
+    }
+
+    /**
+     * Creates an Equirectangular or Plate-Carrée projection from the specified group of parameter values. This
+     * method is an adaptation of {@link org.apache.sis.referencing.operation.projection.NormalizedProjection}
+     * constructor, reproduced in this method because we will create an affine transform instead than the usual
+     * projection classes.
+     */
+    static MathTransform createMathTransform(final AbstractProvider method, final MathTransformFactory factory,
+            final Parameters parameters) throws FactoryException
+    {
+        final ContextualParameters context = new ContextualParameters(method);
+        double a  = MapProjection.getAndStore(parameters, context, MapProjection.SEMI_MAJOR);
+        double b  = MapProjection.getAndStore(parameters, context, MapProjection.SEMI_MINOR);
+        double λ0 = MapProjection.getAndStore(parameters, context, CENTRAL_MERIDIAN);
+        double φ0 = MapProjection.getAndStore(parameters, context, LATITUDE_OF_ORIGIN);
+        double φ1 = MapProjection.getAndStore(parameters, context, STANDARD_PARALLEL);
+        double fe = MapProjection.getAndStore(parameters, context, FALSE_EASTING);
+        double fn = MapProjection.getAndStore(parameters, context, FALSE_NORTHING);
+        /*
+         * Perform following transformation, in that order. Note that following
+         * AffineTransform convention, the Java code appears in reverse order:
+         *
+         *   1) Subtract φ0 to the latitude.
+         *   2) Subtract λ0 to the longitude.
+         *   3) Convert degrees to radians.
+         *   4) Scale longitude by cos(φ1).
+         */
+        φ1 = toRadians(φ1);
+        context.getMatrix(true).concatenate(0, cos(φ1), null);
+        context.normalizeGeographicInputs(λ0)
+               .concatenate(1, null, -φ0);
+        /*
+         * At this point, we usually invoke scaleAndTranslate2D(false, a, fe, fn) where 'a' (the semi-major
+         * axis length) is taken as the Earth radius (R). However quoting EPSG: "If the figure of the earth
+         * used is an ellipsoid rather than a sphere then R should be calculated as the radius of the conformal
+         * sphere at the projection origin at latitude φ1 using the formula for RC given in section 1.2, table 3".
+         */
+        if (a != b) {
+            final double rs = b / a;
+            final double sinφ1 = sin(φ1);
+            a = b / (1 - (1 - rs*rs) * (sinφ1*sinφ1));
+        }
+        context.scaleAndTranslate2D(false, a, fe, fn);
+        /*
+         * Creates the ConcatenatedTransform, letting the factory returns the cached instance
+         * if the caller already invoked this method previously (which usually do not happen).
+         */
+        MathTransform mt = context.completeTransform(factory, MathTransforms.identity(2));
+        if (mt instanceof AffineTransform) {  // Always true in Apache SIS implementation.
+            mt = new ParameterizedAffine((AffineTransform) mt, context, true);
+        }
+        return mt;
     }
 }

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=1671939&r1=1671938&r2=1671939&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 Apr  7 20:28:42 2015
@@ -41,10 +41,14 @@ import org.apache.sis.metadata.iso.citat
 import org.apache.sis.parameter.DefaultParameterDescriptor;
 import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.parameter.Parameters;
+import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Messages;
 
 import static org.opengis.metadata.Identifier.AUTHORITY_KEY;
 
+// Branch-dependent imports
+import java.util.Objects;
+
 
 /**
  * Base class for all map projection providers defined in this package. This base class defines some descriptors
@@ -123,6 +127,57 @@ public abstract class MapProjection exte
     }
 
     /**
+     * Gets a parameter value identified by the given descriptor and stores it in the {@code context}.
+     * This method performs the following actions:
+     *
+     * <ul>
+     *   <li>Convert the value to the units specified by the descriptor.</li>
+     *   <li>Ensure that the value is contained in the range specified by the descriptor.</li>
+     *   <li>Store the value only if different than the default value.</li>
+     * </ul>
+     *
+     * This method should be invoked at {@link #createMathTransform(MathTransformFactory, ParameterValueGroup)}
+     * execution time only.
+     *
+     * @param  source     The parameters from which to read the value.
+     * @param  target     Where to store the parameter values.
+     * @param  descriptor The descriptor that specify the parameter names and desired units.
+     * @return The parameter value in the units given by the descriptor.
+     * @throws IllegalArgumentException if the given value is out of bounds.
+     */
+    public static double getAndStore(final Parameters source, final ParameterValueGroup target,
+            final ParameterDescriptor<Double> descriptor) throws IllegalArgumentException
+    {
+        final double value = source.doubleValue(descriptor);    // Apply a unit conversion if needed.
+        if (Double.isNaN(value) || Double.isInfinite(value)) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalParameterValue_2,
+                    descriptor.getName(), value));
+        }
+        final Comparable<Double> min = descriptor.getMinimumValue();
+        final Comparable<Double> max = descriptor.getMaximumValue();
+        if (!Objects.equals(min, max)) {
+            /*
+             * RATIONAL: why we do not check the bounds if (min == max):
+             * The only case when our descriptor have (min == max) is when a parameter can only be zero,
+             * because of the way the map projection is defined (see e.g. Mercator1SP.LATITUDE_OF_ORIGIN).
+             * But in some cases, it would be possible to deal with non-zero values, even if in principle
+             * we should not. In such case we let the caller decides.
+             */
+            if ((min instanceof Number && !(value >= ((Number) min).doubleValue())) ||
+                (max instanceof Number && !(value <= ((Number) max).doubleValue())))
+            {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.ValueOutOfRange_4,
+                        descriptor.getName(), min, max, value));
+            }
+        }
+        final Double defaultValue = descriptor.getDefaultValue();
+        if (defaultValue == null || !defaultValue.equals(value)) {
+            target.parameter(descriptor.getName().getCode()).setValue(value);
+        }
+        return value;
+    }
+
+    /**
      * Creates a map projection from the specified group of parameter values.
      *
      * @param  factory The factory to use for creating and concatenating the (de)normalization transforms.

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=1671939&r1=1671938&r2=1671939&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 Apr  7 20:28:42 2015
@@ -18,6 +18,7 @@ package org.apache.sis.internal.referenc
 
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.metadata.iso.citation.Citations;
 
@@ -80,7 +81,7 @@ public final class Mercator1SP extends A
         SCALE_FACTOR = createScale(builder
                 .addIdentifier("8805")
                 .addName("Scale factor at natural origin")
-                .addName(Citations.OGC,     "scale_factor")
+                .addName(Citations.OGC,     Constants.SCALE_FACTOR)
                 .addName(Citations.ESRI,    "Scale_Factor")
                 .addName(Citations.NETCDF,  "scale_factor_at_projection_origin")
                 .addName(Citations.GEOTIFF, "ScaleAtNatOrigin")

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MercatorSpherical.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MercatorSpherical.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MercatorSpherical.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MercatorSpherical.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -55,7 +55,7 @@ public final class MercatorSpherical ext
     static {
         final ParameterBuilder builder = builder();
         /*
-         * The "Scale factor at natural origin" is not formally a parameter for this map projection.
+         * The "Latitude of 1st standard parallel" is not formally a parameter for this map projection.
          * But we declare it (as an optional parameter) for compatibility with those who still use it.
          */
         final ParameterDescriptor<?> standardParallel = createLatitude(builder

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -133,15 +133,16 @@ public class Mercator extends Normalized
     @Workaround(library="JDK", version="1.7")
     private Mercator(final OperationMethod method, final Parameters parameters, final byte type) {
         super(method, parameters,
-                (type == REGIONAL) ? RegionalMercator .EASTING_AT_FALSE_ORIGIN : AbstractMercator.FALSE_EASTING,
-                (type == REGIONAL) ? RegionalMercator.NORTHING_AT_FALSE_ORIGIN : AbstractMercator.FALSE_NORTHING);
+                (type == SPHERICAL) ? Mercator2SP     .STANDARD_PARALLEL        : null,
+                (type == REGIONAL ) ? RegionalMercator.EASTING_AT_FALSE_ORIGIN  : AbstractMercator.FALSE_EASTING,
+                (type == REGIONAL ) ? RegionalMercator.NORTHING_AT_FALSE_ORIGIN : AbstractMercator.FALSE_NORTHING);
         this.type = type;
         /*
          * The "Longitude of natural origin" parameter is found in all Mercator projections and is mandatory.
          * Since this is usually the Greenwich meridian, the default value is 0°. We keep the value in degrees
          * for now; it will be converted to radians later.
          */
-        double λ0 = getAndStore(parameters, Mercator1SP.CENTRAL_MERIDIAN);
+        final double λ0 = getAndStore(parameters, Mercator1SP.CENTRAL_MERIDIAN);
         /*
          * The "Latitude of natural origin" is not formally a parameter of Mercator projection. But the parameter
          * is included for completeness in CRS labelling, with the restriction (specified in EPSG documentation)
@@ -154,30 +155,17 @@ public class Mercator extends Normalized
          * "Latitude of origin" can not have a non-zero value, if it still have non-zero value we will process as
          * for "Latitude of false origin".
          */
-        double φ0 = toRadians(getAndStore(parameters, (type == REGIONAL)
+        final double φ0 = toRadians(getAndStore(parameters, (type == REGIONAL)
                 ? RegionalMercator.LATITUDE_OF_FALSE_ORIGIN : Mercator1SP.LATITUDE_OF_ORIGIN));
         /*
          * In theory, the "Latitude of 1st standard parallel" and the "Scale factor at natural origin" parameters
          * are mutually exclusive. The former is for projections of category "2SP" (namely variant B and C) while
-         * the later is for projections "1SP" (namely variant A and spherical).
+         * the later is for projections "1SP" (namely variant A and spherical). However we let users specify both
+         * if they really want, since we sometime see such CRS definitions.
          */
-        double φ1 = toRadians(getAndStore(parameters, Mercator2SP.STANDARD_PARALLEL));
+        final double φ1 = toRadians(getAndStore(parameters, Mercator2SP.STANDARD_PARALLEL));
         double k0 = getAndStore(parameters, Mercator1SP.SCALE_FACTOR);
-        /*
-         * A correction that allows us to employ a standard parallel that is not correspondent to the equator,
-         * as described in Snyder and al. at page 47. This is the same correction factor than the one applied
-         * for the Mercator (2SP) case, constant "ko" in EPSG:9805.
-         *
-         * The scale correction is multiplied with the global scale, which allows the Apache SIS referencing
-         * module to merge this correction with the scale factor in a single multiplication. In principle we
-         * should never have both the scale factor and a standard parallel. Nevertheless we sometime see such
-         * CRS definitions.
-         */
-        switch (type) {
-            case PSEUDO:    /* Do nothing since a is taken as the radius. */ break;
-            case SPHERICAL: k0 *= radiusOfConformalSphere(sin(φ1));          break;
-            default:        k0 *= cos(φ1) / rν(sin(φ1));                     break;
-        }
+        k0 *= cos(φ1) / rν(sin(φ1));
         /*
          * In principle we should rotate the central meridian (λ0) in the normalization transform, as below:
          *
@@ -231,8 +219,7 @@ public class Mercator extends Normalized
      * coordinates in <em>degrees</em> and returns (<var>x</var>,<var>y</var>) coordinates in <em>metres</em>.
      *
      * <p>The non-linear part of the returned transform will be {@code this} transform, except if the ellipsoid
-     * {@linkplain #isSpherical() is spherical}. In the later case, {@code this} transform will be replaced by
-     * a simplified implementation.</p>
+     * is spherical. In the later case, {@code this} transform will be replaced by a simplified implementation.</p>
      *
      * @param  factory The factory to use for creating the transform.
      * @return The map projection from (λ,φ) to (<var>x</var>,<var>y</var>) coordinates.
@@ -241,7 +228,7 @@ public class Mercator extends Normalized
     @Override
     public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException {
         Mercator kernel = this;
-        if (isSpherical() || (type & SPHERICAL) != 0) {
+        if ((type & SPHERICAL) != 0 || excentricity == 0) {
             kernel = new Spherical(this);
         }
         return context.completeTransform(factory, kernel);
@@ -382,9 +369,6 @@ public class Mercator extends Normalized
          */
         Spherical(final Mercator other) {
             super(other);
-            if ((type & SPHERICAL) == 0) {
-                ensureSpherical();
-            }
         }
 
         /**
@@ -421,7 +405,7 @@ public class Mercator extends Normalized
             /*
              * Following part is common to all spherical projections: verify, store and return.
              */
-            assert ((type & SPHERICAL) != 0)
+            assert (excentricity != 0)  // Can not perform the following assertions if excentricity is not zero.
                    || (Assertions.checkDerivative(derivative, super.transform(srcPts, srcOff, dstPts, dstOff, derivate))
                    && Assertions.checkTransform(dstPts, dstOff, λ, y)); // dstPts = result from ellipsoidal formulas.
             if (dstPts != null) {
@@ -475,7 +459,8 @@ public class Mercator extends Normalized
             double x = srcPts[srcOff  ];
             double y = srcPts[srcOff+1];
             y = PI/2 - 2 * atan(exp(-y));     // Part of Snyder (7-4)
-            assert ((type & SPHERICAL) != 0) || checkInverseTransform(srcPts, srcOff, dstPts, dstOff, x, y);
+            assert (excentricity != 0)  // Can not perform the following assertion if excentricity is not zero.
+                   || checkInverseTransform(srcPts, srcOff, dstPts, dstOff, x, y);
             dstPts[dstOff  ] = x;
             dstPts[dstOff+1] = y;
         }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -35,7 +35,6 @@ import org.apache.sis.util.Debug;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.parameter.Parameters;
-import org.apache.sis.parameter.DefaultParameterDescriptor;
 import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.operation.matrix.Matrices;
@@ -100,7 +99,7 @@ import java.util.Objects;
  * org.opengis.referencing.cs.CoordinateSystem) higher level}.</div>
  *
  * {@code NormalizedProjection} does not store the above cited parameters (central meridian, scale factor, <i>etc.</i>)
- * on intend, in order to make clear that those parameters are not used by subclasses.
+ * on intend (except indirectly), in order to make clear that those parameters are not used by subclasses.
  * The ability to recognize two {@code NormalizedProjection}s as {@linkplain #equals(Object, ComparisonMode) equivalent}
  * without consideration for the scale factor (among other) allow more efficient concatenation in some cases
  * (typically some combinations of inverse projection followed by a direct projection).
@@ -190,42 +189,130 @@ public abstract class NormalizedProjecti
      * <ul>
      *   <li>On the <b>normalization</b> matrix (to be applied before {@code this} transform):
      *     <ul>
-     *       <li>Nothing. Callers shall invoke {@link ContextualParameters#normalizeGeographicInputs(double)} themselves.</li>
+     *       <li>{@linkplain ContextualParameters#normalizeGeographicInputs(double) Subtract}
+     *           the <cite>central meridian</cite> value.</li>
+     *       <li>Convert from degrees to radians.</li>
      *     </ul>
      *   </li>
      *   <li>On the <b>denormalization</b> matrix (to be applied after {@code this} transform):
      *     <ul>
      *       <li>{@linkplain ContextualParameters#scaleAndTranslate2D(boolean, double, double, double) Scale}
      *           by the <cite>semi-major</cite> axis length.</li>
-     *       <li>Translate by the false easting and false northing (after the scale).</li>
+     *       <li>Translate by the <cite>false easting</cite> and <cite>false northing</cite> (after the scale).</li>
      *     </ul>
      *   </li>
      *   <li>On the <b>contextual parameters</b> (not the parameters of {@code this} transform):
      *     <ul>
      *       <li>Store the values for <cite>semi-major</cite> axis length, <cite>semi-minor</cite> axis length,
-     *           <cite>false easting</cite> and <cite>false northing</cite>.</li>
+     *           <cite>central meridian</cite>, <cite>false easting</cite> and <cite>false northing</cite> values.</li>
      *     </ul>
      *   </li>
      * </ul>
      *
-     * @param method        Description of the map projection parameters.
-     * @param parameters    The parameters of the projection to be created.
-     * @param falseEasting  The descriptor for fetching the <cite>false easting</cite> parameter.
-     * @param falseNorthing The descriptor for fetching the <cite>false northing</cite> parameter.
+     * <div class="section">Pre-requite</div>
+     * The parameters of the given {@code method} argument shall contains descriptor for the given parameters
+     * (using OGC names):
+     * <ul>
+     *   <li>{@code "semi_major"}</li>
+     *   <li>{@code "semi_minor"}</li>
+     *   <li>{@code "central_meridian"}</li>
+     *   <li>{@code "false_easting"}</li>
+     *   <li>{@code "false_northing"}</li>
+     * </ul>
+     *
+     * <div class="note"><b>Note:</b>
+     * Apache SIS uses EPSG names as much as possible, but this constructor is an exception to this rule.
+     * In this particular case we use OGC names because they are identical for a wide range of projections.
+     * For example there is at least two different EPSG names for the <cite>false northing</cite> parameter,
+     * depending on the projection:
+     *
+     * <ul>
+     *   <li><cite>Northing at false origin</cite></li>
+     *   <li><cite>Northing at projection centre</cite></li>
+     * </ul>
+     *
+     * OGC defines only {@code "false_northing"} for all, which makes a convenient name to look for in this
+     * constructor.</div>
+     *
+     * @param method     Description of the map projection parameters.
+     * @param parameters The parameters of the projection to be created.
+     */
+    protected NormalizedProjection(final OperationMethod method, final Parameters parameters) {
+        this(method, parameters, null,
+                descriptor(method, Constants.FALSE_EASTING),
+                descriptor(method, Constants.FALSE_NORTHING));
+        context.normalizeGeographicInputs(getAndStore(parameters, descriptor(method, Constants.CENTRAL_MERIDIAN)));
+    }
+
+    /**
+     * Returns the parameter descriptor for the given name.
+     * This is a helper method for above constructor only.
      */
-    protected NormalizedProjection(final OperationMethod method, final Parameters parameters,
+    private static ParameterDescriptor<Double> descriptor(final OperationMethod method, final String name) {
+        ensureNonNull("method", method);
+        return Parameters.cast((ParameterDescriptor<?>) method.getParameters().descriptor(name), Double.class);
+    }
+
+    /**
+     * Constructs a new map projection by fetching the values using the given parameter descriptors.
+     * At the difference of the {@link #NormalizedProjection(OperationMethod, Parameters)} constructor,
+     * this constructor does <strong>not</strong> apply the following operations:
+     *
+     * <ul>
+     *   <li>Normalization: no operation done. Callers shall invoke
+     *     {@link ContextualParameters#normalizeGeographicInputs(double)} themselves.</li>
+     * </ul>
+     *
+     *
+     * <div class="section">Radius of conformal sphere (Rc)</div>
+     * If the {@code conformalSphereAtφ} argument is non-null, then the radius of the conformal sphere
+     * at latitude φ will be used instead than the semi-major axis length <var>a</var> (<b>Source:</b>
+     * <cite>Geomatics Guidance Note Number 7, part 2, version 49</cite> from EPSG: table 3 in section
+     * 1.2 and explanation in section 1.3.3.1).
+     *
+     * <p><b>Important usage notes:</b><p>
+     * <ul>
+     *   <li>The {@code conformalSphereAtφ} argument shall be non-null <strong>only</strong> when the user
+     *       requested explicitely spherical formulas, for example the <cite>"Mercator (Spherical)"</cite>
+     *       projection (EPSG:1026), but the figure of the Earth is an ellipsoid rather than a sphere.</li>
+     *   <li>This parameter value is <strong>not</strong> stored since we presume that the caller will fetch
+     *       the value for its own processing.</li>
+     * </ul>
+     *
+     * @param conformalSphere_φ If non-null, the the latitude where to compute the radius of conformal sphere.
+     * @param falseEasting      The descriptor for fetching the <cite>"False easting"</cite> parameter.
+     * @param falseNorthing     The descriptor for fetching the <cite>"False northing"</cite> parameter.
+     */
+    NormalizedProjection(final OperationMethod method, final Parameters parameters,
+            final ParameterDescriptor<Double> conformalSphere_φ,
             final ParameterDescriptor<Double> falseEasting,
             final ParameterDescriptor<Double> falseNorthing)
     {
         ensureNonNull("parameters", parameters);
         context = new ContextualParameters(method);
-        final double a  = getAndStore(parameters, MapProjection.SEMI_MAJOR);
+              double a  = getAndStore(parameters, MapProjection.SEMI_MAJOR);
         final double b  = getAndStore(parameters, MapProjection.SEMI_MINOR);
         final double fe = getAndStore(parameters, falseEasting);
         final double fn = getAndStore(parameters, falseNorthing);
-        context.scaleAndTranslate2D(false, a, fe, fn);
-        excentricitySquared = 1.0 - (b*b) / (a*a);
+        final double rs = b / a;
+        excentricitySquared = 1 - (rs * rs);
         excentricity = sqrt(excentricitySquared);
+        if (conformalSphere_φ != null && excentricitySquared != 0) {
+            /*
+             * EPSG said: R is the radius of the sphere and will normally be one of the CRS parameters.
+             * If the figure of the earth used is an ellipsoid rather than a sphere then R should be calculated
+             * as the radius of the conformal sphere at the projection origin at latitude φ₀ using the formula
+             * for Rc given in section 1.2, table 3.
+             *
+             * Table 3 gives:
+             * Radius of conformal sphere Rc = a √(1 – ℯ²) / (1 – ℯ²⋅sin²φ)
+             *
+             * Using √(1 – ℯ²) = b/a we rewrite as: Rc = b / (1 – ℯ²⋅sin²φ)
+             */
+            final double sinφ = sin(toRadians(parameters.doubleValue(conformalSphere_φ)));
+            a = b / (1 - excentricitySquared * (sinφ*sinφ));
+        }
+        context.scaleAndTranslate2D(false, a, fe, fn);
         inverse = new Inverse();
     }
 
@@ -263,23 +350,6 @@ public abstract class NormalizedProjecti
     }
 
     /**
-     * Returns a parameter descriptor with the same properties than the given one, except that the parameter is
-     * optional. This is sometime needed when invoking {@link #getAndStore(Parameters, ParameterDescriptor)} for
-     * a parameter value which is mandatory in principle, but may be absent because the parameters for the same
-     * projection may be specified in different ways (for example <cite>"Mercator (variant A)"</cite> versus
-     * <cite>"Mercator (variant B)"</cite>).
-     *
-     * @param  <T> The type of parameter value.
-     * @param  descriptor The mandatory descriptor to make optional.
-     * @return A parameter descriptor with the same properties than the given one, but optional.
-     */
-    static <T> ParameterDescriptor<T> makeOptional(final ParameterDescriptor<T> descriptor) {
-        assert descriptor.getMinimumOccurs() == 1; // This method is useless if minOccurs == 0.
-        return new DefaultParameterDescriptor<>(IdentifiedObjects.getProperties(descriptor), 0, 1,
-                descriptor.getValueClass(), Parameters.getValueDomain(descriptor), null, descriptor.getDefaultValue());
-    }
-
-    /**
      * Gets a parameter value identified by the given descriptor and stores it in the {@link #context}.
      * A "contextual parameter" is a parameter that apply to the normalize → {@code this} → denormalize
      * chain as a whole. It does not really apply to this {@code NormalizedProjection} instance when taken alone.
@@ -287,36 +357,7 @@ public abstract class NormalizedProjecti
      * <p>This method shall be invoked at construction time only.</p>
      */
     final double getAndStore(final Parameters parameters, final ParameterDescriptor<Double> descriptor) {
-        final double value = parameters.doubleValue(descriptor);    // Apply a unit conversion if needed.
-        final Comparable<Double> min = descriptor.getMinimumValue();
-        final Comparable<Double> max = descriptor.getMaximumValue();
-        if (!Objects.equals(min, max)) {
-            /*
-             * Why we do not check the bounds in min == max:
-             * The only case when our descriptor have (min == max) is when a parameter can only be zero,
-             * because of the way the map projection is defined. But in some cases, it would be possible
-             * to deal with non-zero values, even if in principle we should not. In such case we let the
-             * caller decides.
-             */
-            if (min instanceof Number && !(value >= ((Number) min).doubleValue())) {
-                throw outOfBounds(descriptor, value);
-            }
-            if (max instanceof Number && !(value <= ((Number) max).doubleValue())) {
-                throw outOfBounds(descriptor, value);
-            }
-        }
-        final Double defaultValue = descriptor.getDefaultValue();
-        if (defaultValue == null || !defaultValue.equals(value)) {
-            context.parameter(descriptor.getName().getCode()).setValue(value);
-        }
-        return value;
-    }
-
-    /**
-     * Creates the exception for a parameter value out of bounds.
-     */
-    private static IllegalArgumentException outOfBounds(final ParameterDescriptor<Double> descriptor, double value) {
-        return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalParameterValue_2, descriptor.getName(), value));
+        return MapProjection.getAndStore(parameters, context, descriptor);
     }
 
     /**
@@ -333,7 +374,7 @@ public abstract class NormalizedProjecti
      *
      * Subclasses can override this method if they wish to use alternative implementations under some circumstances.
      * For example many subclasses will replace {@code this} by a specialized implementation if they detect that the
-     * ellipsoid is actually {@linkplain #isSpherical() spherical}.
+     * ellipsoid is actually spherical.
      *
      * @param  factory The factory to use for creating the transform.
      * @return The map projection from (λ,φ) to (<var>x</var>,<var>y</var>) coordinates.
@@ -413,28 +454,6 @@ public abstract class NormalizedProjecti
     }
 
     /**
-     * Returns {@code true} if this projection is done on a sphere rather than an ellipsoid.
-     * Projections on spheres have an {@linkplain #excentricity} equals to zero.
-     *
-     * @return {@code true} if this projection is on a sphere.
-     */
-    public final boolean isSpherical() {
-        return excentricity == 0;
-    }
-
-    /**
-     * Ensures that this projection is done on a sphere rather than an ellipsoid.
-     * This method is invoked by constructors of classes implementing only spherical formulas.
-     *
-     * @throws IllegalArgumentException If the projection is not done on a sphere.
-     */
-    final void ensureSpherical() throws IllegalArgumentException {
-        if (!isSpherical()) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.EllipticalNotSupported));
-        }
-    }
-
-    /**
      * Converts a single coordinate in {@code srcPts} at the given offset and stores the result
      * in {@code dstPts} at the given offset. In addition, opportunistically computes the
      * transform derivative if requested.
@@ -657,21 +676,6 @@ public abstract class NormalizedProjecti
     }
 
     /**
-     * Computes the radius of conformal sphere (Rc) at latitude φ. This is used when the user requested
-     * explicitely spherical formulas for example with <cite>"Mercator (Spherical)"</cite> projection
-     * (EPSG:1026), but the figure of the Earth used is an ellipsoid rather than a sphere.
-     *
-     * <p><b>Source:</b> <cite>Geomatics Guidance Note Number 7, part 2, version 49</cite> from EPSG:
-     * table 3 in section 1.2 and explanation in section 1.3.3.1.</p>
-     *
-     * @param  sinφ The sine of the φ latitude in radians.
-     * @return Radius of conformal sphere at latitude φ.
-     */
-    final double radiusOfConformalSphere(final double sinφ) {
-        return sqrt(1 - excentricitySquared) / (1 - excentricitySquared * (sinφ*sinφ));
-    }
-
-    /**
      * Computes part of the Mercator projection for the given latitude. This formula is also part of
      * Lambert Conic Conformal projection, since Mercator can be considered as a special case of that
      * Lambert projection with the equator as the single standard parallel.

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/MapProjectionTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/MapProjectionTest.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/MapProjectionTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/MapProjectionTest.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -28,8 +28,7 @@ import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
-import static org.apache.sis.internal.util.Constants.SEMI_MAJOR;
-import static org.apache.sis.internal.util.Constants.SEMI_MINOR;
+import static org.apache.sis.internal.util.Constants.*;
 
 
 /**
@@ -57,14 +56,14 @@ public final strictfp class MapProjectio
     @DependsOnMethod("testSemiAxes")
     public void testMercator1SP() {
         final Iterator<GeneralParameterDescriptor> it = Mercator1SP.PARAMETERS.descriptors().iterator();
-        assertParamEquals("Mercator (variant A)",           "Mercator_1SP",       true, Mercator1SP.PARAMETERS);
-        assertParamEquals(null,                              SEMI_MAJOR,          true, it.next());
-        assertParamEquals(null,                              SEMI_MINOR,          true, it.next());
-        assertParamEquals("Latitude of natural origin",     "latitude_of_origin", true, it.next());
-        assertParamEquals("Longitude of natural origin",    "central_meridian",   true, it.next());
-        assertParamEquals("Scale factor at natural origin", "scale_factor",       true, it.next());
-        assertParamEquals("False easting",                  "false_easting",      true, it.next());
-        assertParamEquals("False northing",                 "false_northing",     true, it.next());
+        assertParamEquals("Mercator (variant A)",          "Mercator_1SP",       true, Mercator1SP.PARAMETERS);
+        assertParamEquals(null,                             SEMI_MAJOR,          true, it.next());
+        assertParamEquals(null,                             SEMI_MINOR,          true, it.next());
+        assertParamEquals("Latitude of natural origin",    "latitude_of_origin", true, it.next());
+        assertParamEquals("Longitude of natural origin",    CENTRAL_MERIDIAN,    true, it.next());
+        assertParamEquals("Scale factor at natural origin", SCALE_FACTOR,        true, it.next());
+        assertParamEquals("False easting",                  FALSE_EASTING,       true, it.next());
+        assertParamEquals("False northing",                 FALSE_NORTHING,      true, it.next());
         assertFalse(it.hasNext());
         assertIsForcedToZero((ParameterDescriptor<?>) Mercator1SP.PARAMETERS.descriptor("latitude_of_origin"));
     }
@@ -76,15 +75,15 @@ public final strictfp class MapProjectio
     @DependsOnMethod("testSemiAxes")
     public void testMercator2SP() {
         final Iterator<GeneralParameterDescriptor> it = Mercator2SP.PARAMETERS.descriptors().iterator();
-        assertParamEquals("Mercator (variant B)",              "Mercator_2SP",        true,  Mercator2SP.PARAMETERS);
-        assertParamEquals(null,                                 SEMI_MAJOR,           true, it.next());
-        assertParamEquals(null,                                 SEMI_MINOR,           true, it.next());
-        assertParamEquals("Latitude of 1st standard parallel", "standard_parallel_1", true,  it.next());
-        assertParamEquals(null,                                "latitude_of_origin",  false, it.next());
-        assertParamEquals("Longitude of natural origin",       "central_meridian",    true,  it.next());
-        assertParamEquals(null,                                "scale_factor",        false, it.next());
-        assertParamEquals("False easting",                     "false_easting",       true,  it.next());
-        assertParamEquals("False northing",                    "false_northing",      true,  it.next());
+        assertParamEquals("Mercator (variant B)",             "Mercator_2SP",        true,  Mercator2SP.PARAMETERS);
+        assertParamEquals(null,                                SEMI_MAJOR,           true, it.next());
+        assertParamEquals(null,                                SEMI_MINOR,           true, it.next());
+        assertParamEquals("Latitude of 1st standard parallel", STANDARD_PARALLEL_1,  true,  it.next());
+        assertParamEquals(null,                               "latitude_of_origin",  false, it.next());
+        assertParamEquals("Longitude of natural origin",       CENTRAL_MERIDIAN,     true,  it.next());
+        assertParamEquals(null,                                SCALE_FACTOR,         false, it.next());
+        assertParamEquals("False easting",                     FALSE_EASTING,        true,  it.next());
+        assertParamEquals("False northing",                    FALSE_NORTHING,       true,  it.next());
         assertFalse(it.hasNext());
         assertIsForcedToZero((ParameterDescriptor<?>) Mercator1SP.PARAMETERS.descriptor("latitude_of_origin"));
     }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/parameter/MapProjectionParametersTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/parameter/MapProjectionParametersTest.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/parameter/MapProjectionParametersTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/parameter/MapProjectionParametersTest.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -26,6 +26,14 @@ import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
+import static org.apache.sis.internal.util.Constants.SEMI_MAJOR;
+import static org.apache.sis.internal.util.Constants.SEMI_MINOR;
+import static org.apache.sis.internal.util.Constants.CENTRAL_MERIDIAN;
+import static org.apache.sis.internal.util.Constants.STANDARD_PARALLEL_1;
+import static org.apache.sis.internal.util.Constants.STANDARD_PARALLEL_2;
+import static org.apache.sis.parameter.MapProjectionDescriptor.EARTH_RADIUS;
+import static org.apache.sis.parameter.MapProjectionDescriptor.INVERSE_FLATTENING;
+import static org.apache.sis.parameter.MapProjectionDescriptor.STANDARD_PARALLEL;
 
 
 /**
@@ -49,9 +57,9 @@ public final strictfp class MapProjectio
         final ParameterDescriptor<?>[] parameters = new ParameterDescriptor<?>[numStandardParallels + 1];
         switch (numStandardParallels) {
             default: throw new IllegalArgumentException();
-            case 2: parameters[2] = parameter("standard_parallel_2");   // Fall through
-            case 1: parameters[1] = parameter("standard_parallel_1");   // Fall through
-            case 0: parameters[0] = parameter("central_meridian");
+            case 2: parameters[2] = parameter(STANDARD_PARALLEL_2);   // Fall through
+            case 1: parameters[1] = parameter(STANDARD_PARALLEL_1);   // Fall through
+            case 0: parameters[0] = parameter(CENTRAL_MERIDIAN);
                     break;
         }
         return new MapProjectionDescriptor(name("Lambert Conic Conformal (2SP)"), parameters);
@@ -75,16 +83,16 @@ public final strictfp class MapProjectio
         final MapProjectionDescriptor descriptor = createDescriptor(0);
         final ParameterValueGroup parameters = descriptor.createValue();
 
-        parameters.parameter("semi_major").setValue(6378137.000); // WGS84
-        parameters.parameter("semi_minor").setValue(6356752.314);
-        assertEquals(6371007, parameters.parameter("earth_radius").doubleValue(), 0.5); // Authalic radius.
-        assertEquals(6378137, parameters.parameter("semi_major")  .doubleValue(), 0.5);
-        assertEquals(6356752, parameters.parameter("semi_minor")  .doubleValue(), 0.5);
-
-        parameters.parameter("earth_radius").setValue(6371000);
-        assertEquals(6371000, parameters.parameter("earth_radius").doubleValue(), 0.0);
-        assertEquals(6371000, parameters.parameter("semi_major")  .doubleValue(), 0.0);
-        assertEquals(6371000, parameters.parameter("semi_minor")  .doubleValue(), 0.0);
+        parameters.parameter(SEMI_MAJOR).setValue(6378137.000); // WGS84
+        parameters.parameter(SEMI_MINOR).setValue(6356752.314);
+        assertEquals(6371007, parameters.parameter(EARTH_RADIUS).doubleValue(), 0.5); // Authalic radius.
+        assertEquals(6378137, parameters.parameter(SEMI_MAJOR)  .doubleValue(), 0.5);
+        assertEquals(6356752, parameters.parameter(SEMI_MINOR)  .doubleValue(), 0.5);
+
+        parameters.parameter(EARTH_RADIUS).setValue(6371000);
+        assertEquals(6371000, parameters.parameter(EARTH_RADIUS).doubleValue(), 0.0);
+        assertEquals(6371000, parameters.parameter(SEMI_MAJOR)  .doubleValue(), 0.0);
+        assertEquals(6371000, parameters.parameter(SEMI_MINOR)  .doubleValue(), 0.0);
     }
 
     /**
@@ -95,17 +103,17 @@ public final strictfp class MapProjectio
         final MapProjectionDescriptor descriptor = createDescriptor(0);
         final ParameterValueGroup parameters = descriptor.createValue();
 
-        parameters.parameter("semi_major").setValue(6378206.4); // Clarke 1866
-        parameters.parameter("semi_minor").setValue(6356583.8);
-        assertEquals(294.97870, parameters.parameter("inverse_flattening").doubleValue(), 0.00001);
-        assertEquals(6378206.4, parameters.parameter("semi_major")        .doubleValue(), 0.5);
-        assertEquals(6356583.8, parameters.parameter("semi_minor")        .doubleValue(), 0.5);
-
-        parameters.parameter("semi_major").setValue(6378137.000); // WGS84
-        parameters.parameter("inverse_flattening").setValue(298.257223563);
-        assertEquals(298.257, parameters.parameter("inverse_flattening").doubleValue(), 0.001);
-        assertEquals(6378137, parameters.parameter("semi_major")        .doubleValue(), 0.5);
-        assertEquals(6356752, parameters.parameter("semi_minor")        .doubleValue(), 0.5);
+        parameters.parameter(SEMI_MAJOR).setValue(6378206.4); // Clarke 1866
+        parameters.parameter(SEMI_MINOR).setValue(6356583.8);
+        assertEquals(294.97870, parameters.parameter(INVERSE_FLATTENING).doubleValue(), 0.00001);
+        assertEquals(6378206.4, parameters.parameter(SEMI_MAJOR)        .doubleValue(), 0.5);
+        assertEquals(6356583.8, parameters.parameter(SEMI_MINOR)        .doubleValue(), 0.5);
+
+        parameters.parameter(SEMI_MAJOR).setValue(6378137.000); // WGS84
+        parameters.parameter(INVERSE_FLATTENING).setValue(298.257223563);
+        assertEquals(298.257, parameters.parameter(INVERSE_FLATTENING).doubleValue(), 0.001);
+        assertEquals(6378137, parameters.parameter(SEMI_MAJOR)        .doubleValue(), 0.5);
+        assertEquals(6356752, parameters.parameter(SEMI_MINOR)        .doubleValue(), 0.5);
     }
 
     /**
@@ -117,11 +125,11 @@ public final strictfp class MapProjectio
         final MapProjectionDescriptor descriptor = createDescriptor(0);
         final ParameterValueGroup parameters = descriptor.createValue();
 
-        parameters.parameter("semi_major").setValue(6378137.000); // WGS84
-        parameters.parameter("inverse_flattening").setValue(298.257223563);
-        assertEquals(298.257, parameters.parameter("inverse_flattening").doubleValue(), 0.001);
-        assertEquals(6378137, parameters.parameter("semi_major")        .doubleValue(), 0.5);
-        assertEquals(6356752, parameters.parameter("semi_minor")        .doubleValue(), 0.5);
+        parameters.parameter(SEMI_MAJOR).setValue(6378137.000); // WGS84
+        parameters.parameter(INVERSE_FLATTENING).setValue(298.257223563);
+        assertEquals(298.257, parameters.parameter(INVERSE_FLATTENING).doubleValue(), 0.001);
+        assertEquals(6378137, parameters.parameter(SEMI_MAJOR)        .doubleValue(), 0.5);
+        assertEquals(6356752, parameters.parameter(SEMI_MINOR)        .doubleValue(), 0.5);
     }
 
     /**
@@ -131,12 +139,15 @@ public final strictfp class MapProjectio
     public void testStandardParallel() {
         final MapProjectionDescriptor descriptor = createDescriptor(2);
         final ParameterValueGroup parameters = descriptor.createValue();
-        final ParameterValue<?> p  = parameters.parameter("standard_parallel"  );
-        final ParameterValue<?> p1 = parameters.parameter("standard_parallel_1");
-        final ParameterValue<?> p2 = parameters.parameter("standard_parallel_2");
-        assertSame(p,  parameters.parameter("standard_parallel"  ));
-        assertSame(p1, parameters.parameter("standard_parallel_1"));
-        assertSame(p2, parameters.parameter("standard_parallel_2"));
+        final ParameterValue<?> p  = parameters.parameter(STANDARD_PARALLEL);
+        final ParameterValue<?> p1 = parameters.parameter(STANDARD_PARALLEL_1);
+        final ParameterValue<?> p2 = parameters.parameter(STANDARD_PARALLEL_2);
+        assertSame(p,  parameters.parameter(STANDARD_PARALLEL));
+        assertSame(p1, parameters.parameter(STANDARD_PARALLEL_1));
+        assertSame(p2, parameters.parameter(STANDARD_PARALLEL_2));
+        assertNotSame(p1, p2);
+        assertNotSame(p1, p);
+        assertNotSame(p2, p);
 
         /* Empty */      assertArrayEquals(new double[] {     }, p.doubleValueList(), 0.0);
         p1.setValue(40); assertArrayEquals(new double[] {40   }, p.doubleValueList(), 0.0);

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -75,10 +75,10 @@ strictfp class MapProjectionTestCase ext
      */
     final void initialize(final MapProjection provider, final boolean ellipse) throws FactoryException {
         final Parameters parameters = parameters(provider, ellipse);
-        parameters.parameter("central_meridian").setValue(0.5, NonSI.DEGREE_ANGLE);
-        parameters.parameter("scale_factor")    .setValue(0.997);
-        parameters.parameter("false_easting")   .setValue(200);
-        parameters.parameter("false_northing")  .setValue(100);
+        parameters.parameter(Constants.CENTRAL_MERIDIAN).setValue(0.5, NonSI.DEGREE_ANGLE);
+        parameters.parameter(Constants.SCALE_FACTOR)    .setValue(0.997);
+        parameters.parameter(Constants.FALSE_EASTING)   .setValue(200);
+        parameters.parameter(Constants.FALSE_NORTHING)  .setValue(100);
         transform = new MathTransformFactoryMock(provider).createParameterizedTransform(parameters);
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -57,7 +57,7 @@ final strictfp class NoOp extends Normal
     private NoOp(final Parameters parameters) {
         super(new DefaultOperationMethod(
                 Collections.singletonMap(DefaultOperationMethod.NAME_KEY, parameters.getDescriptor().getName()),
-                2, 2, parameters.getDescriptor()), parameters,
+                2, 2, parameters.getDescriptor()), parameters, null,
                 MapProjection.SEMI_MAJOR,   // Should actually by FALSE_EASTING,  but we do not care for this test.
                 MapProjection.SEMI_MINOR);  // Should actually by FALSE_NORTHING, but we do not care for this test.
     }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -107,11 +107,9 @@ public final strictfp class NormalizedPr
     public void testExcentricity() {
         NormalizedProjection projection;
         transform = projection = new NoOp(false);
-        assertTrue("isSpherical", projection.isSpherical());
         assertEquals("excentricity", 0.0, projection.excentricity, 0.0);
 
         transform = projection = new NoOp(true);
-        assertFalse("isSpherical", projection.isSpherical());
         assertEquals("excentricity", 0.08181919084262157, projection.excentricity, TOLERANCE);
     }
 

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java?rev=1671939&r1=1671938&r2=1671939&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java [UTF-8] Tue Apr  7 20:28:42 2015
@@ -78,12 +78,48 @@ public final class Constants extends Sta
                                SEMI_MINOR = "semi_minor";
 
     /**
+     * The OGC parameter name for the central meridian.
+     */
+    public static final String CENTRAL_MERIDIAN = "central_meridian";
+
+    /**
      * The OGC parameter name for the standard parallels.
      */
     public static final String STANDARD_PARALLEL_1 = "standard_parallel_1",
                                STANDARD_PARALLEL_2 = "standard_parallel_2";
 
     /**
+     * The OGC parameter name for the scale factor.
+     * While Apache SIS uses EPSG names when possible, the OGC names are convenient in this case
+     * because they do not depend on the projection. For example EPSG has at least three different
+     * names for the scale factor, depending on the projection:
+     *
+     * <ul>
+     *   <li><cite>Scale factor at natural origin</cite></li>
+     *   <li><cite>Scale factor on initial line</cite></li>
+     *   <li><cite>Scale factor on pseudo standard parallel</cite></li>
+     * </ul>
+     *
+     * Usage of OGC names avoid the need to choose a name according the projection.
+     */
+    public static final String SCALE_FACTOR = "scale_factor";
+
+    /**
+     * The OGC parameter name for the false easting or northing.
+     * While Apache SIS uses EPSG names when possible, the OGC names are convenient in this case
+     * because they do not depend on the projection. For example EPSG has at least two different
+     * names for false northing, depending on the projection:
+     *
+     * <ul>
+     *   <li><cite>Northing at false origin</cite></li>
+     *   <li><cite>Northing at projection centre</cite></li>
+     * </ul>
+     *
+     * Usage of OGC names avoid the need to choose a name according the projection.
+     */
+    public static final String FALSE_EASTING  = "false_easting",
+                               FALSE_NORTHING = "false_northing";
+    /**
      * Name of the {@value} matrix parameters.
      */
     public static final String NUM_ROW = "num_row",



Mime
View raw message