sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1649087 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/internal/referencing/ main/java/org/apache/sis/referencing/crs/ main/java/org/apache/sis/referencing/cs/ test/java/org/apache/sis/referencing/cs/
Date Fri, 02 Jan 2015 18:44:01 GMT
Author: desruisseaux
Date: Fri Jan  2 18:44:00 2015
New Revision: 1649087

URL: http://svn.apache.org/r1649087
Log:
Introduce a new AxesConvention.CONVENTIONALLY_ORIENTED constant more clearly targeted to Web
Map Service (WMS).
This new constant is functionally between AxesConvention.RIGHT_HANDED and AxesConvention.NORMALIZED.
This give us more freedom for tuning NORMALIZED, for example by forcing the prime meridian
to Greenwich
(whatever this would be a good idea or not is still an open question).

This commit contains also an initial draft of a ReferencingUtilities.toNormalizedGeographicCRS
internal method,
which is actually the reason why we need to clarify the AxesConvention constants a little
bit more (especially
regarding PrimeMeridian normalization).

Modified:
    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/crs/AbstractCRS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/AbstractCSTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/NormalizerTest.java

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=1649087&r1=1649086&r2=1649087&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] Fri Jan  2 18:44:00 2015
@@ -23,10 +23,20 @@ import org.opengis.annotation.UML;
 import org.opengis.annotation.Specification;
 import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.*;
+import org.opengis.referencing.datum.Datum;
+import org.opengis.referencing.datum.GeodeticDatum;
 import org.apache.sis.util.Static;
