sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1817597 [4/19] - in /sis/branches/ISO-19115-3: ./ application/ application/sis-console/ application/sis-console/src/main/artifact/ application/sis-console/src/main/artifact/lib/ application/sis-console/src/main/artifact/lib/darwin/ applica...
Date Sat, 09 Dec 2017 10:57:47 GMT
Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -127,7 +127,7 @@ public class DefaultResponsibleParty ext
 
     /**
      * Returns the name or the position of the first individual. If no individual is found in the list of parties,
-     * then this method will search in the list of organization members. The later structure is used by our NetCDF
+     * then this method will search in the list of organization members. The later structure is used by our netCDF
      * reader.
      *
      * @param  position {@code true} for returning the position name instead than individual name.

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -17,7 +17,6 @@
 package org.apache.sis.metadata.iso.distribution;
 
 import java.util.Collection;
-import java.util.Collections;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -30,7 +29,6 @@ import org.apache.sis.internal.metadata.
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.ISOMetadata;
-import org.apache.sis.util.iso.Types;
 
 // Branch-dependent imports
 import java.util.function.BiConsumer;
@@ -132,27 +130,6 @@ public class DefaultFormat extends ISOMe
     }
 
     /**
-     * Creates a format initialized to the given name and version.
-     * The given name should be a short name or abbreviation, for example "JPEG" or "GeoTIFF".
-     *
-     * @param  name     the abbreviated name of the data transfer format, or {@code null}.
-     * @param  version  the version of the format (date, number, <i>etc.</i>), or {@code null}.
-     *
-     * @deprecated This constructor had a straightforward meaning in ISO 19115:2003, but became confusing
-     *             with the ISO 19115:2014 update because of differences in the {@code Format} model.
-     *             Consider using {@link org.apache.sis.metadata.sql.MetadataSource#lookup(Class, String)} instead.
-     */
-    @Deprecated
-    public DefaultFormat(CharSequence name, final CharSequence version) {
-        final DefaultCitation citation = new DefaultCitation();
-        if (name != null) {
-            citation.setAlternateTitles(Collections.singleton(Types.toInternationalString(name)));
-        }
-        citation.setEdition(Types.toInternationalString(version));
-        formatSpecificationCitation = citation;
-    }
-
-    /**
      * Constructs a new instance initialized with the values from the specified metadata object.
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultBoundingPolygon.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultBoundingPolygon.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultBoundingPolygon.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultBoundingPolygon.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -47,7 +47,7 @@ import org.opengis.metadata.extent.Bound
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
  * @author  Guilhem Legal (Geomatys)
- * @version 0.3
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -77,6 +77,7 @@ public class DefaultBoundingPolygon exte
      * @param polygon  the sets of points defining the bounding polygon.
      */
     public DefaultBoundingPolygon(final Geometry polygon) {
+        super(true);
         polygons = singleton(polygon, Geometry.class);
     }
 

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -16,7 +16,10 @@
  */
 package org.apache.sis.metadata.iso.extent;
 
+import java.util.Set;
+import java.util.LinkedHashSet;
 import java.util.Collection;
+import java.util.function.BinaryOperator;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -29,9 +32,14 @@ import org.opengis.metadata.extent.Geogr
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.iso.Types;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.collection.Containers;
+import org.apache.sis.metadata.AbstractMetadata;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.internal.metadata.ReferencingServices;
+import org.apache.sis.xml.NilObject;
+import org.apache.sis.xml.NilReason;
 
 
 /**
@@ -74,7 +82,7 @@ import org.apache.sis.internal.metadata.
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
- * @version 0.3
+ * @version 0.8
  *
  * @see Extents#getGeographicBoundingBox(Extent)
  * @see org.apache.sis.referencing.AbstractReferenceSystem#getDomainOfValidity()
@@ -289,6 +297,85 @@ public class DefaultExtent extends ISOMe
      */
     public void addElements(final Envelope envelope) throws TransformException {
         checkWritePermission();
+        ArgumentChecks.ensureNonNull("envelope", envelope);
         ReferencingServices.getInstance().addElements(envelope, this);
     }
+
+    /**
+     * Sets this extent to the intersection of this extent with the specified one.
+     * This method computes the intersections of all geographic, vertical and temporal elements in this extent
+     * with all geographic, vertical and temporal elements in the other extent, ignoring duplicated results.
+     *
+     * @param  other  the extent to intersect with this extent.
+     * @throws IllegalArgumentException if two elements to intersect are not compatible (e.g. mismatched
+     *         {@linkplain DefaultGeographicBoundingBox#getInclusion() bounding box inclusion status} or
+     *         mismatched {@linkplain DefaultVerticalExtent#getVerticalCRS() vertical datum}).
+     * @throws UnsupportedOperationException if a {@code TemporalFactory} is required but no implementation
+     *         has been found on the classpath.
+     *
+     * @see Extents#intersection(Extent, Extent)
+     * @see org.apache.sis.geometry.GeneralEnvelope#intersect(Envelope)
+     *
+     * @since 0.8
+     */
+    public void intersect(final Extent other) {
+        checkWritePermission();
+        ArgumentChecks.ensureNonNull("other", other);
+        final InternationalString od = other.getDescription();
+        if (od != null && !(description instanceof NilObject)) {
+            if (description == null || (od instanceof NilObject)) {
+                description = od;
+            } else if (!description.equals(od)) {
+                description = NilReason.MISSING.createNilObject(InternationalString.class);
+            }
+        }
+        geographicElements = intersect(GeographicExtent.class, geographicElements, other.getGeographicElements(), Extents::intersection);
+        verticalElements   = intersect(VerticalExtent.class,   verticalElements,   other.getVerticalElements(),   Extents::intersection);
+        temporalElements   = intersect(TemporalExtent.class,   temporalElements,   other.getTemporalElements(),   Extents::intersection);
+    }
+
+    /**
+     * Computes the intersections of all elements in the given {@code sources} collection will all elements
+     * in the given {@code targets} collection. If one of those collections is null or empty, this method
+     * returns all elements of the other collection (may be {@code targets} itself).
+     *
+     * @param  <T>        compile-time value of {@code type} argument.
+     * @param  type       the type of elements in the collections.
+     * @param  targets    the elements in this {@code DefaultExtent}. Also the collection where results will be stored.
+     * @param  sources    the elements from the other {@code Extent} to intersect with this extent.
+     * @param  intersect  the function computing intersections.
+     * @return the intersection results. May be the same instance than {@code targets} with elements replaced.
+     */
+    private <T> Collection<T> intersect(final Class<T> type, Collection<T> targets, Collection<? extends T> sources, final BinaryOperator<T> intersect) {
+        if (!Containers.isNullOrEmpty(sources)) {
+            if (!Containers.isNullOrEmpty(targets)) {
+                final Set<T> results = new LinkedHashSet<>(Containers.hashMapCapacity(targets.size()));
+                T empty = null;
+                for (final T target : targets) {
+                    for (final T source : sources) {
+                        final T e = intersect.apply(target, source);
+                        results.add(e);
+                        /*
+                         * If the two elements do not intersect, remember the value created by the intersection method
+                         * for meaning "no intersection".  We remember only the first value since we always create the
+                         * same value for meaning "no intersection".
+                         */
+                        if (empty == null && e != source && e != target && (e instanceof AbstractMetadata) && ((AbstractMetadata) e).isEmpty()) {
+                            empty = e;
+                        }
+                    }
+                }
+                /*
+                 * Remove the "no intersection" value, unless this is the only result.
+                 */
+                results.remove(null);
+                if (results.size() > 1) {
+                    results.remove(empty);
+                }
+                sources = results;
+            }
+            targets = writeCollection(sources, targets, type);
+        }
+        return targets;
+    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBox.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBox.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBox.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBox.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -536,7 +536,7 @@ public class DefaultGeographicBoundingBo
         ArgumentChecks.ensureNonNull("box", box);
         setBounds(box.getWestBoundLongitude(), box.getEastBoundLongitude(),
                   box.getSouthBoundLatitude(), box.getNorthBoundLatitude());
-        setInclusion(box.getInclusion()); // Set only on success.
+        setInclusion(box.getInclusion());                               // Set only on success.
     }
 
     /*
@@ -650,6 +650,7 @@ public class DefaultGeographicBoundingBo
      */
     public void add(final GeographicBoundingBox box) {
         checkWritePermission();
+        ArgumentChecks.ensureNonNull("box", box);
         double λmin = box.getWestBoundLongitude();
         double λmax = box.getEastBoundLongitude();
         double φmin = box.getSouthBoundLatitude();
@@ -707,6 +708,7 @@ public class DefaultGeographicBoundingBo
      */
     public void intersect(final GeographicBoundingBox box) throws IllegalArgumentException {
         checkWritePermission();
+        ArgumentChecks.ensureNonNull("box", box);
         if (getInclusion(getInclusion()) != getInclusion(box.getInclusion())) {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatiblePropertyValue_1, "inclusion"));
         }

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -31,6 +31,8 @@ import org.opengis.referencing.operation
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.internal.util.TemporalUtilities;
 import org.apache.sis.internal.metadata.ReferencingServices;
