Author: desruisseaux
Date: Tue Jul 28 17:18:30 2015
New Revision: 1693133

URL: http://svn.apache.org/r1693133
Log:
WKT: Convention.INTERNAL should display the real internal parameters used by a 
map projection implementation.
Those internal parameters are very different than the public parameters, but 
are sometime needed for debugging.

Modified:
    
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ISOMetadata.java
    
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.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/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConformalTest.java
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ProjectionResultComparator.java
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DefaultFactories.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java

Modified: 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ISOMetadata.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ISOMetadata.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ISOMetadata.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ISOMetadata.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -32,6 +32,7 @@ import org.apache.sis.metadata.MetadataS
 import org.apache.sis.metadata.ModifiableMetadata;
 import org.apache.sis.internal.jaxb.IdentifierMapWithSpecialCases;
 import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.internal.util.Utilities;
 import org.apache.sis.util.collection.Containers;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.CharSequences;
@@ -107,7 +108,7 @@ public class ISOMetadata extends Modifia
                  * without invoking super.getIdentifiers(), in which case 
their identifiers will not be copied.
                  * For safety, we will do this optimization only if the 
implementation is an Apache SIS one.
                  */
-                if (object.getClass().getName().startsWith("org.apache.sis.")) 
{
+                if (Utilities.isSIS(object.getClass())) {
                     return;
                 }
             }

Modified: 
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -30,7 +30,7 @@ import org.apache.sis.io.wkt.Convention;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public strictfp class MetadataAssert extends Assert {
@@ -109,4 +109,31 @@ public strictfp class MetadataAssert ext
                     ((IdentifiedObject) object).getName().getCode() : 
object.getClass().getSimpleName(), expected, wkt);
         }
     }
+
+    /**
+     * Asserts that the WKT of the given object according the given convention 
is equal to the given regular expression.
+     * This method is like {@link #assertWktEquals(String, Object)}, but the 
use of regular expression allows some
+     * tolerance for example on numerical parameter values that may be subject 
to a limited form of rounding errors.
+     *
+     * @param convention The WKT convention to use.
+     * @param expected   The expected regular expression, or {@code null} if 
{@code object} is expected to be null.
+     * @param object     The object to format in <cite>Well Known Text</cite> 
format, or {@code null}.
+     *
+     * @since 0.6
+     */
+    public static void assertWktEqualsRegex(final Convention convention, final 
String expected, final Object object) {
+        if (expected == null) {
+            assertNull(object);
+        } else {
+            assertNotNull(object);
+            final String wkt;
+            synchronized (WKT_FORMAT) {
+                WKT_FORMAT.setConvention(convention);
+                wkt = WKT_FORMAT.format(object);
+            }
+            if (!wkt.matches(expected)) {
+                fail("WKT does not match the expected regular expression. The 
WKT that we got is:\n" + wkt);
+            }
+        }
+    }
 }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -32,6 +32,7 @@ import org.apache.sis.internal.referenci
 import org.apache.sis.internal.metadata.ReferencingServices;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.internal.util.Utilities;
 import 
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
 import org.apache.sis.util.collection.WeakHashSet;
 import org.apache.sis.util.collection.Containers;