+import org.apache.sis.util.Utilities;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.jaxb.Context;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.crs.DefaultGeographicCRS;
+import org.apache.sis.referencing.cs.AxesConvention;
+import org.apache.sis.referencing.datum.DefaultGeodeticDatum;
+
+import static java.util.Collections.singletonMap;
+import static org.opengis.referencing.IdentifiedObject.NAME_KEY;
 
 
 /**
@@ -157,6 +167,59 @@ public final class ReferencingUtilities
     }
 
     /**
+     * Derives a geographic CRS with (<var>longitude</var>, <var>latitude</var>)
axis order
+     * in decimal degrees, relative to Greenwich. If no such CRS can be obtained of created,
+     * returns null.
+     *
+     * <p>This method is similar to the use of {@link AxesConvention#NORMALIZED} except
for the following:</p>
+     * <ul>
+     *   <li>The datum prime meridian is set to Greenwich.</li>
+     *   <li>This method does not require an Apache SIS implementation of the CRS object.</li>
+     * </ul>
+     *
+     * @param  crs A source CRS, or {@code null}.
+     * @return A two-dimensional geographic CRS with standard axes, or {@code null} if none.
+     */
+    public static GeographicCRS toNormalizedGeographicCRS(CoordinateReferenceSystem crs)
{
+        /*
+         * ProjectedCRS instances always have a GeographicCRS as their base.
+         * More generally, derived CRS are always derived from a base, which
+         * is often (but not necessarily) geographic.
+         */
+        while (crs instanceof GeneralDerivedCRS) {
+            crs = ((GeneralDerivedCRS) crs).getBaseCRS();
+        }
+        /*
+         * At this point we usually have a GeographicCRS, but it could also be a GeocentricCRS.
+         * In any case if the datum does not have the Greenwich prime meridian, we need to
fix.
+         */
+        if (crs instanceof GeodeticCRS) {
+            GeodeticDatum datum = ((GeodeticCRS) crs).getDatum();
+            if (datum.getPrimeMeridian().getGreenwichLongitude() != 0) {
+                datum = new DefaultGeodeticDatum(singletonMap(NAME_KEY, datum.getName().getCode()),
+                        datum.getEllipsoid(), CommonCRS.WGS84.primeMeridian());
+            } else if (crs instanceof DefaultGeographicCRS) {
+                return ((DefaultGeographicCRS) crs).forConvention(AxesConvention.NORMALIZED);
+            }
+            final CoordinateSystem cs = CommonCRS.defaultGeographic().getCoordinateSystem();
+            if (crs instanceof GeographicCRS && Utilities.equalsIgnoreMetadata(cs,
crs.getCoordinateSystem())) {
+                return (GeographicCRS) crs;
+            }
+            return new DefaultGeographicCRS(singletonMap(DefaultGeographicCRS.NAME_KEY, crs.getName().getCode()),
+                    datum, (EllipsoidalCS) cs);
+        }
+        if (crs instanceof CompoundCRS) {
+            for (final CoordinateReferenceSystem e : ((CompoundCRS) crs).getComponents())
{
+                final GeographicCRS candidate = toNormalizedGeographicCRS(e);
+                if (candidate != null) {
+                    return candidate;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
      * Ensures that the given argument value is {@code false}. This method is invoked by
private setter methods,
      * which are themselves invoked by JAXB at unmarshalling time. Invoking this method from
those setter methods
      * serves two purposes:

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java?rev=1649087&r1=1649086&r2=1649087&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
[UTF-8] Fri Jan  2 18:44:00 2015
@@ -18,6 +18,7 @@ package org.apache.sis.referencing.crs;
 
 import java.util.Map;
 import java.util.EnumMap;
+import java.util.ConcurrentModificationException;
 import javax.measure.unit.Unit;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -70,7 +71,7 @@ import java.util.Objects;
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4 (derived from geotk-1.2)
- * @version 0.4
+ * @version 0.5
  * @module
  *
  * @see AbstractCS
@@ -103,12 +104,12 @@ public class AbstractCRS extends Abstrac
     private CoordinateSystem coordinateSystem;
 
     /**
-     * Other coordinate reference systems derived from this CRS.
+     * Other coordinate reference systems computed from this CRS by the application of an
axes convention.
      * Created only when first needed.
      *
      * @see #forConvention(AxesConvention)
      */
-    private transient Map<AxesConvention,AbstractCRS> derived;
+    private transient Map<AxesConvention,AbstractCRS> forConvention;
 
     /**
      * Constructs a new object in which every attributes are set to a null value.
@@ -318,15 +319,35 @@ public class AbstractCRS extends Abstrac
     }
 
     /**
-     * Returns the map of cached CRS for axes conventions.
-     * This method shall be invoked in a synchronized block.
+     * Returns the existing CRS for the given convention, or {@code null} if none.
      */
-    final Map<AxesConvention,AbstractCRS> derived() {
+    final AbstractCRS getCached(final AxesConvention convention) {
         assert Thread.holdsLock(this);
-        if (derived == null) {
-            derived = new EnumMap<>(AxesConvention.class);
+        return (forConvention != null) ? forConvention.get(convention) : null;
+    }
+
+    /**
+     * Sets the CRS for the given axes convention.
+     *
+     * @param crs The CRS to cache.
+     * @return The cached CRS. May be different than the given {@code crs} if an existing
instance has been found.
+     */
+    final AbstractCRS setCached(final AxesConvention convention, AbstractCRS crs) {
+        assert Thread.holdsLock(this);
+        if (forConvention == null) {
+            forConvention = new EnumMap<>(AxesConvention.class);
+        } else if (crs != this) {
+            for (final AbstractCRS existing : forConvention.values()) {
+                if (crs.equals(existing)) {
+                    crs = existing;
+                    break;
+                }
+            }
+        }
+        if (forConvention.put(convention, crs) != null) {
+            throw new ConcurrentModificationException(); // Should never happen, unless we
have a synchronization bug.
         }
-        return derived;
+        return crs;
     }
 
     /**
@@ -340,8 +361,7 @@ public class AbstractCRS extends Abstrac
      */
     public synchronized AbstractCRS forConvention(final AxesConvention convention) {
         ensureNonNull("convention", convention);
-        final Map<AxesConvention,AbstractCRS> derived = derived();
-        AbstractCRS crs = derived.get(convention);
+        AbstractCRS crs = getCached(convention);
         if (crs == null) {
             final AbstractCS cs = AbstractCS.castOrCopy(coordinateSystem);
             final AbstractCS candidate = cs.forConvention(convention);
@@ -349,14 +369,8 @@ public class AbstractCRS extends Abstrac
                 crs = this;
             } else {
                 crs = createSameType(IdentifiedObjects.getProperties(this, IDENTIFIERS_KEY),
candidate);
-                for (final AbstractCRS existing : derived.values()) {
-                    if (crs.equals(existing)) {
-                        crs = existing;
-                        break;
-                    }
-                }
             }
-            derived.put(convention, crs);
+            crs = setCached(convention, crs);
         }
         return crs;
     }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java?rev=1649087&r1=1649086&r2=1649087&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
[UTF-8] Fri Jan  2 18:44:00 2015
@@ -333,8 +333,7 @@ public class DefaultCompoundCRS extends
     @Override
     public synchronized DefaultCompoundCRS forConvention(final AxesConvention convention)
{
         ensureNonNull("convention", convention);
-        final Map<AxesConvention,AbstractCRS> derived = derived();
-        DefaultCompoundCRS crs = (DefaultCompoundCRS) derived.get(convention);
+        DefaultCompoundCRS crs = (DefaultCompoundCRS) getCached(convention);
         if (crs == null) {
             crs = this;
             boolean changed = false;
@@ -356,7 +355,7 @@ public class DefaultCompoundCRS extends
                 }
                 crs = new DefaultCompoundCRS(IdentifiedObjects.getProperties(this, IDENTIFIERS_KEY),
newComponents);
             }
-            derived.put(convention, crs);
+            crs = (DefaultCompoundCRS) setCached(convention, crs);
         }
         return crs;
     }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java?rev=1649087&r1=1649086&r2=1649087&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
[UTF-8] Fri Jan  2 18:44:00 2015
@@ -31,8 +31,8 @@ import org.apache.sis.metadata.iso.Immut
 import org.apache.sis.referencing.cs.AxesConvention;
 import org.apache.sis.referencing.AbstractReferenceSystem;
 import org.apache.sis.io.wkt.Formatter;
-
 import org.apache.sis.measure.Longitude;
+
 import static org.apache.sis.internal.referencing.HardCoded.CRS;
 import static org.apache.sis.internal.referencing.HardCoded.EPSG;
 import static org.apache.sis.internal.referencing.HardCoded.CRS27;

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java?rev=1649087&r1=1649086&r2=1649087&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
[UTF-8] Fri Jan  2 18:44:00 2015
@@ -64,7 +64,7 @@ import static org.apache.sis.util.Utilit
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4 (derived from geotk-2.0)
- * @version 0.4
+ * @version 0.5
  * @module
  *
  * @see DefaultCoordinateSystemAxis
@@ -325,8 +325,7 @@ public class AbstractCS extends Abstract
 
     /**
      * Returns a coordinate system equivalent to this one but with axes rearranged according
the given convention.
-     * If this coordinate system is already compatible with the given convention, then this
method returns
-     * {@code this}.
+     * If this coordinate system is already compatible with the given convention, then this
method returns {@code this}.
      *
      * @param  convention The axes convention for which a coordinate system is desired.
      * @return A coordinate system compatible with the given convention (may be {@code this}).
@@ -341,9 +340,10 @@ public class AbstractCS extends Abstract
         AbstractCS cs = derived.get(convention);
         if (cs == null) {
             switch (convention) {
-                case NORMALIZED:     cs = Normalizer.normalize(this, true);  break;
-                case RIGHT_HANDED:   cs = Normalizer.normalize(this, false); break;
-                case POSITIVE_RANGE: cs = Normalizer.shiftAxisRange(this);   break;
+                case NORMALIZED:              cs = Normalizer.normalize(this, true,  true);
 break;
+                case CONVENTIONALLY_ORIENTED: cs = Normalizer.normalize(this, true,  false);
break;
+                case RIGHT_HANDED:            cs = Normalizer.normalize(this, false, false);
break;
+                case POSITIVE_RANGE:          cs = Normalizer.shiftAxisRange(this);     
    break;
                 default: throw new AssertionError(convention);
             }
             for (final AbstractCS existing : derived.values()) {

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java?rev=1649087&r1=1649086&r2=1649087&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
[UTF-8] Fri Jan  2 18:44:00 2015
@@ -17,20 +17,46 @@
 package org.apache.sis.referencing.cs;
 
 import org.opengis.referencing.cs.AxisDirection; // For javadoc
-import org.opengis.referencing.cs.CoordinateSystem;
 
 
 /**
  * High-level characteristics about the axes of a coordinate system.
  * This enumeration provides a convenient way to identify some common axes conventions like
- * (<var>latitude</var>, <var>longitude</var>) versus (<var>longitude</var>,
<var>latitude</var>) axis order,
- * or [-180 … +180]° versus [0 … 360]° longitude range.
+ * (<var>longitude</var>, <var>latitude</var>) axis order or the
[0 … 360]° range of longitude values
+ * (instead than the more usual [-180 … +180]° range). Apache SIS Coordinate System objects
can be made
+ * compliant to a given convention by calls to their {@code forConvention(AxesConvention)}
method.
+ * The following table summarizes the coordinate system aspects that may be modified:
+ *
+ * <table class="sis">
+ *   <caption>Coordinate system properties concerned by enumeration values</caption>
+ *   <tr>
+ *     <th>Property</th>
+ *     <th>Enumeration values</th>
+ *     <th>Example</th>
+ *   </tr>
+ *   <tr>
+ *     <td>Axis order</td>
+ *     <td>{@link #NORMALIZED}, {@link #CONVENTIONALLY_ORIENTED}, {@link #RIGHT_HANDED}</td>
+ *     <td>(<var>longitude</var>, <var>latitude</var>)</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Axis direction</td>
+ *     <td>{@link #NORMALIZED}, {@link #CONVENTIONALLY_ORIENTED}</td>
+ *     <td>({@linkplain AxisDirection#EAST east}, {@linkplain AxisDirection#NORTH north})</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Unit of measurement</td>
+ *     <td>{@link #NORMALIZED}</td>
+ *     <td>Angular degrees, metres</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Range of values</td>
+ *     <td>{@link #POSITIVE_RANGE}</td>
+ *     <td>[0 … 360]° of longitude</td>
+ *   </tr>
+ * </table>
  *
- * <p>Enumeration values are inferred from the properties of given {@link CoordinateSystem}
instances.
- * This enumeration does not add new information and does not aim to cover all possible conventions
– it is
- * only a convenience for identifying some common patterns.</p>
- *
- * {@section Axis order}
+ * {@section Discussion on axis order}
  * The axis order is specified by the authority (typically a national agency) defining the
Coordinate Reference System
  * (CRS). The order depends on the CRS type and the country defining the CRS. In the case
of geographic CRS, the
  * (<var>latitude</var>, <var>longitude</var>) axis order is widely
used by geographers and pilotes for centuries.
@@ -46,23 +72,7 @@ import org.opengis.referencing.cs.Coordi
  * {@link org.apache.sis.referencing.CRS#forCode(String)} method. The actual axis order can
be verified after the CRS
  * creation with {@code System.out.println(crs)}. If (<var>x</var>,<var>y</var>)
axis order is wanted for compatibility
  * with older OGC specifications or other softwares, CRS forced to "longitude first" axis
order can be created using the
- * {@link #RIGHT_HANDED} or {@link #NORMALIZED} enumeration value.</p>
- *
- * {@section Normalized coordinate systems}
- * <cite>Right-handed</cite> coordinate systems have a precise meaning in Apache
SIS.
- * However SIS defines also <cite>normalized</cite> coordinate systems in a more
heuristic way.
- * A similar concept appears in the Web Map Services (WMS) 1.3 specification, quoted here:
- *
- * <div class="note"><b>6.7.2 Map CS</b> —
- * The usual orientation of the Map CS shall be such that the <var>i</var> axis
is parallel to the East-to-West axis
- * of the Layer CRS and increases Eastward, and the <var>j</var> axis is parallel
to the North-to-South axis of the
- * Layer CRS and increases Southward. This orientation will not be possible in some cases,
as (for example) in an
- * orthographic projection over the South Pole. The convention to be followed is that, wherever
possible, East shall
- * be to the right edge and North shall be toward the upper edge of the Map CS.</div>
- *
- * In addition to WMS, Apache SIS uses normalized coordinate systems in map projections.
- * More information are provided in the <cite>Axis units and directions</cite>
section of
- * {@linkplain org.apache.sis.referencing.operation.projection map projection package}.
+ * {@link #CONVENTIONALLY_ORIENTED} or {@link #NORMALIZED} enumeration value.</p>
  *
  * {@section Range of longitude values}
  * Most geographic CRS have a longitude axis defined in the [-180 … +180]° range. All
map projections in Apache SIS are
@@ -74,69 +84,108 @@ import org.opengis.referencing.cs.Coordi
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4 (derived from geotk-3.20)
- * @version 0.4
+ * @version 0.5
  * @module
  *
  * @see AbstractCS#forConvention(AxesConvention)
+ * @see org.apache.sis.referencing.crs.AbstractCRS#forConvention(AxesConvention)
  */
 public enum AxesConvention {
     /**
-     * Axes order, direction and units are forced to commonly used pre-defined values.
-     * This enum identifies the following changes to apply on a coordinate system:
+     * Axes order, direction, units, prime meridian and range of ordinate values are forced
to commonly used
+     * pre-defined values. This enum represents the following changes to apply on a coordinate
system:
      *
      * <ul>
-     *   <li>Directions opposites to the following ones are replaced by their "forward"
counterpart
-     *       (e.g. {@code SOUTH} → {@code NORTH}):
+     *   <li>Axes are oriented and ordered as defined for {@link #CONVENTIONALLY_ORIENTED}
coordinate systems.</li>
+     *   <li>Known units are normalized:
      *     <ul>
-     *       <li>{@link AxisDirection#EAST EAST}, {@link AxisDirection#NORTH NORTH},
-     *           {@link AxisDirection#UP UP}, {@link AxisDirection#FUTURE FUTURE} —
-     *           commonly used (<var>x</var>, <var>y</var>, <var>z</var>,
<var>t</var>) directions for coordinates.</li>
-     *       <li>{@link AxisDirection#DISPLAY_RIGHT DISPLAY_RIGHT}, {@link AxisDirection#DISPLAY_DOWN
DISPLAY_DOWN} —
-     *           commonly used (<var>x</var>, <var>y</var>) directions
for screen devices.</li>
-     *       <li>{@link AxisDirection#ROW_POSITIVE ROW_POSITIVE},
-     *           {@link AxisDirection#COLUMN_POSITIVE COLUMN_POSITIVE} — indices in grids
or matrices.</li>
+     *       <li>Angular units are set to {@link javax.measure.unit.NonSI#DEGREE_ANGLE}.</li>
+     *       <li>Linear units are set to {@link javax.measure.unit.SI#METRE}.</li>
+     *       <li>Temporal units are set to {@link javax.measure.unit.NonSI#DAY}.</li>
      *     </ul>
      *   </li>
-     *   <li>Axes with the new directions are reordered for a <cite>right-handed</cite>
coordinate system.</li>
-     *   <li>Angular units are set to {@link javax.measure.unit.NonSI#DEGREE_ANGLE}.</li>
-     *   <li>Linear units are set to {@link javax.measure.unit.SI#METRE}.</li>
-     *   <li>Temporal units are set to {@link javax.measure.unit.NonSI#DAY}.</li>
      * </ul>
      *
      * <div class="note"><b>Note:</b>
      * The rules for normalized coordinate systems may be adjusted in future SIS versions
based on experience gained.
-     * For more predictable results, consider using the {@link #RIGHT_HANDED} enum instead.</div>
+     * For more predictable results, consider using the {@link #CONVENTIONALLY_ORIENTED}
or {@link #RIGHT_HANDED} enum
+     * instead.</div>
      *
      * @see org.apache.sis.referencing.CommonCRS#normalizedGeographic()
      */
     NORMALIZED,
 
     /**
-     * Axes are reordered for a <cite>right-handed</cite> coordinate system.
Directions, ranges and units are unchanged.
-     * In the two-dimensional case, the handedness is defined from the point of view of an
observer above the plane of
-     * the system.
-     *
-     * <p>This enum is often used for deriving a coordinate system with the (<var>longitude</var>,
<var>latitude</var>)
-     * or (<var>x</var>,<var>y</var>) axis order. While it works
in many cases, note that a right-handed coordinate system
-     * does not guarantee that longitude or <var>x</var> axis will be first in
every cases. The most notable exception
-     * is the (North, West) case.</p>
+     * Axes are oriented toward conventional directions and ordered for a {@linkplain #RIGHT_HANDED
right-handed}
+     * coordinate system. Ranges of ordinate values and units of measurement are unchanged.
+     *
+     * <p>More specifically, directions opposites to the following ones are replaced
by their "forward" counterpart
+     * (e.g. {@code SOUTH} → {@code NORTH}):</p>
      *
-     * <div class="note"><b>Note:</b>
-     * We do not provide a "<cite>longitude or <var>x</var> axis first</cite>"
enumeration value because such
-     * criterion is hard to apply to inter-cardinal directions and has no meaning for map
projections over a pole,
-     * while the right-handed rule can apply everywhere.</div>
-     *
-     * <div class="note"><b>Example:</b>
-     * The following table lists some axis orientations in the first column, and
-     * how those axes are reordered in a right-handed coordinate system (second column):
+     * <table class="sis">
+     *   <caption>Directions used by convention</caption>
+     *   <tr>
+     *     <th>Preferred {@link AxisDirection}</th>
+     *     <th>Purpose</th>
+     *   </tr><tr>
+     *     <td>{@link AxisDirection#EAST EAST}, {@link AxisDirection#NORTH NORTH},
+     *         {@link AxisDirection#UP UP}, {@link AxisDirection#FUTURE FUTURE}</td>
+     *     <td>Commonly used (<var>x</var>, <var>y</var>, <var>z</var>,
<var>t</var>) directions for coordinates.</td>
+     *   </tr><tr>
+     *     <td>{@link AxisDirection#DISPLAY_RIGHT DISPLAY_RIGHT}, {@link AxisDirection#DISPLAY_DOWN
DISPLAY_DOWN}</td>
+     *     <td>Commonly used (<var>x</var>, <var>y</var>) directions
for screen devices.</td>
+     *   </tr><tr>
+     *     <td>{@link AxisDirection#ROW_POSITIVE ROW_POSITIVE},
+     *         {@link AxisDirection#COLUMN_POSITIVE COLUMN_POSITIVE}</td>
+     *     <td>Indices in grids or matrices.</td>
+     *   </tr>
+     * </table>
+     *
+     * Then, axes are ordered for {@link #RIGHT_HANDED} coordinate system.
+     *
+     * {@section Usage}
+     * This enum is often used for deriving a coordinate system with the (<var>longitude</var>,
<var>latitude</var>) or
+     * (<var>x</var>,<var>y</var>) axis order. We do not provide
a "<cite>longitude or <var>x</var> axis first</cite>"
+     * enumeration value because such criterion is hard to apply to inter-cardinal directions
and has no meaning for
+     * map projections over a pole, while the right-handed rule can apply everywhere.
+     *
+     * <p><cite>Right-handed</cite> coordinate systems have a precise meaning
in Apache SIS.
+     * However <cite>conventionally oriented</cite> coordinate systems have a
looser definition.
+     * A similar concept appears in the Web Map Services (WMS) 1.3 specification, quoted
here:</p>
+     *
+     * <div class="note"><b>6.7.2 Map CS</b> —
+     * The usual orientation of the Map CS shall be such that the <var>i</var>
axis is parallel to the East-to-West axis
+     * of the Layer CRS and increases Eastward, and the <var>j</var> axis is
parallel to the North-to-South axis of the
+     * Layer CRS and increases Southward. This orientation will not be possible in some cases,
as (for example) in an
+     * orthographic projection over the South Pole. The convention to be followed is that,
wherever possible, East shall
+     * be to the right edge and North shall be toward the upper edge of the Map CS.</div>
+     *
+     * @since 0.5
+     */
+    CONVENTIONALLY_ORIENTED,
+
+    /**
+     * Axes are ordered for a <cite>right-handed</cite> coordinate system. Axis
directions, ranges or ordinate values
+     * and units of measurement are unchanged. In the two-dimensional case, the handedness
is defined from the point
+     * of view of an observer above the plane of the system.
+     *
+     * <p>Note that a right-handed coordinate system does not guarantee that longitude
or <var>x</var> axis
+     * will be first in every cases. The most notable exception is the case of (West, North)
orientations.
+     * The following table lists that case, together with other common axis orientations.
+     * The axes orientations implied by this {@code RIGHT_HANDED} enum is shown,
+     * together with {@link #CONVENTIONALLY_ORIENTED} axes for reference:</p>
+     *
+     * <div class="note">
      * <table class="sis">
      *   <caption>Examples of left-handed and right-handed coordinate systems</caption>
-     *   <tr><th>Left-handed</th>   <th>Right-handed</th> 
<th>Remarks</th></tr>
-     *   <tr><td>(North, East)</td> <td>(East, North)</td>
<td>This is the most common case.</td></tr>
-     *   <tr><td>(West, North)</td> <td>(North, West)</td>
<td>This right-handed system has latitude first.</td></tr>
-     *   <tr><td>(South, West)</td> <td>(West, South)</td>
<td>Used for the mapping of southern Africa.</td></tr>
-     *   <tr><td>(South along 0°,<br>South along 90° West)</td>
-     *       <td>(South along 90° West,<br>South along 0°)</td> <td>Can
be used for the mapping of North pole.</td></tr>
+     *   <tr><th>Left-handed</th> <th>Right-handed</th> <th>Conventionally
oriented</th> <th>Remarks</th></tr>
+     *   <tr><td>North, East</td> <td>East, North</td> <td>East,
North</td> <td>This is the most common case.</td></tr>
+     *   <tr><td>West, North</td> <td>North, West</td> <td>East,
North</td> <td>This right-handed system has latitude first.</td></tr>
+     *   <tr><td>South, West</td> <td>West, South</td> <td>East,
North</td> <td>Used for the mapping of southern Africa.</td></tr>
+     *   <tr><td>South along 0°,<br>South along 90° West</td>
+     *       <td>South along 90° West,<br>South along 0°</td>
+     *       <td>(Same as right-handed)</td>
+     *       <td>Can be used for the mapping of North pole.</td></tr>
      * </table></div>
      *
      * @see org.apache.sis.referencing.cs.CoordinateSystems#angle(AxisDirection, AxisDirection)
@@ -147,12 +196,19 @@ public enum AxesConvention {
     /**
      * Axes having a <cite>wraparound</cite>
      * {@linkplain org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#getRangeMeaning()
range meaning}
-     * are shifted to their ranges of positive values. The unit and range period are unchanged.
+     * are shifted to their ranges of positive values. The units of measurement and range
period are unchanged.
      *
-     * <p>The most frequent usage of this enum is for shifting longitude values from
the [-180 … +180]° range
+     * <p><b>Usage:</b><br>
+     * The most frequent usage of this enum is for shifting longitude values from the [-180
… +180]° range
      * to the [0 … 360]° range. However this enum could also be used with climatological
calendars if their
      * time axis has a wrapround range meaning.</p>
      *
+     * <p><b>Caution:</b><br>
+     * Conversions between the original Coordinate System and new CS compliant to this {@code
POSITIVE_RANGE}
+     * may not be affine. For example if an image was spanning the [0 … 360]° range of
longitude values, then
+     * a change to the [-180 … +180]° range requires cutting the right side (the side
spanning the [180 … 360]°
+     * range of longitude values) and pasting it on the left side of the image (in the [-180
… 0]° range).</p>
+     *
      * @see org.opengis.referencing.cs.RangeMeaning#WRAPAROUND
      */
     POSITIVE_RANGE

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java?rev=1649087&r1=1649086&r2=1649087&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
[UTF-8] Fri Jan  2 18:44:00 2015
@@ -48,7 +48,7 @@ import static org.opengis.referencing.Id
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4 (derived from geotk-2.2)
- * @version 0.4
+ * @version 0.5
  * @module
  */
 final class Normalizer implements Comparable<Normalizer> {
@@ -127,9 +127,10 @@ final class Normalizer implements Compar
      * but with normalized axis direction and unit of measurement.
      *
      * @param  axis The axis to normalize.
+     * @param  normalizeUnits {@code true} for normalizing units.
      * @return An axis using normalized direction unit, or {@code axis} if the given axis
already uses the given unit.
      */
-    static CoordinateSystemAxis normalize(final CoordinateSystemAxis axis) {
+    static CoordinateSystemAxis normalize(final CoordinateSystemAxis axis, final boolean
normalizeUnits) {
         /*
          * Normalize the axis direction. For now we do not touch to inter-cardinal directions
(e.g. "North-East")
          * because it is not clear which normalization policy would match common usage.
@@ -144,12 +145,16 @@ final class Normalizer implements Compar
          * Normalize unit of measurement.
          */
         final Unit<?> unit = axis.getUnit(), newUnit;
-        if (Units.isLinear(unit)) {
-            newUnit = SI.METRE;
-        } else if (Units.isAngular(unit)) {
-            newUnit = NonSI.DEGREE_ANGLE;
-        } else if (Units.isTemporal(unit)) {
-            newUnit = NonSI.DAY;
+        if (normalizeUnits) {
+            if (Units.isLinear(unit)) {
+                newUnit = SI.METRE;
+            } else if (Units.isAngular(unit)) {
+                newUnit = NonSI.DEGREE_ANGLE;
+            } else if (Units.isTemporal(unit)) {
+                newUnit = NonSI.DAY;
+            } else {
+                newUnit = unit;
+            }
         } else {
             newUnit = unit;
         }
@@ -206,17 +211,18 @@ final class Normalizer implements Compar
      * If no axis change is needed, then this method returns {@code cs} unchanged.
      *
      * @param  cs The coordinate system to normalize.
-     * @param  allowAxisChanges {@code true} for normalizing axis directions and units.
+     * @param  normalizeAxes  {@code true} for normalizing axis directions.
+     * @param  normalizeUnits {@code true} for normalizing units (currently ignored if {@code
normalizeAxes} is {@code false}).
      * @return The normalized coordinate system.
      */
-    static AbstractCS normalize(final AbstractCS cs, final boolean allowAxisChanges) {
+    static AbstractCS normalize(final AbstractCS cs, final boolean normalizeAxes, final boolean
normalizeUnits) {
         boolean changed = false;
         final int dimension = cs.getDimension();
         final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[dimension];
         for (int i=0; i<dimension; i++) {
             CoordinateSystemAxis axis = cs.getAxis(i);
-            if (allowAxisChanges) {
-                changed |= (axis != (axis = normalize(axis)));
+            if (normalizeAxes) {
+                changed |= (axis != (axis = normalize(axis, normalizeUnits)));
             }
             axes[i] = axis;
         }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/AbstractCSTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/AbstractCSTest.java?rev=1649087&r1=1649086&r2=1649087&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/AbstractCSTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/AbstractCSTest.java
[UTF-8] Fri Jan  2 18:44:00 2015
@@ -72,10 +72,19 @@ public final strictfp class AbstractCSTe
     @Test
     public void testForRightHandedConvention() {
         final AbstractCS cs = new AbstractCS(singletonMap(NAME_KEY, "Test"),
-                HardCodedAxes.GEODETIC_LATITUDE, HardCodedAxes.TIME, HardCodedAxes.ALTITUDE,
HardCodedAxes.GEODETIC_LONGITUDE);
+                HardCodedAxes.GEODETIC_LATITUDE,
+                HardCodedAxes.TIME,
+                HardCodedAxes.ALTITUDE,
+                HardCodedAxes.GEODETIC_LONGITUDE);
         verifyAxesConvention(AxesConvention.RIGHT_HANDED, cs,
-                HardCodedAxes.GEODETIC_LONGITUDE, HardCodedAxes.GEODETIC_LATITUDE, HardCodedAxes.ALTITUDE,
HardCodedAxes.TIME);
-        assertSame("Right-handed CS shall be same as normalized.",
+                HardCodedAxes.GEODETIC_LONGITUDE,
+                HardCodedAxes.GEODETIC_LATITUDE,
+                HardCodedAxes.ALTITUDE,
+                HardCodedAxes.TIME);
+        assertSame("Right-handed CS shall be same as conventionally oriented for this test.",
+                cs.forConvention(AxesConvention.RIGHT_HANDED),
+                cs.forConvention(AxesConvention.CONVENTIONALLY_ORIENTED));
+        assertSame("Right-handed CS shall be same as normalized for this test.",
                 cs.forConvention(AxesConvention.RIGHT_HANDED),
                 cs.forConvention(AxesConvention.NORMALIZED));
     }
@@ -89,14 +98,13 @@ public final strictfp class AbstractCSTe
     public void testForNormalizedConvention() {
         /*
          * Some expected axes, identical to the ones in HardCodedAxes except for name or
units.
+         * We verify the properties inferred by the constructor as a matter of principle,
even
+         * if it is not really the purpose of this test.
          */
         final DefaultCoordinateSystemAxis EASTING = new DefaultCoordinateSystemAxis(
                 singletonMap(NAME_KEY, Vocabulary.format(Vocabulary.Keys.Unnamed)), "E",
AxisDirection.EAST, SI.METRE);
         final DefaultCoordinateSystemAxis HEIGHT = new DefaultCoordinateSystemAxis(
                 singletonMap(NAME_KEY, "Height"), "h", AxisDirection.UP, SI.METRE);
-        /*
-         * Verifies the properties inferred by the constructor.
-         */
         assertEquals("minimumValue", Double.NEGATIVE_INFINITY, EASTING.getMinimumValue(),
STRICT);
         assertEquals("maximumValue", Double.POSITIVE_INFINITY, EASTING.getMaximumValue(),
STRICT);
         assertNull  ("rangeMeaning", EASTING.getRangeMeaning());
@@ -104,14 +112,29 @@ public final strictfp class AbstractCSTe
         assertEquals("maximumValue", Double.POSITIVE_INFINITY, HEIGHT.getMaximumValue(),
STRICT);
         assertNull  ("rangeMeaning", HEIGHT.getRangeMeaning());
         /*
-         * Test RIGHT_HANDED as a matter of principle before to test NORMALIZED.
+         * Now the actual test. First we opportunistically test RIGHT_HANDED and CONVENTIONALLY_ORIENTED
+         * before to test NORMALIZED, in order to test in increasing complexity.
          */
         final AbstractCS cs = new AbstractCS(singletonMap(NAME_KEY, "Test"),
-                HardCodedAxes.TIME, HardCodedAxes.NORTHING, HardCodedAxes.WESTING, HardCodedAxes.HEIGHT_cm);
+                HardCodedAxes.TIME,
+                HardCodedAxes.NORTHING,
+                HardCodedAxes.WESTING,
+                HardCodedAxes.HEIGHT_cm);
         verifyAxesConvention(AxesConvention.RIGHT_HANDED, cs,
-                HardCodedAxes.NORTHING, HardCodedAxes.WESTING, HardCodedAxes.HEIGHT_cm, HardCodedAxes.TIME);
+                HardCodedAxes.NORTHING,
+                HardCodedAxes.WESTING,
+                HardCodedAxes.HEIGHT_cm,
+                HardCodedAxes.TIME);
+        verifyAxesConvention(AxesConvention.CONVENTIONALLY_ORIENTED, cs,
+                EASTING,
+                HardCodedAxes.NORTHING,
+                HardCodedAxes.HEIGHT_cm,
+                HardCodedAxes.TIME);
         verifyAxesConvention(AxesConvention.NORMALIZED, cs,
-                EASTING, HardCodedAxes.NORTHING, HEIGHT, HardCodedAxes.TIME);
+                EASTING,
+                HardCodedAxes.NORTHING,
+                HEIGHT,
+                HardCodedAxes.TIME);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/NormalizerTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/NormalizerTest.java?rev=1649087&r1=1649086&r2=1649087&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/NormalizerTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/NormalizerTest.java
[UTF-8] Fri Jan  2 18:44:00 2015
@@ -36,7 +36,7 @@ import static org.apache.sis.test.Refere
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4 (derived from geotk-2.4)
- * @version 0.4
+ * @version 0.5
  * @module
  */
 @DependsOn({
@@ -166,23 +166,27 @@ public final strictfp class NormalizerTe
      */
     @Test
     public void testNormalizeAxis() {
-        assertSame(HardCodedAxes.GEODETIC_LATITUDE,  Normalizer.normalize(HardCodedAxes.GEODETIC_LATITUDE));
-        assertSame(HardCodedAxes.GEODETIC_LONGITUDE, Normalizer.normalize(HardCodedAxes.GEODETIC_LONGITUDE));
-        assertSame(HardCodedAxes.EASTING,            Normalizer.normalize(HardCodedAxes.EASTING));
-        assertSame(HardCodedAxes.NORTHING,           Normalizer.normalize(HardCodedAxes.NORTHING));
-        assertSame(HardCodedAxes.ALTITUDE,           Normalizer.normalize(HardCodedAxes.ALTITUDE));
-        assertSame(HardCodedAxes.TIME,               Normalizer.normalize(HardCodedAxes.TIME));
+        boolean normalizeUnits = false;
+        do { // Executed twice, first without units normalization, then with units normalization.
+            assertSame(HardCodedAxes.GEODETIC_LATITUDE,  Normalizer.normalize(HardCodedAxes.GEODETIC_LATITUDE,
normalizeUnits));
+            assertSame(HardCodedAxes.GEODETIC_LONGITUDE, Normalizer.normalize(HardCodedAxes.GEODETIC_LONGITUDE,
normalizeUnits));
+            assertSame(HardCodedAxes.EASTING,            Normalizer.normalize(HardCodedAxes.EASTING,
normalizeUnits));
+            assertSame(HardCodedAxes.NORTHING,           Normalizer.normalize(HardCodedAxes.NORTHING,
normalizeUnits));
+            assertSame(HardCodedAxes.ALTITUDE,           Normalizer.normalize(HardCodedAxes.ALTITUDE,
normalizeUnits));
+            assertSame(HardCodedAxes.TIME,               Normalizer.normalize(HardCodedAxes.TIME,
normalizeUnits));
+        } while ((normalizeUnits = !normalizeUnits) == true);
         /*
          * Test a change of unit from centimetre to metre.
          */
+        assertSame(HardCodedAxes.HEIGHT_cm, Normalizer.normalize(HardCodedAxes.HEIGHT_cm,
false));
         assertAxisEquals("Height", "h", AxisDirection.UP,
             Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, SI.METRE, null,
-            Normalizer.normalize(HardCodedAxes.HEIGHT_cm));
+            Normalizer.normalize(HardCodedAxes.HEIGHT_cm, true));
         /*
          * Test a change of direction from West to East.
          */
         assertAxisEquals(Vocabulary.format(Vocabulary.Keys.Unnamed), "E",
             AxisDirection.EAST, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, SI.METRE,
null,
-            Normalizer.normalize(HardCodedAxes.WESTING));
+            Normalizer.normalize(HardCodedAxes.WESTING, true));
     }
 }



Mime
View raw message