+import org.apache.sis.xml.NilObject;
+import org.apache.sis.xml.NilReason;
 
 
 /**
@@ -60,7 +62,7 @@ import org.apache.sis.internal.metadata.
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
- * @version 0.3
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -242,4 +244,49 @@ public class DefaultTemporalExtent exten
         checkWritePermission();
         ReferencingServices.getInstance().setBounds(envelope, this);
     }
+
+    /**
+     * Sets this temporal extent to the intersection of this extent with the specified one.
+     * If there is no intersection between the two extents, then this method sets the temporal primitive to nil.
+     * If either this extent or the specified extent has nil primitive, then the intersection result will also be nil.
+     *
+     * @param  other  the temporal extent to intersect with this extent.
+     * @throws UnsupportedOperationException if no implementation of {@code TemporalFactory} has been found
+     *         on the classpath.
+     *
+     * @see Extents#intersection(TemporalExtent, TemporalExtent)
+     * @see org.apache.sis.geometry.GeneralEnvelope#intersect(Envelope)
+     *
+     * @since 0.8
+     */
+    public void intersect(final TemporalExtent other) {
+        checkWritePermission();
+        final TemporalPrimitive ot = other.getExtent();
+        if (ot != null && !(extent instanceof NilObject)) {
+            if (extent == null || (ot instanceof NilObject)) {
+                extent = ot;
+            } else {
+                Date t0 = getTime(extent, true);
+                Date t1 = getTime(extent, false);
+                Date h0 = getTime(ot,     true);
+                Date h1 = getTime(ot,     false);
+                boolean changed = false;
+                if (h0 != null && (t0 == null || h0.after(t0))) {
+                    t0 = h0;
+                    changed = true;
+                }
+                if (h1 != null && (t1 == null || h1.before(t1))) {
+                    t1 = h1;
+                    changed = true;
+                }
+                if (changed) {
+                    if (t0 != null && t1 != null && t0.after(t1)) {
+                        extent = NilReason.MISSING.createNilObject(TemporalPrimitive.class);
+                    } else {
+                        setBounds(t0, t1);
+                    }
+                }
+            }
+        }
+    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultVerticalExtent.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultVerticalExtent.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultVerticalExtent.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultVerticalExtent.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -21,12 +21,20 @@ import javax.xml.bind.annotation.XmlElem
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.geometry.Envelope;
+import org.opengis.util.FactoryException;
 import org.opengis.referencing.crs.VerticalCRS;
+import org.opengis.referencing.operation.MathTransform1D;
 import org.opengis.referencing.operation.TransformException;
+import org.opengis.geometry.MismatchedReferenceSystemException;
 import org.opengis.metadata.extent.VerticalExtent;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.internal.jaxb.gco.GO_Real;
 import org.apache.sis.internal.metadata.ReferencingServices;
+import org.apache.sis.math.MathFunctions;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.Utilities;
+import org.apache.sis.xml.NilReason;
 
 
 /**
@@ -55,7 +63,7 @@ import org.apache.sis.internal.metadata.
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
- * @version 0.3
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -241,4 +249,118 @@ public class DefaultVerticalExtent exten
         checkWritePermission();
         ReferencingServices.getInstance().setBounds(envelope, this);
     }
+
+    /**
+     * Sets this vertical extent to the intersection of this extent with the specified one.
+     * The {@linkplain org.apache.sis.referencing.crs.DefaultVerticalCRS#getDatum() vertical datum}
+     * must be the same (ignoring metadata) for both extents; this method does not perform datum shift.
+     * However this method can perform unit conversions.
+     *
+     * <p>If there is no intersection between the two extents, then this method sets both minimum and
+     * maximum values to {@linkplain Double#NaN}. If either this extent or the specified extent has NaN
+     * bounds, then the corresponding bounds of the intersection result will also be NaN.</p>
+     *
+     * @param  other  the vertical extent to intersect with this extent.
+     * @throws MismatchedReferenceSystemException if the two extents do not use the same datum, ignoring metadata.
+     *
+     * @see Extents#intersection(VerticalExtent, VerticalExtent)
+     * @see org.apache.sis.geometry.GeneralEnvelope#intersect(Envelope)
+     *
+     * @since 0.8
+     */
+    public void intersect(final VerticalExtent other) throws MismatchedReferenceSystemException {
+        checkWritePermission();
+        ArgumentChecks.ensureNonNull("other", other);
+        Double min = other.getMinimumValue();
+        Double max = other.getMaximumValue();
+        try {
+            final MathTransform1D cv = getConversionFrom(other.getVerticalCRS());
+            if (isReversing(cv, min, max)) {
+                Double tmp = min;
+                min = max;
+                max = tmp;
+            }
+            /*
+             * If minimumValue is NaN, keep it unchanged (because x > minimumValue is false)
+             * in order to preserve the NilReason. Conversely if min is NaN, then we want to
+             * take it without conversion for preserving its NilReason.
+             */
+            if (min != null) {
+                if (minimumValue == null || min.isNaN() || (min = convert(cv, min)) > minimumValue) {
+                    minimumValue = min;
+                }
+            }
+            if (max != null) {
+                if (maximumValue == null || max.isNaN() || (max = convert(cv, max)) < maximumValue) {
+                    maximumValue = max;
+                }
+            }
+        } catch (UnsupportedOperationException | FactoryException | ClassCastException | TransformException e) {
+            throw new MismatchedReferenceSystemException(Errors.format(Errors.Keys.IncompatiblePropertyValue_1, "verticalCRS"), e);
+        }
+        if (minimumValue != null && maximumValue != null && minimumValue > maximumValue) {
+            minimumValue = maximumValue = NilReason.MISSING.createNilObject(Double.class);
+        }
+    }
+
+    /**
+     * Returns the conversion from the given CRS to the CRS of this extent, or {@code null} if none or unknown.
+     * The returned {@code MathTransform1D} may apply unit conversions or axis direction reversal, but usually
+     * not datum shift.
+     *
+     * @param  source  the CRS from which to perform the conversions, or {@code null} if unknown.
+     * @return the conversion from {@code source}, or {@code null} if none or unknown.
+     * @throws UnsupportedOperationException if the {@code sis-referencing} module is not on the classpath.
+     * @throws FactoryException if the coordinate operation factory is not available.
+     * @throws ClassCastException if the conversion is not an instance of {@link MathTransform1D}.
+     */
+    private MathTransform1D getConversionFrom(final VerticalCRS source) throws FactoryException {
+        if (!Utilities.equalsIgnoreMetadata(verticalCRS, source) && verticalCRS != null && source != null) {
+            final MathTransform1D cv = (MathTransform1D) ReferencingServices.getInstance()
+                    .getCoordinateOperationFactory(null, null, null, null)
+                    .createOperation(source, verticalCRS).getMathTransform();
+            if (!cv.isIdentity()) {
+                return cv;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns {@code true} if the given conversion seems to change the axis direction.
+     * This happen for example with conversions from "Elevation" axis to "Depth" axis.
+     * In case of doubt, this method returns {@code false}.
+     *
+     * <div class="note"><b>Note about alternatives:</b>
+     * we could compare axis directions instead, but it would not work with user-defined directions
+     * or user-defined unit conversions with negative scale factor (should never happen, but we are
+     * paranoiac). We could compare the minimum and maximum values after conversions, but it would
+     * not work if one or both values are {@code null} or {@code NaN}. Since we want to preserve
+     * {@link NilReason}, we still need to know if axes are reversed in order to put the nil reason
+     * in the right location.</div>
+     *
+     * @param  cv      the conversion computed by {@link #getConversionFrom(VerticalCRS)} (may be {@code null}).
+     * @param  sample  the minimum or the maximum value.
+     * @param  other   the minimum or maximum value at the opposite bound.
+     * @return {@code true} if the axis direction is reversed at the given value.
+     */
+    private static boolean isReversing(final MathTransform1D cv, Double sample, final Double other) throws TransformException {
+        if (cv == null) {
+            return false;
+        }
+        if (sample == null || sample.isNaN()) {
+            sample = other;
+        } else if (other != null && !other.isNaN()) {
+            sample = (sample + other) / 2;
+        }
+        return MathFunctions.isNegative(cv.derivative(sample != null ? sample : Double.NaN));
+    }
+
+    /**
+     * Converts the given value with the given transform if non-null. This converter can generally
+     * not perform datum shift; the operation is merely unit conversion and change of axis direction.
+     */
+    private static Double convert(MathTransform1D tr, Double value) throws TransformException {
+        return (tr != null) ? tr.transform(value) : value;
+    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -29,6 +29,8 @@ import org.opengis.metadata.extent.Tempo
 import org.opengis.metadata.extent.BoundingPolygon;
 import org.opengis.metadata.extent.GeographicExtent;
 import org.opengis.metadata.extent.GeographicBoundingBox;
+import org.opengis.metadata.extent.GeographicDescription;
+import org.opengis.geometry.MismatchedReferenceSystemException;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.crs.VerticalCRS;
@@ -45,6 +47,7 @@ import org.apache.sis.measure.Range;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.Static;
 
 import static java.lang.Math.*;
@@ -59,11 +62,11 @@ import org.opengis.geometry.Geometry;
  * This class provides methods for:
  *
  * <ul>
- *   <li>{@link #getGeographicBoundingBox(Extent)}, {@link #getVerticalRange(Extent)}
- *       and {@link #getDate(Extent, double)}
- *       for fetching geographic or temporal components in a convenient form.</li>
- *   <li>Methods for computing {@linkplain #intersection intersection} of bounding boxes
- *       and {@linkplain #area area} estimations.</li>
+ *   <li>{@linkplain #getGeographicBoundingBox Fetching geographic},
+ *       {@linkplain #getVerticalRange vertical} or
+ *       {@linkplain #getDate temporal components} in a convenient form.</li>
+ *   <li>Computing {@linkplain #intersection intersection} of bounding boxes</li>
+ *   <li>Computing {@linkplain #area area} estimations.</li>
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
@@ -436,33 +439,6 @@ public final class Extents extends Stati
     }
 
     /**
-     * Returns the intersection of the given geographic bounding boxes. If any of the arguments is {@code null},
-     * then this method returns the other argument (which may be null). Otherwise this method returns a box which
-     * is the intersection of the two given boxes.
-     *
-     * <p>This method never modify the given boxes, but may return directly one of the given arguments if it
-     * already represents the intersection result.</p>
-     *
-     * @param  b1  the first bounding box, or {@code null}.
-     * @param  b2  the second bounding box, or {@code null}.
-     * @return the intersection (may be any of the {@code b1} or {@code b2} argument if unchanged),
-     *         or {@code null} if the two given boxes are null.
-     * @throws IllegalArgumentException if the {@linkplain DefaultGeographicBoundingBox#getInclusion() inclusion status}
-     *         is not the same for both boxes.
-     *
-     * @see DefaultGeographicBoundingBox#intersect(GeographicBoundingBox)
-     *
-     * @since 0.4
-     */
-    public static GeographicBoundingBox intersection(final GeographicBoundingBox b1, final GeographicBoundingBox b2) {
-        if (b1 == null) return b2;
-        if (b2 == null || b2 == b1) return b1;
-        final DefaultGeographicBoundingBox box = new DefaultGeographicBoundingBox(b1);
-        box.intersect(b2);
-        return box;
-    }
-
-    /**
      * Returns an <em>estimation</em> of the area (in square metres) of the given bounding box.
      * Since {@code GeographicBoundingBox} provides only approximative information (for example
      * it does not specify the datum), the value returned by this method is also approximative.
@@ -496,4 +472,145 @@ public final class Extents extends Stati
                max(0, sin(toRadians(box.getNorthBoundLatitude())) -
                       sin(toRadians(box.getSouthBoundLatitude())));
     }
+
+    /**
+     * Returns the intersection of the given geographic bounding boxes. If any of the arguments is {@code null},
+     * then this method returns the other argument (which may be null). Otherwise this method returns a box which
+     * is the intersection of the two given boxes.
+     *
+     * <p>This method never modify the given boxes, but may return directly one of the given arguments if it
+     * already represents the intersection result.</p>
+     *
+     * @param  b1  the first bounding box, or {@code null}.
+     * @param  b2  the second bounding box, or {@code null}.
+     * @return the intersection (may be any of the {@code b1} or {@code b2} argument if unchanged),
+     *         or {@code null} if the two given boxes are null.
+     * @throws IllegalArgumentException if the {@linkplain DefaultGeographicBoundingBox#getInclusion() inclusion status}
+     *         is not the same for both boxes.
+     *
+     * @see DefaultGeographicBoundingBox#intersect(GeographicBoundingBox)
+     *
+     * @since 0.4
+     */
+    public static GeographicBoundingBox intersection(final GeographicBoundingBox b1, final GeographicBoundingBox b2) {
+        if (b1 == null) return b2;
+        if (b2 == null || b2 == b1) return b1;
+        final DefaultGeographicBoundingBox box = new DefaultGeographicBoundingBox(b1);
+        box.intersect(b2);
+        if (box.equals(b1, ComparisonMode.BY_CONTRACT)) return b1;
+        if (box.equals(b2, ComparisonMode.BY_CONTRACT)) return b2;
+        return box;
+    }
+
+    /**
+     * May compute an intersection between the given geographic extents.
+     * Current implementation supports only {@link GeographicBoundingBox};
+     * all other kinds are handled as if they were {@code null}.
+     *
+     * <p>We may improve this method in future Apache SIS version, but it is not yet clear how.
+     * For example how to handle {@link GeographicDescription} or {@link BoundingPolygon}?
+     * This method should not be public before we find a better contract.</p>
+     */
+    static GeographicExtent intersection(final GeographicExtent e1, final GeographicExtent e2) {
+        return intersection(e1 instanceof GeographicBoundingBox ? (GeographicBoundingBox) e1 : null,
+                            e2 instanceof GeographicBoundingBox ? (GeographicBoundingBox) e2 : null);
+    }
+
+    /**
+     * Returns the intersection of the given vertical extents. If any of the arguments is {@code null},
+     * then this method returns the other argument (which may be null). Otherwise this method returns a
+     * vertical extent which is the intersection of the two given extents.
+     *
+     * <p>This method never modify the given extents, but may return directly one of the given arguments
+     * if it already represents the intersection result.</p>
+     *
+     * <div class="section">Advantage and inconvenient of this method</div>
+     * This method can not intersect extents defined with different datums because height transformations
+     * generally require the geodetic positions (latitudes and longitudes) of the heights to transform.
+     * For more general transformations, it is better to convert all extent components into a single envelope,
+     * then {@linkplain org.apache.sis.geometry.Envelopes#transform(CoordinateOperation, Envelope) transform
+     * the envelope at once}. On the other hand, this {@code intersect(…)} method preserves better
+     * the {@link org.apache.sis.xml.NilReason} (if any).
+     *
+     * @param  e1  the first extent, or {@code null}.
+     * @param  e2  the second extent, or {@code null}.
+     * @return the intersection (may be any of the {@code e1} or {@code e2} argument if unchanged),
+     *         or {@code null} if the two given extents are null.
+     * @throws MismatchedReferenceSystemException if the two extents do not use the same datum, ignoring metadata.
+     *
+     * @see DefaultVerticalExtent#intersect(VerticalExtent)
+     *
+     * @since 0.8
+     */
+    public static VerticalExtent intersection(final VerticalExtent e1, final VerticalExtent e2) {
+        if (e1 == null) return e2;
+        if (e2 == null || e2 == e1) return e1;
+        final DefaultVerticalExtent extent = new DefaultVerticalExtent(e1);
+        extent.intersect(e2);
+        if (extent.equals(e1, ComparisonMode.BY_CONTRACT)) return e1;
+        if (extent.equals(e2, ComparisonMode.BY_CONTRACT)) return e2;
+        return extent;
+    }
+
+    /**
+     * Returns the intersection of the given temporal extents. If any of the arguments is {@code null},
+     * then this method returns the other argument (which may be null). Otherwise this method returns a
+     * temporal extent which is the intersection of the two given extents.
+     *
+     * <p>This method never modify the given extents, but may return directly one of the given arguments
+     * if it already represents the intersection result.</p>
+     *
+     * @param  e1  the first extent, or {@code null}.
+     * @param  e2  the second extent, or {@code null}.
+     * @return the intersection (may be any of the {@code e1} or {@code e2} argument if unchanged),
+     *         or {@code null} if the two given extents are null.
+     * @throws UnsupportedOperationException if no implementation of {@code TemporalFactory} has been found
+     *         on the classpath.
+     *
+     * @see DefaultTemporalExtent#intersect(TemporalExtent)
+     *
+     * @since 0.8
+     */
+    public static TemporalExtent intersection(final TemporalExtent e1, final TemporalExtent e2) {
+        if (e1 == null) return e2;
+        if (e2 == null || e2 == e1) return e1;
+        final DefaultTemporalExtent extent = new DefaultTemporalExtent(e1);
+        extent.intersect(e2);
+        if (extent.equals(e1, ComparisonMode.BY_CONTRACT)) return e1;
+        if (extent.equals(e2, ComparisonMode.BY_CONTRACT)) return e2;
+        return extent;
+    }
+
+    /**
+     * Returns the intersection of the given extents. If any of the arguments is {@code null},
+     * then this method returns the other argument (which may be null). Otherwise this method
+     * returns an extent which is the intersection of all geographic, vertical and temporal
+     * elements in the two given extents.
+     *
+     * <p>This method never modify the given extents, but may return directly one of the given
+     * arguments if it already represents the intersection result.</p>
+     *
+     * @param  e1  the first extent, or {@code null}.
+     * @param  e2  the second extent, or {@code null}.
+     * @return the intersection (may be any of the {@code e1} or {@code e2} argument if unchanged),
+     *         or {@code null} if the two given extents are null.
+     * @throws IllegalArgumentException if two elements to intersect are not compatible (e.g. mismatched
+     *         {@linkplain DefaultGeographicBoundingBox#getInclusion() bounding box inclusion status} or
+     *         mismatched {@linkplain DefaultVerticalExtent#getVerticalCRS() vertical datum}).
+     * @throws UnsupportedOperationException if a {@code TemporalFactory} is required but no implementation
+     *         has been found on the classpath.
+     *
+     * @see DefaultExtent#intersect(Extent)
+     *
+     * @since 0.8
+     */
+    public static Extent intersection(final Extent e1, final Extent e2) {
+        if (e1 == null) return e2;
+        if (e2 == null || e2 == e1) return e1;
+        final DefaultExtent extent = new DefaultExtent(e1);
+        extent.intersect(e2);
+        if (extent.equals(e1, ComparisonMode.BY_CONTRACT)) return e1;
+        if (extent.equals(e2, ComparisonMode.BY_CONTRACT)) return e2;
+        return extent;
+    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -238,7 +238,7 @@ public class DefaultMaintenanceInformati
     @Dependencies("getMaintenanceDates")
     public Date getDateOfNextUpdate() {
         final Collection<CitationDate> dates = getMaintenanceDates();
-        if (dates != null) { // May be null on XML marshalling.
+        if (dates != null) {                                                    // May be null on XML marshalling.
             for (final CitationDate date : dates) {
                 if (DateType.NEXT_UPDATE.equals(date.getDateType())) {
                     return date.getDate();

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -30,7 +30,7 @@ import org.apache.sis.xml.Namespaces;
 /**
  * Information on ground control point.
  * Ground control points (GCP) are large marked targets on the ground,
- * not to be confused with <cite>localization grid</cite> points embedded in some file formats like GeoTIFF or NetCDF.
+ * not to be confused with <cite>localization grid</cite> points embedded in some file formats like GeoTIFF or netCDF.
  * The following property is mandatory in a well-formed metadata according ISO 19115:
  *
  * <div class="preformat">{@code MI_GCP}

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataSource.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataSource.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataSource.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataSource.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -407,6 +407,9 @@ public class MetadataSource implements A
      *   <li>The schema name must be {@code "metadata"}, as this is the name used unquoted in SQL scripts.</li>
      * </ul>
      *
+     * Maintenance note: this method is invoked by reflection in {@code non-free:sis-embedded-data} module.
+     * If we make this method public in a future Apache SIS version, then we can remove the reflection code.
+     *
      * @throws MetadataStoreException if an error occurred while inserting the metadata.
      */
     final synchronized void install() throws MetadataStoreException {

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -100,8 +100,7 @@ public final strictfp class MergerTest e
         final DefaultMetadata source = createSample1();
         final DefaultMetadata target = createSample2();
         final Merger merger = new Merger(null);
-        merger.avoidConflicts = true;
-        merger.merge(source, target);
+        merger.copy(source, target);
 
         assertSetEquals(Arrays.asList(Locale.JAPANESE, Locale.FRENCH),  target.getLanguages());
         assertSetEquals(Collections.singleton(StandardCharsets.UTF_16), target.getCharacterSets());

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/NameMeaningTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/NameMeaningTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/NameMeaningTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/NameMeaningTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -16,10 +16,14 @@
  */
 package org.apache.sis.internal.metadata;
 
+import javax.measure.Unit;
 import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.*;
 import org.opengis.referencing.datum.*;
 import org.opengis.referencing.ReferenceSystem;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.parameter.ParameterDescriptor;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -41,19 +45,23 @@ public final strictfp class NameMeaningT
      */
     @Test
     public void testToObjectType() {
-        assertEquals("crs",             NameMeaning.toObjectType(GeographicCRS       .class));
-        assertEquals("crs",             NameMeaning.toObjectType(ProjectedCRS        .class));
-        assertEquals("crs",             NameMeaning.toObjectType(VerticalCRS         .class));
-        assertEquals("crs",             NameMeaning.toObjectType(TemporalCRS         .class));
-        assertEquals("datum",           NameMeaning.toObjectType(GeodeticDatum       .class));
-        assertEquals("datum",           NameMeaning.toObjectType(VerticalDatum       .class));
-        assertEquals("datum",           NameMeaning.toObjectType(TemporalDatum       .class));
-        assertEquals("ellipsoid",       NameMeaning.toObjectType(Ellipsoid           .class));
-        assertEquals("meridian",        NameMeaning.toObjectType(PrimeMeridian       .class));
-        assertEquals("cs",              NameMeaning.toObjectType(EllipsoidalCS       .class));
-        assertEquals("cs",              NameMeaning.toObjectType(CartesianCS         .class));
-        assertEquals("axis",            NameMeaning.toObjectType(CoordinateSystemAxis.class));
-        assertEquals("referenceSystem", NameMeaning.toObjectType(ReferenceSystem     .class));
+        assertEquals("crs",                 NameMeaning.toObjectType(GeographicCRS       .class));
+        assertEquals("crs",                 NameMeaning.toObjectType(ProjectedCRS        .class));
+        assertEquals("crs",                 NameMeaning.toObjectType(VerticalCRS         .class));
+        assertEquals("crs",                 NameMeaning.toObjectType(TemporalCRS         .class));
+        assertEquals("datum",               NameMeaning.toObjectType(GeodeticDatum       .class));
+        assertEquals("datum",               NameMeaning.toObjectType(VerticalDatum       .class));
+        assertEquals("datum",               NameMeaning.toObjectType(TemporalDatum       .class));
+        assertEquals("ellipsoid",           NameMeaning.toObjectType(Ellipsoid           .class));
+        assertEquals("meridian",            NameMeaning.toObjectType(PrimeMeridian       .class));
+        assertEquals("cs",                  NameMeaning.toObjectType(EllipsoidalCS       .class));
+        assertEquals("cs",                  NameMeaning.toObjectType(CartesianCS         .class));
+        assertEquals("axis",                NameMeaning.toObjectType(CoordinateSystemAxis.class));
+        assertEquals("referenceSystem",     NameMeaning.toObjectType(ReferenceSystem     .class));
+        assertEquals("coordinateOperation", NameMeaning.toObjectType(CoordinateOperation .class));
+        assertEquals("method",              NameMeaning.toObjectType(OperationMethod     .class));
+        assertEquals("parameter",           NameMeaning.toObjectType(ParameterDescriptor .class));
+        assertEquals("uom",                 NameMeaning.toObjectType(Unit                .class));
     }
 
     /**
@@ -64,7 +72,9 @@ public final strictfp class NameMeaningT
     @Test
     @DependsOnMethod("testToObjectType")
     public void testToURN() {
+        assertEquals("urn:ogc:def:crs:EPSG::4326",    NameMeaning.toURN(GeodeticCRS.class,   "EPSG", null, "4326"));
         assertEquals("urn:ogc:def:crs:OGC:1.3:CRS84", NameMeaning.toURN(GeographicCRS.class, "CRS",  null,   "84"));
         assertEquals("urn:ogc:def:datum:EPSG::6326",  NameMeaning.toURN(GeodeticDatum.class, "EPSG", null, "6326"));
+        assertNull  ("Authority is not optional.",    NameMeaning.toURN(GeographicCRS.class, null,   null, "4326"));
     }
 }

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/sql/TestDatabase.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/sql/TestDatabase.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/sql/TestDatabase.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/sql/TestDatabase.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -16,12 +16,9 @@
  */
 package org.apache.sis.internal.metadata.sql;
 
-import java.nio.file.Files;
-import java.nio.file.Path;
 import java.sql.SQLException;
 import javax.sql.DataSource;
 import org.apache.sis.util.Debug;
-import org.apache.sis.internal.system.DataDirectory;
 
 import static org.junit.Assume.*;
 
@@ -50,7 +47,7 @@ import static org.junit.Assume.*;
  *
  * <p><b>References:</b>
  * <ul>
- *   <li><a href="https://db.apache.org/derby/docs/10.2/adminguide/radminembeddedserverex.html">Embedded server example</a></li>
+ *   <li><a href="https://db.apache.org/derby/docs/10.13/adminguide/radminembeddedserverex.html">Embedded server example</a></li>
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
@@ -77,21 +74,6 @@ public final strictfp class TestDatabase
     }
 
     /**
-     * Returns the path to the directory of the given name in {@code $SIS_DATA/Databases}.
-     * If the directory is not found, then the test will be interrupted by an {@code org.junit.Assume} statement.
-     *
-     * @param  name  the name of the sub-directory.
-     * @return the path to the given sub-directory.
-     */
-    public static Path directory(final String name) {
-        Path dir = DataDirectory.DATABASES.getDirectory();
-        assumeNotNull("$SIS_DATA/Databases directory not found.", dir);
-        dir = dir.resolve(name);
-        assumeTrue("Specified directory not found.", Files.isDirectory(dir));
-        return dir;
-    }
-
-    /**
      * Creates a Derby database in memory. If no Derby or JavaDB driver is not found,
      * then the test will be interrupted by an {@code org.junit.Assume} statement.
      *

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataStandardTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataStandardTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataStandardTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataStandardTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -249,7 +249,7 @@ public final strictfp class MetadataStan
     }
 
     /**
-     * Tests the {@link MetadataStandard#asValueMap(Object, KeyNamePolicy, ValueExistencePolicy)} implementation.
+     * Tests the {@link MetadataStandard#asValueMap(Object, Class, KeyNamePolicy, ValueExistencePolicy)} implementation.
      * This test duplicates {@link ValueMapTest}, but is done here again as an integration test and because many
      * {@code MetadataStandard} methods depend on it ({@code equals}, {@code hashCode}, {@code prune}, <i>etc.</i>).
      */

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -42,7 +42,7 @@ import static org.apache.sis.test.TestUt
 
 /**
  * Tests the {@link ValueMap} class on instances created by
- * {@link MetadataStandard#asValueMap(Object, KeyNamePolicy, ValueExistencePolicy)}.
+ * {@link MetadataStandard#asValueMap(Object, Class, KeyNamePolicy, ValueExistencePolicy)}.
  * Unless otherwise specified, all tests use the {@link MetadataStandard#ISO_19115} constant.
  *
  * @author  Martin Desruisseaux (Geomatys)

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -22,7 +22,9 @@ import java.lang.reflect.Field;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.apache.sis.internal.simple.CitationConstant;
+import org.apache.sis.internal.simple.SimpleCitation;
 import org.apache.sis.internal.util.Constants;
+import org.apache.sis.xml.IdentifierSpace;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -131,27 +133,63 @@ public final strictfp class CitationsTes
     }
 
     /**
-     * Tests {@link org.apache.sis.internal.util.Citations#getCodeSpace(Citation)} on the constants
-     * declared in the {@link Citations} class.
+     * Tests {@link Citations#getCodeSpace(Citation)} with some ignorable characters.
+     * Ignorable character used in this test are:
+     *
+     * <ul>
+     *   <li>200B: zero width space</li>
+     *   <li>2060: word joiner</li>
+     * </ul>
      */
     @Test
-    @DependsOnMethod("testGetUnicodeIdentifier")
+    @DependsOnMethod("testGetIdentifier")
     public void testGetCodeSpace() {
-        assertEquals("SIS",         org.apache.sis.internal.util.Citations.getCodeSpace(SIS));
-        assertEquals("OGC",         org.apache.sis.internal.util.Citations.getCodeSpace(WMS));
-        assertEquals("OGC",         org.apache.sis.internal.util.Citations.getCodeSpace(OGC));
-        assertEquals("IOGP",        org.apache.sis.internal.util.Citations.getCodeSpace(IOGP));
-        assertEquals("EPSG",        org.apache.sis.internal.util.Citations.getCodeSpace(EPSG));
-        assertEquals("ESRI",        org.apache.sis.internal.util.Citations.getCodeSpace(ESRI));
-        assertEquals("NetCDF",      org.apache.sis.internal.util.Citations.getCodeSpace(NETCDF));
-        assertEquals("GeoTIFF",     org.apache.sis.internal.util.Citations.getCodeSpace(GEOTIFF));
-        assertEquals("MapInfo",     org.apache.sis.internal.util.Citations.getCodeSpace(MAP_INFO));
-        assertEquals("ISBN",        org.apache.sis.internal.util.Citations.getCodeSpace(ISBN));
-        assertEquals("ISSN",        org.apache.sis.internal.util.Citations.getCodeSpace(ISSN));
-        assertEquals("Proj4",       org.apache.sis.internal.util.Citations.getCodeSpace(PROJ4));
-        assertEquals("S57",         org.apache.sis.internal.util.Citations.getCodeSpace(S57));
-        assertNull  ("ISO_19115-1", org.apache.sis.internal.util.Citations.getCodeSpace(ISO_19115.get(0)));
-        assertNull  ("ISO_19115-2", org.apache.sis.internal.util.Citations.getCodeSpace(ISO_19115.get(1)));
+        final SimpleCitation citation = new SimpleCitation(" Valid\u2060Id\u200Bentifier ");
+        assertEquals("ValidIdentifier", Citations.getCodeSpace(citation));
+
+        assertNull("Shall not be taken as a valid identifier.",
+                Citations.getCodeSpace(new SimpleCitation("Proj.4")));
+        assertEquals("Shall fallback on the the identifier space name.",
+                "TheProj4Space", Citations.getCodeSpace(new Proj4()));
+    }
+
+    /**
+     * A citation which is also an {@link IdentifierSpace}, for {@link #testGetCodeSpace()} purpose.
+     */
+    @SuppressWarnings("serial")
+    private static final class Proj4 extends SimpleCitation implements IdentifierSpace<Integer> {
+        Proj4() {
+            super("Proj.4");
+        }
+
+        @Override
+        public String getName() {
+            return "TheProj4Space";         // Intentionally a very different name than "Proj4".
+        }
+    }
+
+    /**
+     * Tests {@link Citations#getCodeSpace(Citation)} on the constants
+     * declared in the {@link Citations} class.
+     */
+    @Test
+    @DependsOnMethod({"testGetUnicodeIdentifier", "testGetIdentifier"})
+    public void testGetConstantCodeSpace() {
+        assertEquals("SIS",         Citations.getCodeSpace(SIS));
+        assertEquals("OGC",         Citations.getCodeSpace(WMS));
+        assertEquals("OGC",         Citations.getCodeSpace(OGC));
+        assertEquals("IOGP",        Citations.getCodeSpace(IOGP));
+        assertEquals("EPSG",        Citations.getCodeSpace(EPSG));
+        assertEquals("ESRI",        Citations.getCodeSpace(ESRI));
+        assertEquals("NetCDF",      Citations.getCodeSpace(NETCDF));
+        assertEquals("GeoTIFF",     Citations.getCodeSpace(GEOTIFF));
+        assertEquals("MapInfo",     Citations.getCodeSpace(MAP_INFO));
+        assertEquals("ISBN",        Citations.getCodeSpace(ISBN));
+        assertEquals("ISSN",        Citations.getCodeSpace(ISSN));
+        assertEquals("Proj4",       Citations.getCodeSpace(PROJ4));
+        assertEquals("S57",         Citations.getCodeSpace(S57));
+        assertNull  ("ISO_19115-1", Citations.getCodeSpace(ISO_19115.get(0)));
+        assertNull  ("ISO_19115-2", Citations.getCodeSpace(ISO_19115.get(1)));
     }
 
     /**

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/DefaultExtentTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/DefaultExtentTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/DefaultExtentTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/DefaultExtentTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -17,12 +17,16 @@
 package org.apache.sis.metadata.iso.extent;
 
 import java.net.URL;
+import java.util.Arrays;
 import java.io.IOException;
 import javax.xml.bind.JAXBException;
+import org.opengis.metadata.extent.Extent;
+import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.xml.IdentifierSpace;
+import org.apache.sis.xml.Namespaces;
+import org.apache.sis.xml.NilObject;
 import org.apache.sis.test.XMLTestCase;
 import org.apache.sis.test.DependsOn;
-import org.apache.sis.xml.Namespaces;
 import org.junit.Test;
 
 import static org.apache.sis.test.Assert.*;
@@ -34,7 +38,7 @@ import static org.apache.sis.test.TestUt
  *
  * @author  Cédric Briançon (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -58,6 +62,40 @@ public final strictfp class DefaultExten
     }
 
     /**
+     * Tests {@link DefaultExtent#intersect(Extent)}.
+     */
+    @Test
+    public void testIntersect() {
+        final DefaultGeographicBoundingBox bounds1   = new DefaultGeographicBoundingBox(10, 20, 30, 40);
+        final DefaultGeographicBoundingBox bounds2   = new DefaultGeographicBoundingBox(16, 18, 31, 42);
+        final DefaultGeographicBoundingBox clip      = new DefaultGeographicBoundingBox(15, 25, 26, 32);
+        final DefaultGeographicBoundingBox expected1 = new DefaultGeographicBoundingBox(15, 20, 30, 32);
+        final DefaultGeographicBoundingBox expected2 = new DefaultGeographicBoundingBox(16, 18, 31, 32);
+        final DefaultExtent e1 = new DefaultExtent("Somewhere", bounds1, null, null);
+        final DefaultExtent e2 = new DefaultExtent("Somewhere", clip, null, null);
+        e1.getGeographicElements().add(bounds2);
+        e1.intersect(e2);
+        assertEquals("description", "Somewhere", e1.getDescription().toString());
+        assertFalse("isNil(description)", e1.getDescription() instanceof NilObject);
+        assertArrayEquals("geographicElements", new DefaultGeographicBoundingBox[] {
+            expected1, expected2
+        }, e1.getGeographicElements().toArray());
+        /*
+         * Change the description and test again. That description should be considered missing
+         * because we have a mismatch. Also change abounding box in such a way that there is no
+         * intersection. That bounding box should be omitted.
+         */
+        bounds2.setBounds(8, 12, 33, 35);
+        e1.setGeographicElements(Arrays.asList(bounds1, bounds2));
+        e2.setDescription(new SimpleInternationalString("Somewhere else"));
+        e1.intersect(e2);
+        assertTrue("isNil(description)", e1.getDescription() instanceof NilObject);
+        assertArrayEquals("geographicElements", new DefaultGeographicBoundingBox[] {
+            expected1
+        }, e1.getGeographicElements().toArray());
+    }
+
+    /**
      * Tests the (un)marshalling of a {@code <gmd:EX_Extent>} object.
      * This test opportunistically tests setting {@code "gml:id"} value.
      *

Modified: sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -23,7 +23,10 @@ import javax.measure.Unit;
 import javax.measure.UnitConverter;
 import javax.measure.IncommensurableException;
 import org.opengis.geometry.DirectPosition;
+import org.opengis.metadata.extent.Extent;
+import org.opengis.metadata.extent.VerticalExtent;
 import org.opengis.metadata.extent.GeographicBoundingBox;
+import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.measure.Units;
 import org.apache.sis.measure.MeasurementRange;
 import org.apache.sis.test.mock.VerticalCRSMock;
@@ -47,7 +50,7 @@ import static org.junit.Assert.*;
  * @since   0.4
  * @module
  */
-@DependsOn(DefaultGeographicBoundingBoxTest.class)
+@DependsOn({DefaultGeographicBoundingBoxTest.class, DefaultExtentTest.class})
 public final strictfp class ExtentsTest extends TestCase {
     /**
      * One minute of angle, in degrees.
@@ -97,13 +100,45 @@ public final strictfp class ExtentsTest
      * Tests {@link Extents#intersection(GeographicBoundingBox, GeographicBoundingBox)}.
      */
     @Test
-    public void testIntersection() {
+    public void testGeographicIntersection() {
         final GeographicBoundingBox b1 = new DefaultGeographicBoundingBox(10, 20, 30, 40);
         final GeographicBoundingBox b2 = new DefaultGeographicBoundingBox(15, 25, 26, 32);
-        assertEquals(new DefaultGeographicBoundingBox(15, 20, 30, 32), Extents.intersection(b1, b2));
-        assertSame(b1, Extents.intersection(b1,   null));
+        assertEquals("intersect",        new DefaultGeographicBoundingBox(15, 20, 30, 32), Extents.intersection(b1, b2));
+        assertSame(b1, Extents.intersection(b1, null));
         assertSame(b2, Extents.intersection(null, b2));
-        assertNull(    Extents.intersection(null, null));
+        assertNull(    Extents.intersection((GeographicBoundingBox) null, (GeographicBoundingBox) null));
+    }
+
+    /**
+     * Tests {@link Extents#intersection(VerticalExtent, VerticalExtent)}.
+     * This test does not perform any unit conversion, because it would require the use of different CRS.
+     * For a test with unit conversion, see {@code ServicesForMetadataTest.testVerticalIntersection()} in
+     * {@code sis-referencing} module.
+     *
+     * @throws TransformException should never happen since we do not test transformation in this class.
+     */
+    @Test
+    public void testVerticalIntersection() throws TransformException {
+        final VerticalExtent e1 = new DefaultVerticalExtent(10, 20, null);
+        final VerticalExtent e2 = new DefaultVerticalExtent(15, 25, null);
+        assertEquals("intersect", new DefaultVerticalExtent(15, 20, null), Extents.intersection(e1, e2));
+        assertSame(e1, Extents.intersection(e1, null));
+        assertSame(e2, Extents.intersection(null, e2));
+        assertNull(    Extents.intersection((VerticalExtent) null, (VerticalExtent) null));
+    }
+
+    /**
+     * Tests {@link Extents#intersection(Extent, Extent)}.
+     * This test is subject to the same limitation than {@link #testVerticalIntersection()}.
+     */
+    @Test
+    public void testExtentIntersection() {
+        final Extent e1 = new DefaultExtent(null, new DefaultGeographicBoundingBox(10, 20, 30, 40), new DefaultVerticalExtent(10, 20, null), null);
+        final Extent e2 = new DefaultExtent(null, new DefaultGeographicBoundingBox(15, 25, 26, 32), new DefaultVerticalExtent(15, 25, null), null);
+        assertEquals(     new DefaultExtent(null, new DefaultGeographicBoundingBox(15, 20, 30, 32), new DefaultVerticalExtent(15, 20, null), null), Extents.intersection(e1, e2));
+        assertSame(e1, Extents.intersection(e1, null));
+        assertSame(e2, Extents.intersection(null, e2));
+        assertNull(    Extents.intersection((Extent) null, (Extent) null));
     }
 
     /**

Modified: sis/branches/ISO-19115-3/core/sis-raster/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-raster/pom.xml?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-raster/pom.xml (original)
+++ sis/branches/ISO-19115-3/core/sis-raster/pom.xml Sat Dec  9 10:57:44 2017
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>0.8-jdk8-SNAPSHOT</version>
+    <version>1.0-jdk8-SNAPSHOT</version>
   </parent>
 
 

Modified: sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/pom.xml?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/pom.xml (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/pom.xml Sat Dec  9 10:57:44 2017
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>0.8-jdk8-SNAPSHOT</version>
+    <version>1.0-jdk8-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.sis.core</groupId>

Modified: sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/GeohashReferenceSystem.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/GeohashReferenceSystem.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/GeohashReferenceSystem.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/GeohashReferenceSystem.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -43,6 +43,11 @@ import org.opengis.referencing.gazetteer
 
 /**
  * Geographic coordinates represented as <cite>geohashes</cite> strings.
+ * Geohash is a simple encoding of geographic coordinates into a short string of letters and digits.
+ * Longer strings are more accurate, however the accuracy is not uniformly distributed between latitude
+ * and longitude, and removing digits decreases accuracy faster when the point is located close to the
+ * equator than close to a pole. For a system having more uniform accuracy, see the
+ * {@linkplain MilitaryGridReferenceSystem Military Grid Reference System} (MGRS).
  *
  * @author  Chris Mattmann (JPL)
  * @author  Martin Desruisseaux (Geomatys)

Modified: sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -219,7 +219,7 @@ public class MilitaryGridReferenceSystem
     final CommonCRS datum;
 
     /**
-     * Whether {@link Encoder} should infer the datum from the given coordinates
+     * Whether {@link MilitaryGridReferenceSystem.Encoder} should infer the datum from the given coordinates
      * instead than using {@link #datum}.
      */
     final boolean avoidDatumChange;

Modified: sis/branches/ISO-19115-3/core/sis-referencing/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/pom.xml?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/pom.xml (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/pom.xml Sat Dec  9 10:57:44 2017
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>0.8-jdk8-SNAPSHOT</version>
+    <version>1.0-jdk8-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.sis.core</groupId>

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -47,8 +47,9 @@ import static org.apache.sis.util.Argume
 import static org.apache.sis.util.ArgumentChecks.ensureDimensionMatches;
 import static org.apache.sis.util.StringBuilders.trimFractionalPart;
 import static org.apache.sis.math.MathFunctions.epsilonEqual;
-import static org.apache.sis.math.MathFunctions.isNegative;
 import static org.apache.sis.math.MathFunctions.isPositive;
+import static org.apache.sis.math.MathFunctions.isNegative;
+import static org.apache.sis.math.MathFunctions.isNegativeZero;
 
 
 /**
@@ -213,7 +214,17 @@ public abstract class AbstractEnvelope i
      * @return {@code true} if the range meaning is {@code WRAPAROUND}.
      */
     static boolean isWrapAround(final CoordinateReferenceSystem crs, final int dimension) {
-        final CoordinateSystemAxis axis = getAxis(crs, dimension);
+        return isWrapAround(getAxis(crs, dimension));
+    }
+
+    /**
+     * Returns {@code true} if the given axis is non-null and has the
+     * {@link RangeMeaning#WRAPAROUND WRAPAROUND} range meaning.
+     *
+     * @param  axis  the axis to test, or {@code null}.
+     * @return {@code true} if the range meaning is {@code WRAPAROUND}.
+     */
+    static boolean isWrapAround(final CoordinateSystemAxis axis) {
         return (axis != null) && RangeMeaning.WRAPAROUND.equals(axis.getRangeMeaning());
     }
 
@@ -225,7 +236,7 @@ public abstract class AbstractEnvelope i
      * @return the spanning of the given axis.
      */
     static double getSpan(final CoordinateSystemAxis axis) {
-        if (axis != null && RangeMeaning.WRAPAROUND.equals(axis.getRangeMeaning())) {
+        if (isWrapAround(axis)) {
             return axis.getMaximumValue() - axis.getMinimumValue();
         }
         return Double.NaN;
@@ -338,9 +349,10 @@ public abstract class AbstractEnvelope i
 
     /**
      * Returns the minimal ordinate value for the specified dimension. In the typical case
-     * of envelopes <em>not</em> spanning the anti-meridian, this method returns the
+     * of non-empty envelopes <em>not</em> spanning the anti-meridian, this method returns the
      * {@link #getLower(int)} value verbatim. In the case of envelope spanning the anti-meridian,
      * this method returns the {@linkplain CoordinateSystemAxis#getMinimumValue() axis minimum value}.
+     * If the range in the given dimension is invalid, then this method returns {@code NaN}.
      *
      * @param  dimension  the dimension for which to obtain the ordinate value.
      * @return the minimal ordinate value at the given dimension.
@@ -352,16 +364,17 @@ public abstract class AbstractEnvelope i
         double lower = getLower(dimension);
         if (isNegative(getUpper(dimension) - lower)) {              // Special handling for -0.0
             final CoordinateSystemAxis axis = getAxis(getCoordinateReferenceSystem(), dimension);
-            lower = (axis != null) ? axis.getMinimumValue() : Double.NEGATIVE_INFINITY;
+            lower = isWrapAround(axis) ? axis.getMinimumValue() : Double.NaN;
         }
         return lower;
     }
 
     /**
      * Returns the maximal ordinate value for the specified dimension. In the typical case
-     * of envelopes <em>not</em> spanning the anti-meridian, this method returns the
+     * of non-empty envelopes <em>not</em> spanning the anti-meridian, this method returns the
      * {@link #getUpper(int)} value verbatim. In the case of envelope spanning the anti-meridian,
      * this method returns the {@linkplain CoordinateSystemAxis#getMaximumValue() axis maximum value}.
+     * If the range in the given dimension is invalid, then this method returns {@code NaN}.
      *
      * @param  dimension  the dimension for which to obtain the ordinate value.
      * @return the maximal ordinate value at the given dimension.
@@ -373,7 +386,7 @@ public abstract class AbstractEnvelope i
         double upper = getUpper(dimension);
         if (isNegative(upper - getLower(dimension))) {              // Special handling for -0.0
             final CoordinateSystemAxis axis = getAxis(getCoordinateReferenceSystem(), dimension);
-            upper = (axis != null) ? axis.getMaximumValue() : Double.POSITIVE_INFINITY;
+            upper = isWrapAround(axis) ? axis.getMaximumValue() : Double.NaN;
         }
         return upper;
     }
@@ -417,7 +430,7 @@ public abstract class AbstractEnvelope i
      * If no shift can be applied, returns {@code NaN}.
      */
     static double fixMedian(final CoordinateSystemAxis axis, final double median) {
-        if (axis != null && RangeMeaning.WRAPAROUND.equals(axis.getRangeMeaning())) {
+        if (isWrapAround(axis)) {
             final double minimum = axis.getMinimumValue();
             final double maximum = axis.getMaximumValue();
             final double cycle   = maximum - minimum;
@@ -468,7 +481,7 @@ public abstract class AbstractEnvelope i
      * @return a positive span, or NaN if the span can not be fixed.
      */
     static double fixSpan(final CoordinateSystemAxis axis, double span) {
-        if (axis != null && RangeMeaning.WRAPAROUND.equals(axis.getRangeMeaning())) {
+        if (isWrapAround(axis)) {
             final double cycle = axis.getMaximumValue() - axis.getMinimumValue();
             if (cycle > 0 && cycle != Double.POSITIVE_INFINITY) {
                 span += cycle;
@@ -809,10 +822,12 @@ public abstract class AbstractEnvelope i
                     // Not the excluded case, go to next dimension.
                     continue;
                 }
-                // If this envelope does not span the anti-meridian but the given envelope
-                // does, we don't contain the given envelope except in the special case
-                // where the envelope spanning is equals or greater than the axis spanning
-                // (including the case where this envelope expands to infinities).
+                /*
+                 * If this envelope does not span the anti-meridian but the given envelope does,
+                 * then this envelope does not contain the given envelope except in the special
+                 * case where the envelope spanning is equals or greater than the axis spanning
+                 * (including the case where this envelope expands to infinities).
+                 */
                 if ((lower0 == Double.NEGATIVE_INFINITY && upper0 == Double.POSITIVE_INFINITY) ||
                     (upper0 - lower0 >= getSpan(getAxis(getCoordinateReferenceSystem(), i))))
                 {
@@ -836,6 +851,14 @@ public abstract class AbstractEnvelope i
                         continue;
                     }
                 }
+            } else if (isNegativeZero(upper0 - lower0)) {
+                /*      !upperCnd
+                 *  ────────┬────────
+                 *        ┌─┼────┐
+                 *        └─┼────┘
+                 *  ────────┴────────
+                 *      !lowerCnd */
+                continue;
             }
             return false;
         }
@@ -1108,7 +1131,7 @@ public abstract class AbstractEnvelope i
      *
      * <div class="note"><b>Note:</b>
      * The {@code BOX} element is not part of the standard <cite>Well Known Text</cite> (WKT) format.
-     * However it is understood by many softwares, for example GDAL and PostGIS.</div>
+     * However it is understood by many software libraries, for example GDAL and PostGIS.</div>
      *
      * The string returned by this method can be {@linkplain GeneralEnvelope#GeneralEnvelope(CharSequence) parsed}
      * by the {@code GeneralEnvelope} constructor.

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -459,7 +459,7 @@ scanNumber: while ((i += Character.charC
         double lower = ordinates[i];
         if (isNegative(ordinates[i + (ordinates.length >>> 1)] - lower)) {      // Special handling for -0.0
             final CoordinateSystemAxis axis = getAxis(crs, dimension);
-            lower = (axis != null) ? axis.getMinimumValue() : Double.NEGATIVE_INFINITY;
+            lower = isWrapAround(axis) ? axis.getMinimumValue() : Double.NaN;
         }
         return lower;
     }
@@ -474,7 +474,7 @@ scanNumber: while ((i += Character.charC
         double upper = ordinates[i + (ordinates.length >>> 1)];
         if (isNegative(upper - ordinates[i])) {                                 // Special handling for -0.0
             final CoordinateSystemAxis axis = getAxis(crs, dimension);
-            upper = (axis != null) ? axis.getMaximumValue() : Double.POSITIVE_INFINITY;
+            upper = isWrapAround(axis) ? axis.getMaximumValue() : Double.NaN;
         }
         return upper;
     }

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -32,12 +32,11 @@ import org.apache.sis.util.Emptiable;
 
 import static java.lang.Double.NaN;
 import static java.lang.Double.isNaN;
-import static java.lang.Double.POSITIVE_INFINITY;
-import static java.lang.Double.NEGATIVE_INFINITY;
 import static java.lang.Double.doubleToLongBits;
+import static org.apache.sis.math.MathFunctions.isSameSign;
 import static org.apache.sis.math.MathFunctions.isPositive;
 import static org.apache.sis.math.MathFunctions.isNegative;
-import static org.apache.sis.math.MathFunctions.isSameSign;
+import static org.apache.sis.math.MathFunctions.isNegativeZero;
 import static org.apache.sis.util.ArgumentChecks.ensureDimensionMatches;
 import static org.apache.sis.internal.referencing.Formulas.isPoleToPole;
 
@@ -388,7 +387,7 @@ public class Envelope2D extends Rectangl
         }
         if (isNegative(span)) {                                         // Special handling for -0.0
             final CoordinateSystemAxis axis = getAxis(crs, dimension);
-            return (axis != null) ? axis.getMinimumValue() : NEGATIVE_INFINITY;
+            return isWrapAround(axis) ? axis.getMinimumValue() : NaN;
         }
         return value;
     }
@@ -412,7 +411,7 @@ public class Envelope2D extends Rectangl
         }
         if (isNegative(span)) {                                         // Special handling for -0.0
             final CoordinateSystemAxis axis = getAxis(crs, dimension);
-            return (axis != null) ? axis.getMaximumValue() : POSITIVE_INFINITY;
+            return isWrapAround(axis) ? axis.getMaximumValue() : NaN;
         }
         return value + span;
     }
@@ -771,13 +770,15 @@ public class Envelope2D extends Rectangl
                 if (!isNegativeUnsafe(span1) || isNegativeUnsafe(span0)) {
                     continue;
                 }
-                if (span0 >= AbstractEnvelope.getSpan(getAxis(getCoordinateReferenceSystem(), i))) {
+                if (span0 >= AbstractEnvelope.getSpan(getAxis(crs, i))) {
                     continue;
                 }
             } else if (minCondition != maxCondition) {
                 if (isNegative(span0) && isPositive(span1)) {
                     continue;
                 }
+            } else if (isNegativeZero(span0)) {
+                continue;
             }
             return false;
         }
@@ -882,8 +883,13 @@ public class Envelope2D extends Rectangl
                 min1  = rect.getY();
                 span1 = (env != null) ? env.height : rect.getHeight();
             }
-            final double max0 = min0 + span0;
-            final double max1 = min1 + span1;
+            /*
+             * The purpose for (min != 0) test before addition is to preserve the sign of zero.
+             * In the [0 … -0] range, the span is -0. But computing max = 0 + -0 result in +0,
+             * while we need max = -0 in this case.
+             */
+            final double max0 = (min0 != 0) ? min0 + span0 : span0;
+            final double max1 = (min1 != 0) ? min1 + span1 : span1;
             double min = Math.max(min0, min1);
             double max = Math.min(max0, max1);
             /*
@@ -906,10 +912,10 @@ public class Envelope2D extends Rectangl
                 }
                 if (intersect == 0 || intersect == 3) {
                     final double csSpan = AbstractEnvelope.getSpan(getAxis(crs, i));
-                    if (span1 >= csSpan) {
+                    if (span1 >= csSpan || isNegativeZero(span1)) {
                         min = min0;
                         max = max0;
-                    } else if (span0 >= csSpan) {
+                    } else if (span0 >= csSpan || isNegativeZero(span0)) {
                         min = min1;
                         max = max1;
                     } else {



Mime
View raw message