@@ -569,7 +570,7 @@ public class DefaultCoordinateOperationF
             return delegate;
         }
         for (final CoordinateOperationFactory factory : 
java.util.ServiceLoader.load(CoordinateOperationFactory.class)) {
-            if (!factory.getClass().getName().startsWith("org.apache.sis.")) {
+            if (!Utilities.isSIS(factory.getClass())) {
                 delegate = factory;
                 return factory;
             }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -45,6 +45,12 @@ import static java.lang.Math.*;
  * appear to be the same with the <var>n</var> factor fixed to 1 or -1, so we 
leverage the code provided by
  * this base class. This class hierarchy is only an implementation convenience 
and not part of public API.</p>
  *
+ * <div class="note"><b>Reference:</b>
+ * “Lambert developed the regular Conformal Conic as the oblique aspect of a 
family containing the previously
+ * known polar Stereographic and regular Mercator projections. (…) If the 
standard parallels are symmetrical
+ * about the Equator, the regular Mercator results (although formulas must be 
revised). If the only standard
+ * parallel is a pole, the polar Stereographic results.” (Snyder, page 
105)</div>
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
  * @version 0.6

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -19,7 +19,6 @@ package org.apache.sis.referencing.opera
 import java.util.Map;
 import java.util.EnumMap;
 import org.opengis.util.FactoryException;
-import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
@@ -36,12 +35,8 @@ import org.apache.sis.internal.referenci
 import org.apache.sis.internal.referencing.provider.LambertConformalMichigan;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.util.DoubleDouble;
-import org.apache.sis.internal.util.Constants;
-import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.Workaround;
-import org.apache.sis.util.Debug;
 
 import static java.lang.Math.*;
 import static java.lang.Double.*;
@@ -118,6 +113,11 @@ public class LambertConformal extends Co
      *   <li>If φ1 = φ2 = ±90°, then this {@code n} value become ±1. The 
formulas in the transform and
      *       inverse transform methods become basically the same than the ones 
in {@link PolarStereographic},
      *       (de)normalization matrices contain NaN values.</li>
+     *   <li>Depending on how the formulas are written, <var>n</var> may be 
positive in the South hemisphere and
+     *       negative in the North hemisphere (or conversely). However Apache 
SIS adjusts the coefficients of the
+     *       (de)normalization matrices in order to keep <var>n</var> 
positive, because the formulas are slightly
+     *       more accurate for positive <var>n</var> values. However this 
adjustment is optional and can be disabled
+     *       in the constructor.</li>
      * </ul>
      */
     final double n;
@@ -329,6 +329,24 @@ public class LambertConformal extends Co
     }
 
     /**
+     * Returns the names of additional internal parameters which need to be 
taken in account when
+     * comparing two {@code LambertConformal} projections or formatting them 
in debug mode.
+     */
+    @Override
+    String[] getInternalParameterNames() {
+        return new String[] {"n"};
+    }
+
+    /**
+     * Returns the values of additional internal parameters which need to be 
taken in account when
+     * comparing two {@code LambertConformal} projections or formatting them 
in debug mode.
+     */
+    @Override
+    double[] getInternalParameterValues() {
+        return new double[] {n};
+    }
+
+    /**
      * Returns the sequence of <cite>normalization</cite> → {@code this} → 
<cite>denormalization</cite> transforms
      * as a whole. The transform returned by this method except 
(<var>longitude</var>, <var>latitude</var>)
      * coordinates in <em>degrees</em> and returns (<var>x</var>,<var>y</var>) 
coordinates in <em>metres</em>.
@@ -350,48 +368,6 @@ public class LambertConformal extends Co
     }
 
     /**
-     * Returns a copy of the parameter values for this projection.
-     * This method supplies a value only for the following parameters:
-     *
-     * <ul>
-     *   <li>Semi-major axis length of 1</li>
-     *   <li>Semi-minor axis length of <code>sqrt(1 - {@linkplain 
#excentricitySquared ℯ²})</code></li>
-     *   <li>Only one of the following:
-     *     <ul>
-     *       <li>Natural origin (1SP case)</li>
-     *     </ul>
-     *     or, in the 2SP case:
-     *     <ul>
-     *       <li>Standard parallel 1</li>
-     *       <li>Standard parallel 2</li>
-     *     </ul>
-     *   </li>
-     * </ul>
-     *
-     * No other parameters are set because only the above-cited ones are 
significant for the non-linear part
-     * of this projection.
-     *
-     * <div class="note"><b>Note:</b>
-     * This method is mostly for {@linkplain 
org.apache.sis.io.wkt.Convention#INTERNAL debugging purposes}
-     * since the isolation of non-linear parameters in this class is highly 
implementation dependent.
-     * Most GIS applications will instead be interested in the {@linkplain 
#getContextualParameters()
-     * contextual parameters}.</div>
-     *
-     * @return A copy of the parameter values for this normalized projection.
-     */
-    @Debug
-    @Override
-    public ParameterValueGroup getParameterValues() {
-        return getParameterValues(new String[] {
-            Constants.SEMI_MAJOR,
-            Constants.SEMI_MINOR,
-            Constants.STANDARD_PARALLEL_1,
-            Constants.STANDARD_PARALLEL_2,
-            "latitude_of_origin"
-        });
-    }
-
-    /**
      * Converts the specified (θ,φ) coordinate (units in radians) and stores 
the result in {@code dstPts}.
      * In addition, opportunistically computes the projection derivative if 
{@code derivate} is {@code true}.
      *
@@ -567,17 +543,4 @@ public class LambertConformal extends Co
             dstPts[dstOff+1] = PI/2 - 2*atan(pow(1/ρ, 1/n));
         }
     }
-
-    /**
-     * Compares the given object with this transform for equivalence.
-     *
-     * @return {@code true} if the given object is equivalent to this map 
projection.
-     */
-    @Override
-    public boolean equals(final Object object, final ComparisonMode mode) {
-        if (super.equals(object, mode)) {
-            return Numerics.epsilonEqual(n, ((LambertConformal) object).n, 
mode);
-        }
-        return false;
-    }
 }

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=1693133&r1=1693132&r2=1693133&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 Jul 28 17:18:30 2015
@@ -16,16 +16,14 @@
  */
 package org.apache.sis.referencing.operation.projection;
 
