Author: desruisseaux
Date: Wed Jul 29 14:55:12 2015
New Revision: 1693283

URL: http://svn.apache.org/r1693283
Log:
Consolidation of the tolerance threshold when comparing objects: try to use 
thresholds having a physical meaning:
- LINEAR_THRESHOLD (1 cm) when comparing the Ellipsoid axis length,
- ANGULAR_THRESHOLD (equivalent to about 1 cm on Earth) when comparing the 
PrimeMeridian Greenwich longitude,
- A threshold computed in a way that describe an error of about 1 cm on Earth 
when comparing map projection excentricity.

Modified:
    
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
    
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
    
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.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/AbstractLinearTransform.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/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ComparisonMode.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java
    
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java

Modified: 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -108,7 +108,7 @@ public class ReferenceSystemMetadata ext
     public boolean equals(final Object object, final ComparisonMode mode) {
         if (super.equals(object, mode) && (object instanceof ReferenceSystem)) 
{
             final ReferenceSystem that = (ReferenceSystem) object;
-            if (mode.ordinal() >= ComparisonMode.IGNORE_METADATA.ordinal()) {
+            if (mode.isIgnoringMetadata()) {
                 // Compare the name because it was ignored by super.equals(…) 
in "ignore metadata" mode.
                 return Objects.equals(getName(), that.getName());
             }

Modified: 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -346,16 +346,17 @@ public final class ServiceParameter exte
                 that.getDefaultValue() == null &&
                 that.getValueClass()   == getValueClass())
             {
-                if (mode.ordinal() >= 
ComparisonMode.IGNORE_METADATA.ordinal()) {
+                if (mode.isIgnoringMetadata()) {
                     return Objects.equals(toString(getName()), 
toString(that.getName()));
+                    // super.equals(…) already compared 'getName()' in others 
mode.
                 }
                 return deepEquals(that.getDescription(), getDescription(), 
mode) &&
-                       that.getDirection()     == getDirection()     &&
-                       that.getMinimumOccurs() == getMinimumOccurs() &&
-                       that.getMaximumOccurs() == getMaximumOccurs() &&
-                       that.getValidValues()   == null &&
-                       that.getMinimumValue()  == null &&
-                       that.getMaximumValue()  == null;
+                                  that.getDirection()     == getDirection()    
 &&
+                                  that.getMinimumOccurs() == 
getMinimumOccurs() &&
+                                  that.getMaximumOccurs() == 
getMaximumOccurs() &&
+                                  that.getValidValues()   == null &&
+                                  that.getMinimumValue()  == null &&
+                                  that.getMaximumValue()  == null;
             }
         }
         return false;

Modified: 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -29,6 +29,7 @@ import org.opengis.annotation.UML;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.ExtendedElementInformation;
 import org.apache.sis.internal.util.Citations;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.measure.ValueRange;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
@@ -48,7 +49,6 @@ import org.apache.sis.xml.IdentifiedObje
 
 import static org.apache.sis.metadata.PropertyComparator.*;
 import static org.apache.sis.metadata.ValueExistencePolicy.isNullOrEmpty;
-import static org.apache.sis.internal.util.Numerics.floatEpsilonEqual;
 import static org.apache.sis.internal.util.CollectionsExt.snapshot;
 import static org.apache.sis.internal.util.CollectionsExt.modifiableCopy;
 import static org.apache.sis.util.collection.Containers.hashMapCapacity;
@@ -176,9 +176,8 @@ class PropertyAccessor {
     private final Method[] setters;
 
     /**
-     * The JavaBeans property names. They are computed at construction time,
-     * {@linkplain String#intern() interned} then cached. Those names are often
-     * the same than field names (at least in SIS implementation), so it is
+     * The JavaBeans property names. They are computed at construction time, 
{@linkplain String#intern() interned}
+     * then cached. Those names are often the same than field names (at least 
in SIS implementation), so it is
      * reasonable to intern them in order to share {@code String} instances.
      *
      * <p>This array shall not contains any {@code null} elements.</p>
@@ -1112,10 +1111,17 @@ class PropertyAccessor {
                 // Empty strings are also considered equal to null (this is 
more questionable).
                 continue;
             }
-            if (!Utilities.deepEquals(value1, value2, mode)) {
-                if (mode.ordinal() >= ComparisonMode.APPROXIMATIVE.ordinal() 
&& floatEpsilonEqual(value1, value2)) {
-                    continue; // Accept this slight difference.
-                }
+            final boolean equals;
+            if ((value1 instanceof Double || value1 instanceof Float) &&
+                (value2 instanceof Double || value2 instanceof Float))
+            {
+                equals = Numerics.epsilonEqual(((Number) value1).doubleValue(),
+                                               ((Number) 
value2).doubleValue(), mode);
+            } else {
+                equals = Utilities.deepEquals(value1, value2, mode);
+            }
+            if (!equals) {
+                assert (mode != ComparisonMode.DEBUG) : type.getSimpleName() + 
'.' + names[i] + " differ.";
                 return false;
             }
         }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -532,6 +532,7 @@ public abstract class AbstractEnvelope i
      *
      * @since 0.4
      */
+    @SuppressWarnings("ReturnOfCollectionOrArrayField")
     public Envelope[] toSimpleEnvelopes() {
         long isWrapAround = 0; // A bitmask of the dimensions having a "wrap 
around" behavior.
         CoordinateReferenceSystem crs = null;

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -36,7 +36,6 @@ import org.apache.sis.referencing.crs.De
 import org.apache.sis.referencing.cs.AxesConvention;
 
 import static java.util.Collections.singletonMap;
-import static org.apache.sis.internal.util.Numerics.epsilonEqual;
 
 
 /**
@@ -59,27 +58,6 @@ public final class ReferencingUtilities
     }
 
     /**
-     * Returns {@code true} if the Greenwich longitude of the {@code actual} 
prime meridian is equals to the
-     * Greenwich longitude of the {@code expected} prime meridian. The 
comparison is performed in unit of the
-     * expected prime meridian.
-     *
-     * <p>A {@code null} argument is interpreted as "unknown prime meridian". 
Consequently this method
-     * unconditionally returns {@code false} if one or both arguments is 
{@code null}.</p>
-     *
-     * @param expected The expected prime meridian, or {@code null}.
-     * @param actual The actual prime meridian, or {@code null}.
-     * @return {@code true} if both prime meridian have the same Greenwich 
longitude,
-     *         in unit of the expected prime meridian.
-     */
-    public static boolean isGreenwichLongitudeEquals(final PrimeMeridian 
expected, final PrimeMeridian actual) {
-        if (expected == null || actual == null) {
-            return false; // See method javadoc.
-        }
-        return (expected == actual) || 
epsilonEqual(expected.getGreenwichLongitude(),
-                getGreenwichLongitude(actual, expected.getAngularUnit()));
-    }
-
-    /**
      * Returns the longitude value relative to the Greenwich Meridian, 
expressed in the specified units.
      * This method provides the same functionality than {@link 
DefaultPrimeMeridian#getGreenwichLongitude(Unit)},
      * but on arbitrary implementation.

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -20,7 +20,7 @@ import java.util.Map;
 import javax.measure.unit.SI;
 import javax.measure.unit.Unit;
 import javax.measure.quantity.Length;
-import javax.measure.converter.ConversionException;
+import javax.measure.converter.UnitConverter;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -44,7 +44,6 @@ import org.apache.sis.util.resources.Err
 
 import static java.lang.Math.*;
 import static java.lang.Double.*;
-import static org.apache.sis.internal.util.Numerics.epsilonEqual;
 import static org.apache.sis.util.ArgumentChecks.ensureStrictlyPositive;
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
@@ -422,13 +421,10 @@ public class DefaultEllipsoid extends Ab
      * Sets the semi-major axis value.
      * This method is invoked by JAXB at unmarshalling time only.
      *
-     * @throws ConversionException If semi-major and semi-minor axes use 
inconsistent units
-     *         and we can not convert from one to the other.
-     *
      * @see #setSecondDefiningParameter(SecondDefiningParameter)
      * @see #afterUnmarshal()
      */
-    private void setSemiMajorAxisMeasure(final Measure measure) throws 
ConversionException {
+    private void setSemiMajorAxisMeasure(final Measure measure) {
         if (semiMajorAxis != 0) {
             warnDuplicated("semiMajorAxis");
         } else {
@@ -525,13 +521,10 @@ public class DefaultEllipsoid extends Ab
      * value or the semi minor axis value, according to what have been defined 
in the
      * second defining parameter given. This is for JAXB unmarshalling process 
only.
      *
-     * @throws ConversionException If semi-major and semi-minor axes use 
inconsistent units
-     *         and we can not convert from one to the other.
-     *
      * @see #setSemiMajorAxisMeasure(Measure)
      * @see #afterUnmarshal()
      */
-    private void setSecondDefiningParameter(SecondDefiningParameter second) 
throws ConversionException {
+    private void setSecondDefiningParameter(SecondDefiningParameter second) {
         while (second.secondDefiningParameter != null) {
             second = second.secondDefiningParameter;
         }
@@ -563,15 +556,13 @@ public class DefaultEllipsoid extends Ab
      * Ensures that the semi-minor axis uses the same unit than the semi-major 
one.
      * The {@link #unit} field shall be set to the semi-major axis unit before 
this method call.
      *
-     * @param  uom The semi-minor axis unit.
-     * @throws ConversionException If semi-major and semi-minor axes use 
inconsistent units
-     *         and we can not convert from one to the other.
+     * @param uom The semi-minor axis unit.
      */
-    private void harmonizeAxisUnits(final Unit<Length> uom) throws 
ConversionException {
+    private void harmonizeAxisUnits(final Unit<Length> uom) {
         if (unit == null) {
             unit = uom;
         } else if (uom != null && uom != unit) {
-            semiMinorAxis = uom.getConverterToAny(unit).convert(semiMinorAxis);
+            semiMinorAxis = uom.getConverterTo(unit).convert(semiMinorAxis);
         }
     }
 
@@ -730,12 +721,48 @@ public class DefaultEllipsoid extends Ab
                 }
                 // Fall through
             }
+            case IGNORE_METADATA: {
+                /*
+                 * "Inverse flattening factor" and "semi-minor axis length" 
are computed from each other,
+                 * so we do not need to compare both of them. But in 
non-approximative mode we nevertheless
+                 * compare both as a safety against rounding errors.
+                 */
+                if (!Numerics.equals(getInverseFlattening(), ((Ellipsoid) 
object).getInverseFlattening())) {
+                    return false;
+                }
+                // Fall through
+            }
             default: {
+                /*
+                 * Note: DefaultPrimeMeridian.equals(object, IGNORE_METADATA) 
ignores the unit.
+                 * But we do not perform the same relaxation here because the 
ellipsoid unit will
+                 * become the linear unit of map projections if the user does 
not overwrite them
+                 * with an explicit CoordinateSystem declaration.
+                 */
                 final Ellipsoid that = (Ellipsoid) object;
-                return epsilonEqual(getSemiMajorAxis(),     
that.getSemiMajorAxis(),     mode) &&
-                       epsilonEqual(getSemiMinorAxis(),     
that.getSemiMinorAxis(),     mode) &&
-                       epsilonEqual(getInverseFlattening(), 
that.getInverseFlattening(), mode) &&
-                       Objects.equals(getAxisUnit(),        
that.getAxisUnit());
+                final Unit<Length> unit = getAxisUnit();  // In case the user 
override this method.
+                if (!Objects.equals(unit, that.getAxisUnit())) {
+                    return false;
+                }
+                final UnitConverter c = mode.isApproximative() ? 
unit.getConverterTo(SI.METRE) : null;
+                boolean isMinor = false;
+                double v1 = this.getSemiMajorAxis();
+                double v2 = that.getSemiMajorAxis();
+                if (c == null ? Numerics.equals(v1, v2) : 
Numerics.epsilonEqual(
+                        c.convert(v1), c.convert(v2), 
Formulas.LINEAR_TOLERANCE))
+                {
+                    isMinor = true;
+                    v1 = this.getSemiMinorAxis();
+                    v2 = that.getSemiMinorAxis();
+                    if (c == null ? Numerics.equals(v1, v2) : 
Numerics.epsilonEqual(
+                            c.convert(v1), c.convert(v2), 
Formulas.LINEAR_TOLERANCE))
+                    {
+                        return true;
+                    }
+                }
+                assert (mode != ComparisonMode.DEBUG) : 
Numerics.messageForDifference(
+                        isMinor ? "semiMinorAxis" : "semiMajorAxis", v1, v2);
+                return false;
             }
         }
     }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -29,6 +29,7 @@ import org.opengis.metadata.Identifier;
 import org.opengis.referencing.datum.PrimeMeridian;
 import org.opengis.referencing.crs.GeneralDerivedCRS;
 import org.apache.sis.referencing.AbstractIdentifiedObject;
+import org.apache.sis.internal.referencing.ReferencingUtilities;
 import org.apache.sis.internal.util.PatchedUnitFormat;
 import org.apache.sis.internal.metadata.WKTKeywords;
 import org.apache.sis.internal.jaxb.gco.Measure;
@@ -39,10 +40,10 @@ import org.apache.sis.util.ComparisonMod
 
 import static org.apache.sis.util.ArgumentChecks.ensureFinite;
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
-import static 
org.apache.sis.internal.referencing.ReferencingUtilities.canSetProperty;
 
 // Branch-dependent imports
 import java.util.Objects;
+import org.apache.sis.internal.referencing.Formulas;
 
 
 /**
@@ -265,7 +266,7 @@ public class DefaultPrimeMeridian extend
      * Invoked by JAXB for setting the Greenwich longitude and its unit of 
measurement.
      */
     private void setGreenwichMeasure(final Measure measure) {
-        if (measure != null && canSetProperty(DefaultPrimeMeridian.class,
+        if (measure != null && 
ReferencingUtilities.canSetProperty(DefaultPrimeMeridian.class,
                 "setGreenwichMeasure", "greenwichLongitude", 
greenwichLongitude != 0 || angularUnit != null))
         {
             greenwichLongitude = measure.value;
@@ -299,10 +300,7 @@ public class DefaultPrimeMeridian extend
         if (object == this) {
             return true; // Slight optimization.
         }
-        if (!super.equals(object, mode)) {
-            return false;
-        }
-        switch (mode) {
+        if (super.equals(object, mode)) switch (mode) {
             case STRICT: {
                 final DefaultPrimeMeridian that = (DefaultPrimeMeridian) 
object;
                 return Numerics.equals(this.greenwichLongitude, 
that.greenwichLongitude) &&
@@ -314,16 +312,25 @@ public class DefaultPrimeMeridian extend
                         Objects.equals(getAngularUnit(),        
that.getAngularUnit());
             }
             default: {
-                final DefaultPrimeMeridian that = castOrCopy((PrimeMeridian) 
object);
-                return 
Numerics.epsilonEqual(this.getGreenwichLongitude(NonSI.DEGREE_ANGLE),
-                                             
that.getGreenwichLongitude(NonSI.DEGREE_ANGLE), mode);
-                /*
-                 * Note: if mode==IGNORE_METADATA, we relax the unit check 
because EPSG uses
-                 *       sexagesimal degrees for the Greenwich meridian. 
Requirying the same
-                 *       unit prevent Geodetic.isWGS84(...) method to 
recognize EPSG's WGS84.
-                 */
+                final double v1 = getGreenwichLongitude(NonSI.DEGREE_ANGLE);
+                final double v2 = 
ReferencingUtilities.getGreenwichLongitude((PrimeMeridian) object, 
NonSI.DEGREE_ANGLE);
+                if (mode == ComparisonMode.IGNORE_METADATA) {
+                    /*
+                     * We relax the check on unit of measurement because EPSG 
uses sexagesimal degrees
+                     * for the Greenwich meridian.  Requirying the same unit 
would make more difficult
+                     * for isWGS84(…) methods to recognize EPSG's WGS84. We 
allow this relaxation here
+                     * because the unit of the prime meridian is usually not 
inherited by axes (indeed,
+                     * they are often not the same in the EPSG dataset). The 
same is not true for other
+                     * objects like DefaultEllipsoid.
+                     */
+                    return Numerics.equals(v1, v2);
+                } else if (Numerics.epsilonEqual(v1, v2, 
Formulas.ANGULAR_TOLERANCE)) {
+                    return true;
+                }
+                assert (mode != ComparisonMode.DEBUG) : 
Numerics.messageForDifference("greenwichLongitude", v1, v2);
             }
         }
+        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=1693283&r1=1693282&r2=1693283&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] Wed Jul 29 14:55:12 2015
@@ -133,14 +133,19 @@ public abstract class NormalizedProjecti
 
     /**
      * Maximum difference allowed when comparing longitudes or latitudes in 
radians.
-     * The current value take the system-wide angular tolerance value 
(equivalent to
+     * The current value takes the system-wide angular tolerance value 
(equivalent to
      * about 1 cm on Earth) converted to radians.
      *
      * <p>Some formulas use this tolerance value for testing sines or cosines 
of an angle.
      * In the sine case, this is justified because sin(θ) ≅ θ when θ is small.
      * Similar reasoning applies to cosine with cos(θ) ≅ θ + π/2 when θ is 
small.</p>
+     *
+     * <p>Some formulas may use this tolerance value as a <em>linear</em> 
tolerance on the unit sphere.
+     * This is okay because the arc length for an angular tolerance θ is r⋅θ, 
but in this class r=1.</p>
      */
     static final double ANGULAR_TOLERANCE = Formulas.ANGULAR_TOLERANCE * 
(PI/180);
+    // Note: an alternative way to compute this value could be 
Formulas.LINEAR_TOLERANCE / AUTHALIC_RADIUS.
+    // But the later is only 0.07% lower than the current value.
 
     /**
      * Desired accuracy for the result of iterative computations, in radians.
@@ -150,7 +155,7 @@ public abstract class NormalizedProjecti
      * So if the linear tolerance is 1 cm, then the accuracy that we will seek 
for is 0.25 cm (about
      * 4E-10 radians). The 0.25 factor is a safety margin for meeting the 1 cm 
accuracy.</p>
      */
-    static final double ITERATION_TOLERANCE = Formulas.ANGULAR_TOLERANCE * 
(PI/180) * 0.25;
+    static final double ITERATION_TOLERANCE = ANGULAR_TOLERANCE * 0.25;
 
     /**
      * Maximum number of iterations for iterative computations.
@@ -832,50 +837,83 @@ public abstract class NormalizedProjecti
      * @return {@code true} if the given object is equivalent to this map 
projection.
      */
     @Override
+    @SuppressWarnings("fallthrough")
     public boolean equals(final Object object, final ComparisonMode mode) {
         if (object == this) {
             return true;
         }
-        if (super.equals(object, mode)) {
-            final double e1, e2;
-            final NormalizedProjection that = (NormalizedProjection) object;
-            if (mode.ordinal() < ComparisonMode.IGNORE_METADATA.ordinal()) {
+        if (!super.equals(object, mode)) {
+            return false;
+        }
+        final NormalizedProjection that = (NormalizedProjection) object;
+        switch (mode) {
+            case STRICT:
+            case BY_CONTRACT: {
                 if (!Objects.equals(context, that.context)) {
                     return false;
                 }
-                e1 = this.excentricitySquared;
-                e2 = that.excentricitySquared;
-            } else {
-                e1 = this.excentricity;
-                e2 = that.excentricity;
+                // Fall through for comparing the excentricity.
+            }
+            case IGNORE_METADATA: {
+                /*
+                 * There is no need to compare both 'excentricity' and 
'excentricitySquared' since the former
+                 * is computed from the later. We are better to compare 
'excentricitySquared' since it is the
+                 * original value from which the other value is derived.
+                 */
+                if (!Numerics.equals(excentricitySquared, 
that.excentricitySquared)) {
+                    return false;
+                }
+                break;
+            }
+            default: {
+                /*
+                 * We want to compare the excentricity with a tolerance 
threshold corresponding approximatively
+                 * to an error of 1 cm on Earth. The excentricity for an 
ellipsoid of semi-major axis a=1 is:
+                 *
+                 *     ℯ² = 1 - b²
+                 *
+                 * If we add a slight ε error to the semi-minor axis length 
(where ε will be our linear tolerance
+                 * threshold), we get:
+                 *
+                 *     (ℯ + ε′)²    =    1 - (b + ε)²    ≈    1 - (b² + 2⋅b⋅ε) 
   assuming ε ≪ b
+                 *
+                 * Replacing  1 - b²  by  ℯ²:
+                 *
+                 *     ℯ² + 2⋅ℯ⋅ε′  ≈   ℯ² - 2⋅b⋅ε
+                 *
+                 * After a few rearrangements:
+                 *
+                 *     ε′  ≈   ε⋅(ℯ - 1/ℯ)
+                 *
+                 * Note that  ε′  is negative for  ℯ < 1  so we actually need 
to compute  ε⋅(1/ℯ - ℯ)  instead.
+                 * The result is less than 2E-8 for the excentricity of the 
Earth.
+                 */
+                final double e = max(excentricity, that.excentricity);
+                if (!Numerics.epsilonEqual(excentricity, that.excentricity, 
ANGULAR_TOLERANCE * (1/e - e))) {
+                    assert (mode != ComparisonMode.DEBUG) : 
Numerics.messageForDifference(
+                            "excentricity", excentricity, that.excentricity);
+                    return false;
+                }
+                break;
             }
+        }
+        final double[] parameters = getInternalParameterValues();
+        if (parameters != null) {
             /*
-             * There is no need to compare both 'excentricity' and 
'excentricitySquared' since
-             * the former is computed from the later. In strict comparison 
mode, we are better
-             * to compare the 'excentricitySquared' since it is the original 
value from which
-             * the other value is derived. However in approximative comparison 
mode, we need
-             * to use the 'excentricity', otherwise we would need to take the 
square of the
-             * tolerance factor before comparing 'excentricitySquared'.
+             * 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.
              */
-            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;
-                        }
-                    }
+            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)) {
+                    assert (mode != ComparisonMode.DEBUG) : 
Numerics.messageForDifference(
+                            getInternalParameterNames()[i], parameters[i], 
others[i]);
+                    return false;
                 }
-                return true;
             }
         }
-        return false;
+        return true;
     }
 
 

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractLinearTransform.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractLinearTransform.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractLinearTransform.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractLinearTransform.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -64,6 +64,7 @@ abstract class AbstractLinearTransform e
      * Returns a copy of the matrix that user can modify.
      */
     @Override
+    @SuppressWarnings("CloneDoesntCallSuperClone")
     public final Matrix clone() {
         return Matrices.copy(this);
     }
@@ -151,10 +152,8 @@ abstract class AbstractLinearTransform e
             return true;
         }
         if (object != null) {
-            if (getClass() == object.getClass()) {
-                if (mode.ordinal() < ComparisonMode.APPROXIMATIVE.ordinal()) {
-                    return equalsSameClass(object);
-                }
+            if (getClass() == object.getClass() && !mode.isApproximative()) {
+                return equalsSameClass(object);
             }
             if (mode != ComparisonMode.STRICT) {
                 if (object instanceof LinearTransform) {

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=1693283&r1=1693282&r2=1693283&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] Wed Jul 29 14:55:12 2015
@@ -895,7 +895,7 @@ public abstract class AbstractMathTransf
              * If the classes are the same, then the hash codes should be 
computed in the same way. Since those
              * codes are cached, this is an efficient way to quickly check if 
the two objects are different.
              */
-            if (mode.ordinal() < ComparisonMode.APPROXIMATIVE.ordinal()) {
+            if (!mode.isApproximative()) {
                 final int tc = hashCode;
                 if (tc != 0) {
                     final int oc = that.hashCode;
@@ -905,7 +905,7 @@ public abstract class AbstractMathTransf
                 }
             }
             // See the policy documented in the LenientComparable javadoc.
-            if (mode.ordinal() >= ComparisonMode.IGNORE_METADATA.ordinal()) {
+            if (mode.isIgnoringMetadata()) {
                 return true;
             }
             return Utilities.deepEquals(this.getContextualParameters(),

Modified: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -22,7 +22,6 @@ import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.datum.PrimeMeridian;
-import org.apache.sis.referencing.datum.DefaultPrimeMeridian;
 import org.apache.sis.referencing.datum.HardCodedDatum;
 import org.apache.sis.referencing.crs.HardCodedCRS;
 import org.apache.sis.internal.metadata.WKTKeywords;
@@ -31,8 +30,6 @@ import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
-import static java.util.Collections.singletonMap;
-import static org.opengis.referencing.IdentifiedObject.NAME_KEY;
 import static org.apache.sis.internal.referencing.ReferencingUtilities.*;
 
 
@@ -46,26 +43,6 @@ import static org.apache.sis.internal.re
  */
 public final strictfp class ReferencingUtilitiesTest extends TestCase {
     /**
-     * Tests {@link 
ReferencingUtilities#isGreenwichLongitudeEquals(PrimeMeridian, PrimeMeridian)}.
-     */
-    @Test
-    public void testIsGreenwichLongitudeEquals() {
-        assertFalse(isGreenwichLongitudeEquals(null, null)); // "null" 
interpreted as "unknown".
-        assertFalse(isGreenwichLongitudeEquals(null, 
HardCodedDatum.GREENWICH));
-        assertFalse(isGreenwichLongitudeEquals(HardCodedDatum.GREENWICH, 
null));
-        assertFalse(isGreenwichLongitudeEquals(HardCodedDatum.GREENWICH, 
HardCodedDatum.PARIS));
-        assertFalse(isGreenwichLongitudeEquals(HardCodedDatum.PARIS, 
HardCodedDatum.PARIS_RGS));
-        assertFalse(isGreenwichLongitudeEquals(HardCodedDatum.PARIS_RGS, 
HardCodedDatum.PARIS));
-        assertTrue (isGreenwichLongitudeEquals(HardCodedDatum.PARIS, 
HardCodedDatum.PARIS));
-        /*
-         * Test two prime meridians using different units (Paris in grade and 
Paris in degrees).
-         */
-        final PrimeMeridian pd = new 
DefaultPrimeMeridian(singletonMap(NAME_KEY, "Paris"), 2.33722917, 
NonSI.DEGREE_ANGLE);
-        assertTrue(isGreenwichLongitudeEquals(HardCodedDatum.PARIS, pd));
-        assertTrue(isGreenwichLongitudeEquals(pd, HardCodedDatum.PARIS));
-    }
-
-    /**
      * Tests {@link ReferencingUtilities#getGreenwichLongitude(PrimeMeridian, 
Unit)}.
      */
     @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=1693283&r1=1693282&r2=1693283&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] Wed Jul 29 14:55:12 2015
@@ -68,7 +68,7 @@ public final strictfp class MercatorTest
      * 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()
+     * @see LambertConicConformalTest#testNormalizedWKT()
      */
     @Test
     public void testNormalizedWKT() {

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -203,10 +203,10 @@ public class SimpleIdentifiedObject impl
         }
         if (object instanceof IdentifiedObject) {
             if (mode != ComparisonMode.STRICT || object.getClass() == 
getClass()) {
-                final IdentifiedObject that = (IdentifiedObject) object;
-                if (mode.ordinal() >= 
ComparisonMode.IGNORE_METADATA.ordinal()) {
+                if (mode.isIgnoringMetadata()) {
                     return true;
                 }
+                final IdentifiedObject that = (IdentifiedObject) object;
                 return Objects.equals(getName(), that.getName()) &&
                         isNullOrEmpty(that.getIdentifiers()) &&
                         isNullOrEmpty(that.getAlias()) &&

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -18,6 +18,7 @@ package org.apache.sis.internal.util;
 
 import java.util.Map;
 import java.util.HashMap;
+import org.apache.sis.util.Debug;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.ComparisonMode;
 
@@ -30,7 +31,7 @@ import static java.lang.Math.abs;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.4
+ * @version 0.6
  * @module
  */
 public final class Numerics extends Static {
@@ -58,9 +59,9 @@ public final class Numerics extends Stat
      * Helper method for the construction of the {@link #CACHE} map.
      */
     private static void cache(final double value) {
-        Double key;
-        key = Double.valueOf( value); CACHE.put(key, key);
-        key = Double.valueOf(-value); CACHE.put(key, key);
+        Double boxed;
+        boxed =  value; CACHE.put(boxed, boxed);
+        boxed = -value; CACHE.put(boxed, boxed);
     }
 
     /**
@@ -146,9 +147,9 @@ public final class Numerics extends Stat
      * @return The given value as a {@code Double}.
      */
     public static Double valueOf(final double value) {
-        final Double n = Double.valueOf(value);
-        final Object candidate = CACHE.get(value);
-        return (candidate != null) ? (Double) candidate : n;
+        final Double boxed = value;
+        final Object candidate = CACHE.get(boxed);
+        return (candidate != null) ? (Double) candidate : boxed;
     }
 
     /**
@@ -188,14 +189,14 @@ public final class Numerics extends Stat
      * Returns {@code true} if the given floats are equals. Positive and 
negative zero are
      * considered different, while a NaN value is considered equal to all 
other NaN values.
      *
-     * @param  o1 The first value to compare.
-     * @param  o2 The second value to compare.
+     * @param  v1 The first value to compare.
+     * @param  v2 The second value to compare.
      * @return {@code true} if both values are equal.
      *
      * @see Float#equals(Object)
      */
-    public static boolean equals(final float o1, final float o2) {
-        return Float.floatToIntBits(o1) == Float.floatToIntBits(o2);
+    public static boolean equals(final float v1, final float v2) {
+        return Float.floatToIntBits(v1) == Float.floatToIntBits(v2);
     }
 
     /**
@@ -203,78 +204,86 @@ public final class Numerics extends Stat
      * Positive and negative zeros are considered different.
      * NaN values are considered equal to all other NaN values.
      *
-     * @param  o1 The first value to compare.
-     * @param  o2 The second value to compare.
+     * @param  v1 The first value to compare.
+     * @param  v2 The second value to compare.
      * @return {@code true} if both values are equal.
      *
      * @see Double#equals(Object)
      */
-    public static boolean equals(final double o1, final double o2) {
-        return Double.doubleToLongBits(o1) == Double.doubleToLongBits(o2);
+    public static boolean equals(final double v1, final double v2) {
+        return Double.doubleToLongBits(v1) == Double.doubleToLongBits(v2);
     }
 
     /**
      * Returns {@code true} if the given doubles are equal, ignoring the sign 
of zero values.
      * NaN values are considered equal to all other NaN values.
      *
-     * @param  o1 The first value to compare.
-     * @param  o2 The second value to compare.
+     * @param  v1 The first value to compare.
+     * @param  v2 The second value to compare.
      * @return {@code true} if both values are equal.
      */
-    public static boolean equalsIgnoreZeroSign(final double o1, final double 
o2) {
-        return (o1 == o2) || Double.doubleToLongBits(o1) == 
Double.doubleToLongBits(o2);
+    public static boolean equalsIgnoreZeroSign(final double v1, final double 
v2) {
+        return (v1 == v2) || Double.doubleToLongBits(v1) == 
Double.doubleToLongBits(v2);
     }
 
     /**
-     * Returns {@code true} if the given values are approximatively equal,
-     * up to the {@linkplain #COMPARISON_THRESHOLD comparison threshold}.
+     * Returns {@code true} if the given values are approximatively equal, up 
to the given comparison threshold.
      *
      * @param  v1 The first value to compare.
      * @param  v2 The second value to compare.
-     * @return {@code true} If both values are approximatively equal.
+     * @param  threshold The comparison threshold.
+     * @return {@code true} if both values are approximatively equal.
      */
-    public static boolean epsilonEqual(final double v1, final double v2) {
-        final double threshold = COMPARISON_THRESHOLD * max(abs(v1), abs(v2));
-        if (threshold == Double.POSITIVE_INFINITY || Double.isNaN(threshold)) {
-            return Double.doubleToLongBits(v1) == Double.doubleToLongBits(v2);
-        }
-        return abs(v1 - v2) <= threshold;
+    public static boolean epsilonEqual(final double v1, final double v2, final 
double threshold) {
+        return (abs(v1 - v2) <= threshold) || equals(v1, v2);
     }
 
     /**
      * Returns {@code true} if the given values are approximatively equal 
given the comparison mode.
+     * In mode {@code APPROXIMATIVE} or {@code DEBUG}, this method will 
compute a relative comparison
+     * threshold from the {@link #COMPARISON_THRESHOLD} constant.
      *
-     * @param  v1 The first value to compare.
-     * @param  v2 The second value to compare.
+     * <p>This method does not thrown {@link AssertionError} in {@link 
ComparisonMode#DEBUG}.
+     * It is caller responsibility to handle the {@code DEBUG} case.</p>
+     *
+     * @param  v1   The first value to compare.
+     * @param  v2   The second value to compare.
      * @param  mode The comparison mode to use for comparing the numbers.
-     * @return {@code true} If both values are approximatively equal.
+     * @return {@code true} if both values are considered equal for the given 
comparison mode.
      */
     public static boolean epsilonEqual(final double v1, final double v2, final 
ComparisonMode mode) {
-        switch (mode) {
-            default: return equals(v1, v2);
-            case APPROXIMATIVE: return epsilonEqual(v1, v2);
-            case DEBUG: {
-                final boolean equal = epsilonEqual(v1, v2);
-                assert equal : "v1=" + v1 + " v2=" + v2 + " Δv=" + abs(v1-v2);
-                return equal;
+        if (mode.isApproximative()) {
+            final double mg = max(abs(v1), abs(v2));
+            if (mg != Double.POSITIVE_INFINITY) {
+                return epsilonEqual(v1, v2, COMPARISON_THRESHOLD * mg);
             }
         }
+        return equals(v1, v2);
     }
 
     /**
-     * Returns {@code true} if the following objects are floating point 
numbers ({@link Float} or
-     * {@link Double} types) and approximatively equal. If the given object 
are not floating point
-     * numbers, then this method returns {@code false} unconditionally on the 
assumption that
-     * strict equality has already been checked before this method call.
+     * Creates a messages to put in {@link AssertionError} when two values 
differ in an unexpected way.
+     * This is a helper method for debugging purpose only, typically used with 
{@code assert} statements.
      *
-     * @param  v1 The first value to compare.
-     * @param  v2 The second value to compare.
-     * @return {@code true} If both values are real number and approximatively 
equal.
+     * @param name The name of the property which differ, or {@code null} if 
unknown.
+     * @param v1   The first value.
+     * @param v2   The second value.
+     * @return The message to put in {@code AssertionError}.
+     *
+     * @since 0.6
      */
-    public static boolean floatEpsilonEqual(final Object v1, final Object v2) {
-        return (v1 instanceof Float || v1 instanceof Double) &&
-               (v2 instanceof Float || v2 instanceof Double) &&
-               epsilonEqual(((Number) v1).doubleValue(), ((Number) 
v2).doubleValue());
+    @Debug
+    public static String messageForDifference(final String name, final double 
v1, final double v2) {
+        final StringBuilder builder = new StringBuilder();
+        if (name != null) {
+            builder.append(name).append(": ");
+        }
+        builder.append("values ").append(v1).append(" and 
").append(v2).append(" differ");
+        final float delta = (float) abs(v1 - v2);
+        if (delta < Float.POSITIVE_INFINITY) {
+            builder.append(" by ").append(delta);
+        }
+        return builder.toString();
     }
 
     /**

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ComparisonMode.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ComparisonMode.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ComparisonMode.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ComparisonMode.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -41,7 +41,7 @@ package org.apache.sis.util;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.6
  * @module
  *
  * @see LenientComparable#equals(Object, ComparisonMode)
@@ -152,6 +152,32 @@ public enum ComparisonMode {
     DEBUG;
 
     /**
+     * Returns {@code true} if this comparison ignores metadata.
+     * This method currently returns {@code true} for {@code IGNORE_METADATA}, 
{@code APPROXIMATIVE}
+     * or {@code DEBUG} only, but this list may be extended in future SIS 
versions.
+     *
+     * @return Whether this comparison ignore metadata.
+     *
+     * @since 0.6
+     */
+    public boolean isIgnoringMetadata() {
+        return ordinal() >= IGNORE_METADATA.ordinal();
+    }
+
+    /**
+     * Returns {@code true} if this comparison uses a tolerance threshold.
+     * This method currently returns {@code true} for {@code APPROXIMATIVE} or 
{@code DEBUG} only,
+     * but this list may be extended in future SIS versions.
+     *
+     * @return Whether this comparison uses a tolerance threshold.
+     *
+     * @since 0.6
+     */
+    public boolean isApproximative() {
+        return ordinal() >= APPROXIMATIVE.ordinal();
+    }
+
+    /**
      * If the two given objects are equals according one of the modes 
enumerated in this class,
      * then returns that mode. Otherwise returns {@code null}. This method is 
used mostly for
      * diagnostic purpose.

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Numbers.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -43,6 +43,10 @@ import static java.lang.Double.doubleToL
  *
  * @see org.apache.sis.math.MathFunctions
  */
+@SuppressWarnings({
+    "UnnecessaryBoxing",
+    "ResultOfObjectAllocationIgnored"
+})
 public final class Numbers extends Static {
     /**
      * Constant of value {@value} used in {@code switch} statements or as 
index in arrays.
@@ -88,6 +92,7 @@ public final class Numbers extends Stati
     /**
      * Creates an entry for a type which is not a primitive type.
      */
+    @SuppressWarnings("ThisEscapedInObjectConstruction")
     private Numbers(final Class<?> type, final boolean isFloat, final boolean 
isInteger, final byte ordinal) {
         primitive = wrapper = type;
         this.isFloat   = isFloat;
@@ -104,6 +109,7 @@ public final class Numbers extends Stati
     /**
      * Creates a mapping between a primitive type and its wrapper.
      */
+    @SuppressWarnings("ThisEscapedInObjectConstruction")
     private Numbers(final Class<?> primitive, final Class<?> wrapper,
                     final boolean  isFloat,   final boolean  isInteger,
                     final byte     size,      final byte     ordinal,

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -179,7 +179,7 @@ final class NilObjectHandler implements
         if (other == proxy) return true;
         if (other == null) return false;
         if (proxy.getClass() == other.getClass()) {
-            if (mode.ordinal() >= ComparisonMode.IGNORE_METADATA.ordinal()) {
+            if (mode.isIgnoringMetadata()) {
                 return true;
             }
             final NilObjectHandler h = (NilObjectHandler) 
Proxy.getInvocationHandler(other);

Modified: 
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java?rev=1693283&r1=1693282&r2=1693283&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
 [UTF-8] Wed Jul 29 14:55:12 2015
@@ -20,6 +20,7 @@ import java.util.Random;
 import org.apache.sis.math.MathFunctions;
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.TestCase;
+import org.apache.sis.util.ComparisonMode;
 import org.junit.Test;
 
 import static java.lang.Double.NaN;
@@ -34,9 +35,10 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.4
+ * @version 0.6
  * @module
  */
+@SuppressWarnings("UnnecessaryBoxing")
 public final strictfp class NumericsTest extends TestCase {
     /**
      * Tests the {@link Numerics#cached(Object)} method.
@@ -67,20 +69,20 @@ public final strictfp class NumericsTest
     }
 
     /**
-     * Tests the {@link Numerics#epsilonEqual(double, double)} method.
+     * Tests the {@link Numerics#epsilonEqual(double, double, ComparisonMode)} 
method.
      */
     @Test
     public void testEpsilonEqual() {
-        assertTrue (epsilonEqual(POSITIVE_INFINITY, POSITIVE_INFINITY));
-        assertTrue (epsilonEqual(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
-        assertFalse(epsilonEqual(POSITIVE_INFINITY, NEGATIVE_INFINITY));
-        assertFalse(epsilonEqual(POSITIVE_INFINITY, NaN));
-        assertTrue (epsilonEqual(NaN,               NaN));
-        assertFalse(epsilonEqual(   0,        COMPARISON_THRESHOLD / 2));
-        assertTrue (epsilonEqual(   1,    1 + COMPARISON_THRESHOLD / 2));
-        assertFalse(epsilonEqual(   1,    1 + COMPARISON_THRESHOLD * 2));
-        assertTrue (epsilonEqual(-100, -100 + COMPARISON_THRESHOLD * 50));
-        assertFalse(epsilonEqual( 100,  100 + COMPARISON_THRESHOLD * 150));
+        assertTrue (epsilonEqual(POSITIVE_INFINITY, POSITIVE_INFINITY,    
ComparisonMode.APPROXIMATIVE));
+        assertTrue (epsilonEqual(NEGATIVE_INFINITY, NEGATIVE_INFINITY,    
ComparisonMode.APPROXIMATIVE));
+        assertFalse(epsilonEqual(POSITIVE_INFINITY, NEGATIVE_INFINITY,    
ComparisonMode.APPROXIMATIVE));
+        assertFalse(epsilonEqual(POSITIVE_INFINITY, NaN,                  
ComparisonMode.APPROXIMATIVE));
+        assertTrue (epsilonEqual(NaN,               NaN,                  
ComparisonMode.APPROXIMATIVE));
+        assertFalse(epsilonEqual(   0,        COMPARISON_THRESHOLD /   2, 
ComparisonMode.APPROXIMATIVE));
+        assertTrue (epsilonEqual(   1,    1 + COMPARISON_THRESHOLD /   2, 
ComparisonMode.APPROXIMATIVE));
+        assertFalse(epsilonEqual(   1,    1 + COMPARISON_THRESHOLD *   2, 
ComparisonMode.APPROXIMATIVE));
+        assertTrue (epsilonEqual(-100, -100 + COMPARISON_THRESHOLD *  50, 
ComparisonMode.APPROXIMATIVE));
+        assertFalse(epsilonEqual( 100,  100 + COMPARISON_THRESHOLD * 150, 
ComparisonMode.APPROXIMATIVE));
     }
 
     /**


Reply via email to