You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2015/01/02 19:44:01 UTC
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/
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));
}
}