-import java.util.List;
-import java.util.ArrayList;
 import java.util.Map;
+import java.util.HashMap;
 import java.io.Serializable;
+import java.lang.reflect.Modifier;
 import org.opengis.metadata.Identifier;
-import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
-import org.opengis.parameter.GeneralParameterDescriptor;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransform2D;
@@ -34,18 +32,21 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.util.FactoryException;
 import org.apache.sis.util.Debug;
+import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.parameter.Parameters;
-import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
-import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.referencing.operation.transform.AbstractMathTransform2D;
 import org.apache.sis.referencing.operation.transform.ContextualParameters;
 import org.apache.sis.internal.referencing.provider.MapProjection;
 import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.util.DoubleDouble;
 import org.apache.sis.internal.util.Constants;
+import org.apache.sis.internal.util.Utilities;
 import org.apache.sis.internal.util.Numerics;
 
 import static java.lang.Math.*;
@@ -160,6 +161,17 @@ public abstract class NormalizedProjecti
     static final int MAXIMUM_ITERATIONS = 15;
 
     /**
+     * The internal parameter descriptors. Keys are implementation classes.  
Values are parameter descriptor groups
+     * containing at least a parameter for the {@link #excentricity} value, 
and optionally other internal parameter
+     * added by some subclasses.
+     *
+     * <p>Entries are created only when first needed. Those descriptors are 
usually never created since they are
+     * used only by {@link #getParameterDescriptors()}, which is itself 
invoked mostly for debugging purpose.</p>
+     */
+    @Debug
+    private static final Map<Class<?>,ParameterDescriptorGroup> DESCRIPTORS = 
new HashMap<>();
+
+    /**
      * The parameters used for creating this projection. They are used for 
formatting <cite>Well Known Text</cite> (WKT)
      * and error messages. Subclasses shall not use the values defined in this 
object for computation purpose, except at
      * construction time.
@@ -566,18 +578,11 @@ public abstract class NormalizedProjecti
     }
 
     /**
-     * Returns a copy of the parameter values for this projection.
-     * This base class supplies a value only for the following parameters:
-     *
-     * <ul>
-     *   <li>Semi-major axis length, which is set to 1.</li>
-     *   <li>Semi-minor axis length, which is set to
-     *       <code>sqrt(1 - {@linkplain #excentricitySquared ℯ²})</code>.</li>
-     * </ul>
-     *
-     * Subclasses must complete if needed. Many projections will not need to 
complete,
-     * because most parameters like the scale factor or the false 
easting/northing can
-     * be handled by the (de)normalization affine transforms.
+     * Returns a copy of non-linear internal parameter values of this {@code 
NormalizedProjection}.
+     * The returned group contained at least the {@link #excentricity} 
parameter value.
+     * Some subclasses add more non-linear parameters, but most of them do not 
because many parameters
+     * like the <cite>scale factor</cite> or the <cite>false 
easting/northing</cite> are handled by the
+     * {@linkplain ContextualParameters#getMatrix(boolean) (de)normalization 
affine transforms} instead.
      *
      * <div class="note"><b>Note:</b>
      * This method is mostly for {@linkplain 
org.apache.sis.io.wkt.Convention#INTERNAL debugging purposes}
@@ -585,56 +590,85 @@ public abstract class NormalizedProjecti
      * Most GIS applications will instead be interested in the {@linkplain 
#getContextualParameters()
      * contextual parameters}.</div>
      *
-     * @return A copy of the parameter values for this normalized projection.
+     * @return A copy of the internal parameter values for this normalized 
projection.
      */
     @Debug
     @Override
     public ParameterValueGroup getParameterValues() {
-        return getParameterValues(new String[] {
-            Constants.SEMI_MAJOR,
-            Constants.SEMI_MINOR
-        });
+        final ParameterValueGroup group = 
getParameterDescriptors().createValue();
+        group.parameter("excentricity").setValue(excentricity);
+        final String[] names  = getInternalParameterNames();
+        final double[] values = getInternalParameterValues();
+        for (int i=0; i<names.length; i++) {
+            group.parameter(names[i]).setValue(values[i]);
+        }
+        return group;
     }
 
     /**
-     * Filters the parameter descriptor in order to retain only the parameters 
of the given names, and
-     * sets the semi-major and semi-minor axis lengths. The specified 
parameters list should contains at
-     * least the {@code "semi_major"} and {@code "semi_minor"} strings.
+     * Returns a description of the non-linear internal parameters of this 
{@code NormalizedProjection}.
+     * The returned group contained at least a descriptor for the {@link 
#excentricity} parameter.
+     * Subclasses may add more parameters.
+     *
+     * <p>This method is for inspecting the parameter values of this 
non-linear kernel only,
+     * not for inspecting the {@linkplain #getContextualParameters() 
contextual parameters}.
+     * Inspecting the kernel parameter values is usually for debugging purpose 
only.</p>
      *
-     * <p>This filtered descriptor is used for displaying the parameter values 
of this non-linear kernel only,
-     * not for displaying the {@linkplain #getContextualParameters() 
contextual parameters}. Since displaying
-     * the kernel parameter values is for debugging purpose only, it is not 
worth to cache this descriptor.</p>
+     * @return A description of the internal parameters.
      */
     @Debug
-    final ParameterValueGroup getParameterValues(final String[] 
nonLinearParameters) {
-        ParameterDescriptorGroup descriptor = getParameterDescriptors();
-        final List<GeneralParameterDescriptor> filtered = new 
ArrayList<>(nonLinearParameters.length);
-        for (final GeneralParameterDescriptor p : descriptor.descriptors()) {
-            for (final String name : nonLinearParameters) {
-                if (IdentifiedObjects.isHeuristicMatchForName(p, name)) {
-                    filtered.add(p);
-                    break;
+    @Override
+    public ParameterDescriptorGroup getParameterDescriptors() {
+        Class<?> type = getClass();
+        while (!Modifier.isPublic(type.getModifiers())) {
+            type = type.getSuperclass();
+        }
+        ParameterDescriptorGroup group;
+        synchronized (DESCRIPTORS) {
+            group = DESCRIPTORS.get(type);
+            if (group == null) {
+                final ParameterBuilder builder = new 
ParameterBuilder().setRequired(true);
+                if (Utilities.isSIS(type)) {
+                    builder.setCodeSpace(Citations.SIS, "SIS");
                 }
+                final String[] names = getInternalParameterNames();
+                final ParameterDescriptor<?>[] parameters = new 
ParameterDescriptor<?>[names.length + 1];
+                for (int i=0; i<parameters.length; i++) {
+                    final ParameterDescriptor<?> p;
+                    if (i == 0) {
+                        final ParameterDescriptorGroup existing = 
CollectionsExt.first(DESCRIPTORS.values());
+                        if (existing != null) {
+                            p = (ParameterDescriptor<?>) 
existing.descriptor("excentricity");
+                        } else {
+                            p = builder.addName(Citations.SIS, 
"excentricity").createBounded(0, 1, Double.NaN, null);
+                        }
+                    } else {
+                        p = builder.addName(names[i-1]).create(Double.class, 
null);
+                    }
+                    parameters[i] = p;
+                }
+                group = 
builder.addName(CharSequences.camelCaseToSentence(type.getSimpleName())).createGroup(1,
 1, parameters);
+                DESCRIPTORS.put(type, group);
             }
         }
-        descriptor = new 
DefaultParameterDescriptorGroup(IdentifiedObjects.getProperties(descriptor),
-                1, 1, filtered.toArray(new 
GeneralParameterDescriptor[filtered.size()]));
-        /*
-         * Parameter values for the ellipsoid semi-major and semi-minor axis 
lengths are 1 and <= 1
-         * respectively because the denormalization (e.g. multiplication by a 
scale factor) will be
-         * applied by an affine transform after this NormalizedProjection.
-         */
-        final ParameterValueGroup values = descriptor.createValue();
-        for (final GeneralParameterDescriptor desc : filtered) {
-            final String name = desc.getName().getCode();
-            final ParameterValue<?> p = values.parameter(name);
-            switch (name) {
-                case Constants.SEMI_MAJOR: p.setValue(1.0); break;
-                case Constants.SEMI_MINOR: p.setValue(sqrt(1 - 
excentricitySquared)); break;
-                default: p.setValue(context.parameter(name).getValue());
-            }
-        }
-        return values;
+        return group;
+    }
+
+    /**
+     * Returns the names of any additional internal parameters (other than 
{@link #excentricity})
+     * that this projection has. The length of this array must be the same 
than the length of the
+     * {@link #getInternalParameterValues()} array, if the later is non-null.
+     */
+    String[] getInternalParameterNames() {
+        return CharSequences.EMPTY_ARRAY;
+    }
+
+    /**
+     * Returns the values of any additional internal parameters (other than 
{@link #excentricity}) that
+     * this projection has. Those values are also compared by {@link 
#equals(Object, ComparisonMode)}.
+     */
+    double[] getInternalParameterValues() {
+        return null;
     }
 
     /**
@@ -760,14 +794,20 @@ public abstract class NormalizedProjecti
     }
 
     /**
-     * Computes a hash code value for this map projection.
-     * The default implementation computes a value from the parameters given 
at construction time.
+     * Computes a hash code value for this {@code NormalizedProjection}.
      *
      * @return The hash code value.
      */
     @Override
     protected int computeHashCode() {
-        return context.hashCode() + 31 * super.computeHashCode();
+        long c = Double.doubleToLongBits(excentricity);
+        final double[] parameters = getInternalParameterValues();
+        if (parameters != null) {
+            for (int i=0; i<parameters.length; i++) {
+                c = c*31 + Double.doubleToLongBits(parameters[i]);
+            }
+        }
+        return super.computeHashCode() ^ Numerics.hashCode(c);
     }
 
     /**
@@ -817,7 +857,23 @@ public abstract class NormalizedProjecti
              * to use the 'excentricity', otherwise we would need to take the 
square of the
              * tolerance factor before comparing 'excentricitySquared'.
              */
-            return Numerics.epsilonEqual(e1, e2, mode);
+            if (Numerics.epsilonEqual(e1, e2, mode)) {
+                final double[] parameters = getInternalParameterValues();
+                if (parameters != null) {
+                    /*
+                     * super.equals(…) guarantees that the two objects are of 
the same class.
+                     * So in SIS implementation, this implies that the arrays 
have the same length.
+                     */
+                    final double[] others = that.getInternalParameterValues();
+                    assert others.length == parameters.length;
+                    for (int i=0; i<parameters.length; i++) {
+                        if (!Numerics.epsilonEqual(parameters[i], others[i], 
mode)) {
+                            return false;
+                        }
+                    }
+                }
+                return true;
+            }
         }
         return false;
     }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -874,14 +874,13 @@ public abstract class AbstractMathTransf
      * <p>The default implementation returns {@code true} if the following 
conditions are meet:</p>
      * <ul>
      *   <li>{@code object} is an instance of the same class than {@code 
this}. We require the
-     *        same class because there is no interface for the various kinds 
of transform.</li>
-     *   <li>The {@linkplain #getParameterDescriptors() parameter descriptors} 
are equal according
+     *       same class because there is no interface for the various kinds of 
transform.</li>
+     *   <li>If the hash code value has already been {@linkplain 
#computeHashCode() computed} for both
+     *       instances, their values are the same <i>(opportunist performance 
enhancement)</i>.</li>
+     *   <li>The {@linkplain #getContextualParameters() contextual parameters} 
are equal according
      *       the given comparison mode.</li>
      * </ul>
      *
-     * The {@linkplain #getParameterValues() parameter values} are 
<strong>not</strong> compared because
-     * subclasses can typically compare those values more efficiently by 
accessing to their member fields.
-     *
      * @param  object The object to compare with this transform.
      * @param  mode The strictness level of the comparison. Default to {@link 
ComparisonMode#STRICT STRICT}.
      * @return {@code true} if the given object is considered equals to this 
math transform.
@@ -909,8 +908,8 @@ public abstract class AbstractMathTransf
             if (mode.ordinal() >= ComparisonMode.IGNORE_METADATA.ordinal()) {
                 return true;
             }
-            return Utilities.deepEquals(this.getParameterDescriptors(),
-                                        that.getParameterDescriptors(), mode);
+            return Utilities.deepEquals(this.getContextualParameters(),
+                                        that.getContextualParameters(), mode);
         }
         return false;
     }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -562,7 +562,7 @@ public class ContextualParameters extend
      */
     @Override
     public int hashCode() {
-        return (normalize.hashCode() + 31*denormalize.hashCode()) ^ (int) 
serialVersionUID;
+        return (normalize.hashCode() + 31*denormalize.hashCode()) ^ 
Arrays.hashCode(values) ^ (int) serialVersionUID;
     }
 
     /**
@@ -575,9 +575,10 @@ public class ContextualParameters extend
     public boolean equals(final Object object) {
         if (object != null && object.getClass() == getClass()) {
             final ContextualParameters that = (ContextualParameters) object;
-            return Objects.equals(descriptor,  that.descriptor) &&
-                   Objects.equals(normalize,   that.normalize)  &&
-                   Objects.equals(denormalize, that.denormalize);
+            return Objects.equals(descriptor,  that.descriptor)  &&
+                   Objects.equals(normalize,   that.normalize)   &&
+                   Objects.equals(denormalize, that.denormalize) &&
+                    Arrays.equals(values,      that.values);
         }
         return false;
     }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConformalTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConformalTest.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConformalTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConformalTest.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -73,16 +73,22 @@ public final strictfp class LambertConfo
 
     /**
      * Tests the WKT formatting of {@link NormalizedProjection}. For the 
Lambert Conformal projection, we expect
-     * the standard parallels or the latitude of origin in addition to the 
semi-major and semi-minor axis length.
+     * the internal {@code n} parameter in addition to the excentricity.
+     *
+     * <div class="section">Note on accuracy</div>
+     * The value of the excentricity parameter should be fully accurate 
because it is calculated using only the
+     * {@link Math#sqrt(double)} function (ignoring basic algebraic 
operations) which, according javadoc, must
+     * give the result closest to the true mathematical result. But the 
functions involved in the calculation of
+     * <var>n</var> do not have such strong guarantees. So we use a regular 
expression in this test for ignoring
+     * the 2 last digits of <var>n</var>.
      */
     @Test
     public void testNormalizedWKT() {
         createNormalizedProjection(true, 40);
-        assertWktEquals(
-                "PARAM_MT[“Lambert_Conformal_Conic_1SP”,\n" +
-                "  PARAMETER[“semi_major”, 1.0],\n" +
-                "  PARAMETER[“semi_minor”, 0.9966471893352525],\n" +
-                "  PARAMETER[“latitude_of_origin”, 40.0]]");
+        assertWktEqualsRegex("\\Q" +
+                "PARAM_MT[“Lambert conformal”,\n" +
+                "  PARAMETER[“excentricity”, 0.08181919084262157],\n" +
+                "  PARAMETER[“n”, 0.64278760968653\\E\\d*\\]\\]");  // 
0.6427876096865393 in the original test.
     }
 
     /**

Modified: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -65,16 +65,17 @@ public final strictfp class MercatorTest
 
     /**
      * Tests the WKT formatting of {@link NormalizedProjection}. For the 
Mercator projection, we expect only
-     * the semi-major and semi-minor axis length. We expect nothing else 
because all other parameters are used
+     * the ellipsoid excentricity. We expect nothing else because all other 
parameters are used
      * by the (de)normalization affine transforms instead than the {@link 
Mercator} class itself.
+     *
+     * @see LambertConformalTest#testNormalizedWKT()
      */
     @Test
     public void testNormalizedWKT() {
         createNormalizedProjection(true);
         assertWktEquals(
-                "PARAM_MT[“Mercator_2SP”,\n" +
-                "  PARAMETER[“semi_major”, 1.0],\n" +
-                "  PARAMETER[“semi_minor”, 0.9966471893352525]]");
+                "PARAM_MT[“Mercator”,\n" +
+                "  PARAMETER[“excentricity”, 0.08181919084262157]]");
     }
 
     /**

Modified: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ProjectionResultComparator.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ProjectionResultComparator.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ProjectionResultComparator.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ProjectionResultComparator.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -19,6 +19,7 @@ package org.apache.sis.referencing.opera
 import java.util.Arrays;
 import java.util.List;
 import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.Matrix;
 import org.apache.sis.internal.referencing.Formulas;
@@ -170,6 +171,15 @@ final strictfp class ProjectionResultCom
     }
 
     /**
+     * Delegates to the {@link #tested} implementation.
+     */
+    @Debug
+    @Override
+    public ParameterDescriptorGroup getParameterDescriptors() {
+        return tested.getParameterDescriptors();
+    }
+
+    /**
      * Delegates to the {@link #tested} implementation.
      */
     @Debug

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=1693133&r1=1693132&r2=1693133&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 Jul 28 17:18:30 2015
@@ -366,6 +366,20 @@ public abstract strictfp class MathTrans
     }
 
     /**
+     * Asserts that the current {@linkplain #transform transform} produces a 
WKT matching the given regular expression.
+     *
+     * @param expected A regular expression for the expected WKT.
+     *
+     * @see #printInternalWKT()
+     *
+     * @since 0.6
+     */
+    protected final void assertWktEqualsRegex(final String expected) {
+        assertNotNull("The 'transform' field shall be assigned a value.", 
transform);
+        ReferencingAssert.assertWktEqualsRegex(Convention.WKT1, expected, 
transform);
+    }
+
+    /**
      * Prints the current {@linkplain #transform transform} as normal and 
internal WKT.
      * This method is for debugging purpose only.
      *
@@ -373,6 +387,7 @@ public abstract strictfp class MathTrans
      */
     @Debug
     protected final void printInternalWKT() {
+        @SuppressWarnings("UseOfSystemOutOrSystemErr")
         final TableAppender table = new TableAppender(System.out);
         table.setMultiLinesCells(true);
         table.appendHorizontalSeparator();

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DefaultFactories.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DefaultFactories.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DefaultFactories.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DefaultFactories.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.IdentityHashMap;
 import java.util.ServiceLoader;
 import java.util.ServiceConfigurationError;
+import org.apache.sis.internal.util.Utilities;
 
 
 /**
@@ -86,8 +87,7 @@ public final class DefaultFactories exte
         if (factory == null && !FACTORIES.containsKey(type)) {
             T fallback = null;
             for (final T candidate : ServiceLoader.load(type)) {
-                final Class<?> ct = candidate.getClass();
-                if (ct.getName().startsWith("org.apache.sis.")) {
+                if (Utilities.isSIS(candidate.getClass())) {
                     if (factory != null) {
                         throw new ServiceConfigurationError("Found two 
implementations of " + type);
                     }

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java?rev=1693133&r1=1693132&r2=1693133&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
 [UTF-8] Tue Jul 28 17:18:30 2015
@@ -39,6 +39,16 @@ public final class Utilities extends Sta
     }
 
     /**
+     * Returns {@code true} if the given class is an Apache SIS class.
+     *
+     * @param  type The class to verify.
+     * @return {@code true} if the given class is an Apache SIS class.
+     */
+    public static boolean isSIS(final Class<?> type) {
+        return type.getName().startsWith("org.apache.sis.");
+    }
+
+    /**
      * Appends to the given buffer only the characters that are valid for a 
Unicode identifier.
      * The given separator character is append before the given {@code text} 
only if the buffer
      * is not empty and at least one {@code text} character is valid.


Reply via email to