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 2014/01/30 13:37:11 UTC
svn commit: r1562800 [2/3] - in /sis/trunk: ./
core/sis-referencing/src/main/java/org/apache/sis/geometry/
core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/
core/sis-referencing/src/main/java/org/apache/sis/io/wkt/ core/sis-refere...
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTFormat.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -16,8 +16,71 @@
*/
package org.apache.sis.io.wkt;
+import java.text.Format;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import org.opengis.metadata.citation.Citation;
+import org.opengis.parameter.GeneralParameterValue;
+import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.MathTransform;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.resources.Errors;
+
+
+/**
+ * Parser and formatter for <cite>Well Known Text</cite> (WKT) objects.
+ * This format handles a pair of {@link Parser} and {@link Formatter},
+ * to be used by {@code parse} and {@code format} methods respectively.
+ * {@code WKTFormat} objects allow the following configuration:
+ *
+ * <ul>
+ * <li>The {@linkplain Symbols symbols} to use (curly braces or brackets, <i>etc.</i>)</li>
+ * <li>The preferred authority of {@linkplain IdentifiedObject#getName() object name} to
+ * format (see {@link Formatter#getName(IdentifiedObject)} for more information)</li>
+ * <li>Whatever ANSI X3.64 colors are allowed or not (default is not)</li>
+ * <li>The indentation</li>
+ * </ul>
+ *
+ * {@section String expansion}
+ * Because the strings to be parsed by this class are long and tend to contain repetitive substrings,
+ * {@code WKTFormat} provides a mechanism for performing string substitutions before the parsing take place.
+ * Long strings can be assigned short names by calls to the
+ * <code>{@linkplain #definitions()}.put(<var>key</var>,<var>value</var>)</code> method.
+ * After definitions have been added, any call to a parsing method will replace all occurrences
+ * of a short name by the associated long string.
+ *
+ * <p>The short names must comply with the rules of Java identifiers. It is recommended, but not
+ * required, to prefix the names by some symbol like {@code "$"} in order to avoid ambiguity.
+ * Note however that this class doesn't replace occurrences between quoted text, so string
+ * expansion still relatively safe even when used with non-prefixed identifiers.</p>
+ *
+ * <blockquote><font size="-1"><b>Example:</b>
+ * In the example below, the {@code $WGS84} substring which appear in the argument given to the
+ * {@code parseObject(…)} method will be expanded into the full {@code GEOGCS["WGS84", …]} string
+ * before the parsing proceed.
+ *
+ * <blockquote><code>{@linkplain #definitions()}.put("$WGS84", "GEOGCS[\"WGS84\", DATUM[</code> <i>…etc…</i> <code>]]);<br>
+ * Object crs = {@linkplain #parseObject(String) parseObject}("PROJCS[\"Mercator_1SP\", <strong>$WGS84</strong>,
+ * PROJECTION[</code> <i>…etc…</i> <code>]]");</code></blockquote>
+ * </font></blockquote>
+ *
+ * {@section Thread safety}
+ * {@code WKTFormat}s are not synchronized. It is recommended to create separated format instances for each thread.
+ * If multiple threads access a {@code WKTFormat} concurrently, it must be synchronized externally.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @author Rémi Eve (IRD)
+ * @since 0.4 (derived from geotk-3.20)
+ * @version 0.4
+ * @module
+ */
+public class WKTFormat extends Format {
+ /**
+ * For cross-version compatibility.
+ */
+ private static final long serialVersionUID = -2909110214650709560L;
-public class WKTFormat {
/**
* The indentation value to give to the {@link #setIndentation(int)}
* method for formatting the complete object on a single line.
@@ -28,4 +91,270 @@ public class WKTFormat {
* The default indentation value.
*/
static final byte DEFAULT_INDENTATION = 2;
+
+ /**
+ * The symbols to use for this formatter.
+ * The same object is also referenced in the {@linkplain #parser} and {@linkplain #formatter}.
+ * It appears here for serialization purpose.
+ */
+ private Symbols symbols = Symbols.DEFAULT;
+
+ /**
+ * The colors to use for this formatter, or {@code null} for no syntax coloring.
+ * The same object is also referenced in the {@linkplain #formatter}.
+ * It appears here for serialization purpose.
+ */
+ private Colors colors;
+
+ /**
+ * The convention to use. The same object is also referenced in the {@linkplain #formatter}.
+ * It appears here for serialization purpose.
+ */
+ private Convention convention = Convention.DEFAULT;
+
+ /**
+ * The preferred authority for objects or parameter names. A {@code null} value
+ * means that the authority shall be inferred from the {@linkplain #convention}.
+ */
+ private Citation authority;
+
+ /**
+ * The amount of spaces to use in indentation, or {@value #SINGLE_LINE} if indentation is disabled.
+ * The same value is also stored in the {@linkplain #formatter}.
+ * It appears here for serialization purpose.
+ */
+ private byte indentation = DEFAULT_INDENTATION;
+
+ /**
+ * A formatter using the same symbols than the {@linkplain #parser}.
+ * Will be created by the {@link #format} method when first needed.
+ */
+ private transient Formatter formatter;
+
+ /**
+ * Constructs a format using the default factories.
+ */
+ public WKTFormat() {
+ }
+
+ /**
+ * Returns the symbols used for parsing and formatting WKT.
+ *
+ * @return The current set of symbols used for parsing and formatting WKT.
+ */
+ public Symbols getSymbols() {
+ return symbols;
+ }
+
+ /**
+ * Sets the symbols used for parsing and formatting WKT.
+ *
+ * @param symbols The new set of symbols to use for parsing and formatting WKT.
+ */
+ public void setSymbols(final Symbols symbols) {
+ ArgumentChecks.ensureNonNull("symbols", symbols);
+ if (!symbols.equals(this.symbols)) {
+ this.symbols = symbols;
+ formatter = null;
+ }
+ }
+
+ /**
+ * Returns the colors to use for syntax coloring, or {@code null} if none.
+ * By default there is no syntax coloring.
+ *
+ * @return The colors for syntax coloring, or {@code null} if none.
+ */
+ public Colors getColors() {
+ return colors;
+ }
+
+ /**
+ * Sets the colors to use for syntax coloring.
+ * This property applies only when formatting text.
+ *
+ * <p>Newly created {@code WKTFormat}s have no syntax coloring. If a non-null argument like
+ * {@link Colors#CONSOLE} is given to this method, then the {@link #format(Object) format(…)}
+ * method tries to highlight most of the elements that are relevant to
+ * {@link org.apache.sis.util.Utilities#equalsIgnoreMetadata(Object, Object)}.</p>
+ *
+ * @param colors The colors for syntax coloring, or {@code null} if none.
+ */
+ public void setColors(final Colors colors) {
+ this.colors = colors;
+ if (formatter != null) {
+ formatter.colors = colors;
+ }
+ }
+
+ /**
+ * Returns the convention for parsing and formatting WKT elements.
+ * The default value is {@link Convention#WKT2}.
+ *
+ * @return The convention to use for formatting WKT elements (never {@code null}).
+ */
+ public Convention getConvention() {
+ return convention;
+ }
+
+ /**
+ * Sets the convention for parsing and formatting WKT elements.
+ *
+ * @param convention The new convention to use for parsing and formatting WKT elements.
+ */
+ public void setConvention(final Convention convention) {
+ ArgumentChecks.ensureNonNull("convention", convention);
+ this.convention = convention;
+ updateFormatter(formatter);
+ }
+
+ /**
+ * Returns the preferred authority for choosing the projection and parameter names.
+ * If no authority has been {@link #setNameAuthority(Citation) explicitly set}, then this
+ * method returns the authority associated to the {@linkplain #getConvention() convention}.
+ *
+ * @return The authority for projection and parameter names.
+ *
+ * @see Convention#getNameAuthority()
+ * @see Formatter#getName(IdentifiedObject)
+ */
+ public Citation getNameAuthority() {
+ Citation result = authority;
+ if (result == null) {
+ result = convention.getNameAuthority();
+ }
+ return result;
+ }
+
+ /**
+ * Sets the preferred authority for choosing the projection and parameter names.
+ * If non-null, the given priority will have precedence over the authority usually
+ * associated to the {@linkplain #getConvention() convention}. A {@code null} value
+ * restore the default behavior.
+ *
+ * @param authority The new authority, or {@code null} for inferring it from the convention.
+ *
+ * @see Formatter#getName(IdentifiedObject)
+ */
+ public void setNameAuthority(final Citation authority) {
+ this.authority = authority;
+ updateFormatter(formatter);
+ // No need to update the parser.
+ }
+
+ /**
+ * Updates the formatter convention and authority according the current state of this
+ * {@code WKTFormat}. The authority may be null, in which case it will be inferred from
+ * the convention when first needed.
+ */
+ private void updateFormatter(final Formatter formatter) {
+ if (formatter != null) {
+ formatter.setConvention(convention, authority);
+ }
+ }
+
+ /**
+ * Returns the current indentation to be used for formatting objects.
+ * The {@value #SINGLE_LINE} value means that the whole WKT is to be formatted on a single line.
+ *
+ * @return The current indentation.
+ */
+ public int getIndentation() {
+ return indentation;
+ }
+
+ /**
+ * Sets a new indentation to be used for formatting objects.
+ * The {@value #SINGLE_LINE} value means that the whole WKT is to be formatted on a single line.
+ *
+ * @param indentation The new indentation to use.
+ */
+ public void setIndentation(final int indentation) {
+ ArgumentChecks.ensureBetween("indentation", WKTFormat.SINGLE_LINE, Byte.MAX_VALUE, indentation);
+ this.indentation = (byte) indentation;
+ if (formatter != null) {
+ formatter.indentation = this.indentation;
+ }
+ }
+
+ /**
+ * Not yet supported.
+ *
+ * @param text The text to parse.
+ * @param position The index of the first character to parse.
+ * @return The parsed object, or {@code null} in case of failure.
+ */
+ @Override
+ public Object parseObject(final String text, final ParsePosition position) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ /**
+ * Returns the formatter, creating it if needed.
+ */
+ private Formatter getFormatter() {
+ Formatter formatter = this.formatter;
+ if (formatter == null) {
+ formatter = new Formatter(Convention.DEFAULT, symbols, colors, indentation);
+ updateFormatter(formatter);
+ this.formatter = formatter;
+ }
+ return formatter;
+ }
+
+ /**
+ * Formats the specified object as a Well Know Text. The given object shall be an instance of one of
+ * {@link FormattableObject}, {@link IdentifiedObject}, {@link MathTransform}, {@link GeneralParameterValue}
+ * or {@link Matrix}.
+ *
+ * @param object The object to format.
+ * @param toAppendTo Where the text is to be appended.
+ * @param pos An identification of a field in the formatted text.
+ * @return The given {@code toAppendTo} buffer.
+ *
+ * @see #getWarning()
+ */
+ @Override
+ public StringBuffer format(final Object object,
+ final StringBuffer toAppendTo,
+ final FieldPosition pos)
+ {
+ final Formatter formatter = getFormatter();
+ try {
+ formatter.clear();
+ formatter.buffer = toAppendTo;
+ formatter.bufferBase = toAppendTo.length();
+ if (object instanceof FormattableObject) {
+ formatter.append((FormattableObject) object);
+ } else if (object instanceof IdentifiedObject) {
+ formatter.append((IdentifiedObject) object);
+ } else if (object instanceof MathTransform) {
+ formatter.append((MathTransform) object);
+ } else if (object instanceof GeneralParameterValue) {
+ /*
+ * Special processing for parameter values, which is formatted directly in 'Formatter'.
+ * Note that this interface doesn't share the same parent interface than other interfaces.
+ */
+ formatter.append((GeneralParameterValue) object);
+ } else if (object instanceof Matrix) {
+ formatter.append((Matrix) object);
+ } else {
+ throw new ClassCastException(Errors.format(
+ Errors.Keys.IllegalArgumentClass_2, "object", object.getClass()));
+ }
+ return toAppendTo;
+ } finally {
+ formatter.buffer = null;
+ }
+ }
+
+ /**
+ * If a warning occurred during the last WKT {@linkplain #format formatting}, returns the warning.
+ * Otherwise returns {@code null}. The warning is cleared every time a new object is formatted.
+ *
+ * @return The last warning, or {@code null} if none.
+ */
+ public String getWarning() {
+ return (formatter != null) ? formatter.getErrorMessage() : null;
+ }
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -17,49 +17,43 @@
/**
* <cite>Well Known Text</cite> (WKT) parsing and formatting.
- * This package provides the internal mechanism used by SIS implementation. Most users do not need to know about it,
- * except if they want to customize the parsing process or the WKT output. For example this package allows to:
+ * This package implements the services provided by the {@link org.apache.sis.referencing.CRS#parseWKT(String)}
+ * and {@link org.opengis.referencing.IdentifiedObject#toWKT()} convenience methods, with more control.
+ * For example this package allows to:
*
* <ul>
- * <li>{@linkplain org.apache.sis.io.wkt.WKTFormat#setConvention Format the parameters using the names
- * of an other authority than OGC}. For example a user may want to format map projections using the
- * {@linkplain org.apache.sis.io.wkt.Convention#GEOTIFF GeoTIFF} parameter names.</li>
- * <li>{@linkplain org.apache.sis.io.wkt.WKTFormat#setSymbols Use curly brackets instead than square ones},
- * for example {@code DATUM("WGS84")} instead than {@code DATUM["WGS84"]}.
- * The former is legal WKT, while less frequently used than the later one.</li>
- * <li>{@linkplain org.apache.sis.io.wkt.WKTFormat#setColors Apply syntactic coloring} for output
- * on terminal supporting <cite>ANSI escape codes</cite> (a.k.a. ECMA-48, ISO/IEC 6429 and X3.64).</li>
- * <li>{@linkplain org.apache.sis.io.wkt.WKTFormat#setIndentation Use a different indentation}, or
- * format the whole WKT on a {@linkplain org.apache.sis.io.wkt.WKTFormat#SINGLE_LINE single line}.</li>
+ * <li>Format projection and parameters using the names of a chosen authority. For example the
+ * "<cite>Mercator (variant A)</cite>" projection is named {@code "Mercator_1SP"} by OGC 01-009
+ * and {@code "CT_Mercator"} by GeoTIFF.</li>
+ * <li>Format the elements with curly brackets instead than square ones.
+ * For example both {@code ID["EPSG",4326]} and {@code ID("EPSG",4326)} are legal WKT.</li>
+ * <li>Format with a different indentation or format the whole WKT on a single line.</li>
+ * <li>Apply syntactic coloring on terminal supporting <cite>ANSI escape codes</cite>
+ * (a.k.a. ECMA-48, ISO/IEC 6429 and X3.64).</li>
+ * <li>Ignore the {@code AXIS[…]} elements at parsing time. This approach can be used as a way to force
+ * the (<var>longitude</var>, <var>latitude</var>) axes order.</li>
* </ul>
*
- * Current implementation is primarily designed for parsing and formatting referencing objects.
- * However other objects (especially the one for geometric objects) are expected to be provided
- * here in future versions.
- *
* {@section Referencing WKT}
- * Parsing of {@linkplain org.apache.sis.referencing.crs.AbstractCRS Coordinate Reference System}
- * and {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform Math Transform} objects
- * are performed by the {@link org.apache.sis.io.wkt.ReferencingParser} class. The parser provides methods for:
- *
+ * Referencing WKT is defined using Extended Backus Naur Form (EBNF) in two versions:
* <ul>
- * <li>Specifying whatever the default axis names shall be ISO identifiers or the
- * legacy identifiers specified in the WKT specification.</li>
- * <li>Ignoring the {@code AXIS[...]} elements. This approach can be used as a way to force
- * the (<var>longitude</var>, <var>latitude</var>) axes order.</li>
+ * <li>ISO 19162 defines the current format, also known as “WKT 2”.</li>
+ * <li>The previous format — “WKT 1” — was defined in the <a href="http://www.opengeospatial.org/standards/ct">OGC
+ * document 01-009</a>. This definition is
+ * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">shown on GeoAPI</a>.</li>
* </ul>
*
- * {@section Geometry WKT}
- * The {@link org.apache.sis.geometry.GeneralEnvelope} and
- * {@link org.apache.sis.geometry.GeneralDirectPosition} classes provide their own, limited,
- * WKT parsing and formatting services for the {@code BOX} and {@code POINT} elements.
+ * The WKT 1 format has been interpreted differently by various implementors.
+ * One noticeable difference is the unit of measurement of prime meridians and projection parameters.
+ * The WKT 2 format aims to solve the inter-operability problem caused by such mismatches,
+ * but not all softwares support this new format. Consequently importing or exporting data from/to a software with
+ * the WKT syntax require knowledge of the WKT variant used by that software. This variant can be specified by the
+ * {@link org.apache.sis.io.wkt.Convention} enumeration.
*
- * {@section References}
- * <ul>
- * <li><a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Well Known Text specification</a></li>
- * <li><a href="http://home.gdal.org/projects/opengis/wktproblems.html">OGC WKT Coordinate System Issues</a></li>
- * <li><a href="http://en.wikipedia.org/wiki/Well-known_text">Wikipedia: Well Known Text</a></li>
- * </ul>
+ * {@section Geometry WKT}
+ * The {@link org.apache.sis.geometry.GeneralEnvelope} and {@link org.apache.sis.geometry.GeneralDirectPosition} classes
+ * provide their own, limited, WKT parsing and formatting services for the {@code BOX} and {@code POINT} elements.
+ * A description for this WKT format can be found on <a href="http://en.wikipedia.org/wiki/Well-known_text">Wikipedia</a>.
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Rémi Eve (IRD)
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -86,10 +86,10 @@ import org.apache.sis.internal.jdk7.Obje
* Applications should instead instantiate the most specific subclass having a name starting by {@code Default}.
* However exceptions to this rule may occur when it is not possible to identify the exact type.
*
- * {@example It is sometime not possible to infer the exact coordinate system from version 1 of
- * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
- * Known Text</cite></a>, for example when parsing a <code>LOCAL_CS</code> element. In such exceptional
- * situation, a plain <code>AbstractCS</code> object may be instantiated.}
+ * {@example It is sometime not possible to infer the exact coordinate system type from
+ * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">version 1 of
+ * <cite>Well Known Text format</cite></a>, for example when parsing a <code>LOCAL_CS</code> element.
+ * In such exceptional situation, a plain <code>AbstractCS</code> object may be instantiated.}
*
* {@code IdentifiedObject} instances are created in two main ways:
*
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -16,28 +16,66 @@
*/
package org.apache.sis.referencing;
+import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import org.opengis.util.FactoryException;
import org.opengis.util.NoSuchIdentifierException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.opengis.referencing.crs.SingleCRS;
import org.opengis.referencing.crs.CompoundCRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.CRSAuthorityFactory;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
+import org.opengis.referencing.crs.TemporalCRS;
+import org.opengis.referencing.crs.VerticalCRS;
+import org.opengis.metadata.extent.Extent;
+import org.opengis.metadata.extent.GeographicBoundingBox;
import org.apache.sis.internal.util.DefinitionURI;
+import org.apache.sis.internal.referencing.AxisDirections;
import org.apache.sis.internal.referencing.ReferencingUtilities;
+import org.apache.sis.referencing.cs.DefaultVerticalCS;
+import org.apache.sis.referencing.cs.DefaultEllipsoidalCS;
+import org.apache.sis.referencing.crs.DefaultGeographicCRS;
+import org.apache.sis.referencing.crs.DefaultVerticalCRS;
import org.apache.sis.referencing.crs.DefaultCompoundCRS;
+import org.apache.sis.metadata.iso.extent.Extents;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.Utilities;
import org.apache.sis.util.Static;
+import static java.util.Collections.singletonMap;
import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
/**
* Static methods working on {@linkplain CoordinateReferenceSystem Coordinate Reference Systems}.
+ * The methods defined in this class can be grouped in two categories:
+ *
+ * <ul>
+ * <li>Factory methods, the most notable one being {@link #forCode(String)}.</li>
+ * <li>Methods providing information, like {@link #isHorizontalCRS(CoordinateReferenceSystem)}.</li>
+ * </ul>
+ *
+ * {@section Note on kinds of CRS}
+ * The {@link #getSingleComponents(CoordinateReferenceSystem)} method decomposes an arbitrary CRS into a flat
+ * list of single components. In such flat list, vertical and temporal components can easily be identified by
+ * {@code instanceof} checks. But identifying the horizontal component is not as easy. The list below suggests
+ * ways to classify the components:
+ *
+ * <ul>
+ * <li><code>if (crs instanceof TemporalCRS)</code> determines if the CRS is for the temporal component.</li>
+ * <li><code>if (crs instanceof VerticalCRS)</code> determines if the CRS is for the vertical component.</li>
+ * <li><code>if (CRS.{@linkplain #isHorizontalCRS(CoordinateReferenceSystem) isHorizontalCRS}(crs))</code>
+ * determines if the CRS is for the horizontal component.</li>
+ * </ul>
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.3 (derived from geotk-2.1)
@@ -59,17 +97,23 @@ public final class CRS extends Static {
* on any installation of Apache SIS version 0.4 or above:
*
* <blockquote><table class="sis">
- * <tr><th>Code</th> <th>Enum</th> <th>CRS Type</th> <th>Description</th></tr>
- * <tr><td>CRS:27</td> <td>{@link CommonCRS#NAD27 NAD27}</td> <td>Geographic</td> <td>Like EPSG:4267 except for (<var>longitude</var>, <var>latitude</var>) axis order</td></tr>
- * <tr><td>CRS:83</td> <td>{@link CommonCRS#NAD83 NAD83}</td> <td>Geographic</td> <td>Like EPSG:4269 except for (<var>longitude</var>, <var>latitude</var>) axis order</td></tr>
- * <tr><td>CRS:84</td> <td>{@link CommonCRS#WGS84 WGS84}</td> <td>Geographic</td> <td>Like EPSG:4326 except for (<var>longitude</var>, <var>latitude</var>) axis order</td></tr>
- * <tr><td>EPSG:4047</td> <td>{@link CommonCRS#SPHERE SPHERE}</td> <td>Geographic</td> <td>GRS 1980 Authalic Sphere</td></tr>
- * <tr><td>EPSG:4230</td> <td>{@link CommonCRS#ED50 ED50}</td> <td>Geographic</td> <td>European Datum 1950</td></tr>
- * <tr><td>EPSG:4258</td> <td>{@link CommonCRS#ETRS89 ETRS89}</td> <td>Geographic</td> <td>European Terrestrial Reference Frame 1989</td></tr>
- * <tr><td>EPSG:4267</td> <td>{@link CommonCRS#NAD27 NAD27}</td> <td>Geographic</td> <td>North American Datum 1927</td></tr>
- * <tr><td>EPSG:4269</td> <td>{@link CommonCRS#NAD83 NAD83}</td> <td>Geographic</td> <td>North American Datum 1983</td></tr>
- * <tr><td>EPSG:4322</td> <td>{@link CommonCRS#WGS72 WGS72}</td> <td>Geographic</td> <td>World Geodetic System 1972</td></tr>
- * <tr><td>EPSG:4326</td> <td>{@link CommonCRS#WGS84 WGS84}</td> <td>Geographic</td> <td>World Geodetic System 1984</td></tr>
+ * <tr><th>Code</th> <th>Enum</th> <th>CRS Type</th> <th>Description</th></tr>
+ * <tr><td>CRS:27</td> <td>{@link CommonCRS#NAD27 NAD27}</td> <td>Geographic</td> <td>Like EPSG:4267 except for (<var>longitude</var>, <var>latitude</var>) axis order</td></tr>
+ * <tr><td>CRS:83</td> <td>{@link CommonCRS#NAD83 NAD83}</td> <td>Geographic</td> <td>Like EPSG:4269 except for (<var>longitude</var>, <var>latitude</var>) axis order</td></tr>
+ * <tr><td>CRS:84</td> <td>{@link CommonCRS#WGS84 WGS84}</td> <td>Geographic</td> <td>Like EPSG:4326 except for (<var>longitude</var>, <var>latitude</var>) axis order</td></tr>
+ * <tr><td>EPSG:4047</td> <td>{@link CommonCRS#SPHERE SPHERE}</td> <td>Geographic</td> <td>GRS 1980 Authalic Sphere</td></tr>
+ * <tr><td>EPSG:4230</td> <td>{@link CommonCRS#ED50 ED50}</td> <td>Geographic</td> <td>European Datum 1950</td></tr>
+ * <tr><td>EPSG:4258</td> <td>{@link CommonCRS#ETRS89 ETRS89}</td> <td>Geographic</td> <td>European Terrestrial Reference Frame 1989</td></tr>
+ * <tr><td>EPSG:4267</td> <td>{@link CommonCRS#NAD27 NAD27}</td> <td>Geographic</td> <td>North American Datum 1927</td></tr>
+ * <tr><td>EPSG:4269</td> <td>{@link CommonCRS#NAD83 NAD83}</td> <td>Geographic</td> <td>North American Datum 1983</td></tr>
+ * <tr><td>EPSG:4322</td> <td>{@link CommonCRS#WGS72 WGS72}</td> <td>Geographic</td> <td>World Geodetic System 1972</td></tr>
+ * <tr><td>EPSG:4326</td> <td>{@link CommonCRS#WGS84 WGS84}</td> <td>Geographic</td> <td>World Geodetic System 1984</td></tr>
+ * <tr><td>EPSG:4936</td> <td>{@link CommonCRS#ETRS89 ETRS89}</td> <td>Geocentric</td> <td>European Terrestrial Reference Frame 1989</td></tr>
+ * <tr><td>EPSG:4937</td> <td>{@link CommonCRS#ETRS89 ETRS89}</td> <td>Geographic 3D</td> <td>European Terrestrial Reference Frame 1989</td></tr>
+ * <tr><td>EPSG:4978</td> <td>{@link CommonCRS#WGS84 WGS84}</td> <td>Geocentric</td> <td>World Geodetic System 1984</td></tr>
+ * <tr><td>EPSG:4979</td> <td>{@link CommonCRS#WGS84 WGS84}</td> <td>Geographic 3D</td> <td>World Geodetic System 1984</td></tr>
+ * <tr><td>EPSG:4984</td> <td>{@link CommonCRS#WGS72 WGS72}</td> <td>Geocentric</td> <td>World Geodetic System 1972</td></tr>
+ * <tr><td>EPSG:4985</td> <td>{@link CommonCRS#WGS72 WGS72}</td> <td>Geographic 3D</td> <td>World Geodetic System 1972</td></tr>
* <tr><td>EPSG:5715</td> <td>{@link CommonCRS.Vertical#DEPTH DEPTH}</td> <td>Vertical</td> <td>Mean Sea Level depth</td></tr>
* <tr><td>EPSG:5714</td> <td>{@link CommonCRS.Vertical#MEAN_SEA_LEVEL MEAN_SEA_LEVEL}</td> <td>Vertical</td> <td>Mean Sea Level height</td></tr>
* </table></blockquote>
@@ -85,6 +129,8 @@ public final class CRS extends Static {
* @return The Coordinate Reference System for the given authority code.
* @throws NoSuchAuthorityCodeException If there is no known CRS associated to the given code.
* @throws FactoryException if the CRS creation failed for an other reason.
+ *
+ * @category factory
*/
public static CoordinateReferenceSystem forCode(final String code)
throws NoSuchAuthorityCodeException, FactoryException
@@ -122,14 +168,16 @@ public final class CRS extends Static {
}
} else if (authority.equalsIgnoreCase("EPSG")) {
final int n = Integer.parseInt(value);
- for (final CommonCRS candidate : CommonCRS.values()) {
- if (candidate.geographic == n) {
- return candidate.geographic();
+ if (n != 0) { // CommonCRS uses 0 as a sentinel value for "no EPSG code".
+ for (final CommonCRS candidate : CommonCRS.values()) {
+ if (candidate.geographic == n) return candidate.geographic();
+ if (candidate.geocentric == n) return candidate.geocentric();
+ if (candidate.geo3D == n) return candidate.geographic3D();
}
- }
- for (final CommonCRS.Vertical candidate : CommonCRS.Vertical.values()) {
- if (candidate.isEPSG && candidate.crs == n) {
- return candidate.crs();
+ for (final CommonCRS.Vertical candidate : CommonCRS.Vertical.values()) {
+ if (candidate.isEPSG && candidate.crs == n) {
+ return candidate.crs();
+ }
}
}
} else {
@@ -146,6 +194,194 @@ public final class CRS extends Static {
}
/**
+ * Returns the valid geographic area for the given coordinate reference system, or {@code null} if unknown.
+ * This method explores the {@linkplain CoordinateReferenceSystem#getDomainOfValidity() domain of validity}
+ * associated with the given CRS. If more than one geographic bounding box is found, then they will be
+ * {@linkplain org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox#add(GeographicBoundingBox)
+ * added} together.
+ *
+ * @param crs The coordinate reference system, or {@code null}.
+ * @return The geographic area, or {@code null} if none.
+ *
+ * @see #getEnvelope(CoordinateReferenceSystem)
+ * @see Extents#getGeographicBoundingBox(Extent)
+ *
+ * @category information
+ */
+ public static GeographicBoundingBox getGeographicBoundingBox(final CoordinateReferenceSystem crs) {
+ return (crs != null) ? Extents.getGeographicBoundingBox(crs.getDomainOfValidity()) : null;
+ }
+
+ /**
+ * Returns {@code true} if the given CRS is horizontal. The current implementation considers a
+ * CRS as horizontal if it is two-dimensional and comply with one of the following conditions:
+ *
+ * <ul>
+ * <li>It is an instance of {@link GeographicCRS}.</li>
+ * <li>It is an instance of {@link ProjectedCRS}.</li>
+ * </ul>
+ *
+ * In case of doubt, this method conservatively returns {@code false}.
+ *
+ * @todo Future SIS implementation may extend the above condition list. For example a radar station could
+ * use a polar coordinate system in a <code>DerivedCRS</code> instance based on a projected CRS.
+ * See <a href="http://issues.apache.org/jira/browse/SIS-161">SIS-161</a>.
+ *
+ * @param crs The coordinate reference system, or {@code null}.
+ * @return {@code true} if the given CRS is non-null and comply with one of the above conditions,
+ * or {@code false} otherwise.
+ *
+ * @see #getHorizontalComponent(CoordinateReferenceSystem)
+ *
+ * @category information
+ */
+ public static boolean isHorizontalCRS(final CoordinateReferenceSystem crs) {
+ if (crs instanceof GeographicCRS || crs instanceof ProjectedCRS) {
+ return crs.getCoordinateSystem().getDimension() == 2;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the first horizontal coordinate reference system found in the given CRS, or {@code null} if there is
+ * none. If the given CRS is already horizontal according {@link #isHorizontalCRS(CoordinateReferenceSystem)},
+ * then this method returns it as-is. Otherwise if the given CRS is compound, then this method searches for the
+ * first horizontal component in the order of the {@linkplain #getSingleComponents(CoordinateReferenceSystem)
+ * single components list}.
+ *
+ * <p>In the special case where a three-dimensional geographic CRS is found, this method will create a
+ * two-dimensional geographic CRS without the vertical axis.</p>
+ *
+ * @param crs The coordinate reference system, or {@code null}.
+ * @return The first horizontal CRS, or {@code null} if none.
+ *
+ * @category information
+ */
+ public static SingleCRS getHorizontalComponent(final CoordinateReferenceSystem crs) {
+ if (isHorizontalCRS(crs)) {
+ return (SingleCRS) crs;
+ }
+ if (crs instanceof GeographicCRS) {
+ EllipsoidalCS cs = ((GeographicCRS) crs).getCoordinateSystem();
+ final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
+ if (i >= 0) {
+ final CoordinateSystemAxis xAxis = cs.getAxis(i > 0 ? 0 : 1);
+ final CoordinateSystemAxis yAxis = cs.getAxis(i > 1 ? 1 : 2);
+ cs = CommonCRS.DEFAULT.geographic().getCoordinateSystem();
+ if (!Utilities.equalsIgnoreMetadata(cs.getAxis(0), xAxis) ||
+ !Utilities.equalsIgnoreMetadata(cs.getAxis(1), yAxis))
+ {
+ // We can not reuse the name of the existing CS, because it typically
+ // contains text about axes including the axis that we just dropped.
+ cs = new DefaultEllipsoidalCS(singletonMap(EllipsoidalCS.NAME_KEY, "Ellipsoidal 2D"), xAxis, yAxis);
+ }
+ return new DefaultGeographicCRS(IdentifiedObjects.getProperties(crs), ((GeographicCRS) crs).getDatum(), cs);
+ }
+ }
+ if (crs instanceof CompoundCRS) {
+ final CompoundCRS cp = (CompoundCRS) crs;
+ for (final CoordinateReferenceSystem c : cp.getComponents()) {
+ final SingleCRS candidate = getHorizontalComponent(c);
+ if (candidate != null) {
+ return candidate;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the first vertical coordinate reference system found in the given CRS, or {@code null} if there is none.
+ * If the given CRS is already an instance of {@code VerticalCRS}, then this method returns it as-is.
+ * Otherwise if the given CRS is compound, then this method searches for the first vertical component
+ * in the order of the {@linkplain #getSingleComponents(CoordinateReferenceSystem) single components list}.
+ *
+ * {@section Height in a three-dimensional geographic CRS}
+ * In ISO 19111 model, ellipsoidal heights are indissociable from geographic CRS because such heights
+ * without their (<var>latitude</var>, <var>longitude</var>) locations make little sense. Consequently
+ * a standard-conformant library should return {@code null} when asked for the {@code VerticalCRS}
+ * component of a geographic CRS. This is what {@code getVerticalComponent(…)} does when the
+ * {@code allowCreateEllipsoidal} argument is {@code false}.
+ *
+ * <p>However in some exceptional cases, handling ellipsoidal heights like any other kind of heights
+ * may simplify the task. For example when computing <em>difference</em> between heights above the
+ * same datum, the impact of ignoring locations may be smaller (but not necessarily canceled).
+ * Orphan {@code VerticalCRS} may also be useful for information purpose like labeling a plot axis.
+ * If the caller feels confident that ellipsoidal heights are safe for his task, he can set the
+ * {@code allowCreateEllipsoidal} argument to {@code true}. In such case, this {@code getVerticalComponent(…)}
+ * method will create a temporary {@code VerticalCRS} from the first three-dimensional {@code GeographicCRS}
+ * <em>in last resort</em>, only if it can not find an existing {@code VerticalCRS} instance.
+ * <strong>Note that this is not a valid CRS according ISO 19111</strong> — use with care.</p>
+ *
+ * @param crs The coordinate reference system, or {@code null}.
+ * @param allowCreateEllipsoidal {@code true} for allowing the creation of orphan CRS for ellipsoidal heights.
+ * The recommended value is {@code false}.
+ * @return The first vertical CRS, or {@code null} if none.
+ *
+ * @category information
+ */
+ public static VerticalCRS getVerticalComponent(final CoordinateReferenceSystem crs,
+ final boolean allowCreateEllipsoidal)
+ {
+ if (crs instanceof VerticalCRS) {
+ return (VerticalCRS) crs;
+ }
+ if (crs instanceof CompoundCRS) {
+ final CompoundCRS cp = (CompoundCRS) crs;
+ boolean a = false;
+ do { // Executed at most twice.
+ for (final CoordinateReferenceSystem c : cp.getComponents()) {
+ final VerticalCRS candidate = getVerticalComponent(c, a);
+ if (candidate != null) {
+ return candidate;
+ }
+ }
+ } while ((a = !a) == allowCreateEllipsoidal);
+ }
+ if (allowCreateEllipsoidal && crs instanceof GeographicCRS) {
+ final CoordinateSystem cs = crs.getCoordinateSystem();
+ final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
+ if (i >= 0) {
+ final CoordinateSystemAxis axis = cs.getAxis(i);
+ VerticalCRS c = CommonCRS.Vertical.ELLIPSOIDAL.crs();
+ if (!c.getCoordinateSystem().getAxis(0).equals(axis)) {
+ final Map<String,?> properties = IdentifiedObjects.getProperties(c);
+ c = new DefaultVerticalCRS(properties, c.getDatum(), new DefaultVerticalCS(properties, axis));
+ }
+ return c;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the first temporal coordinate reference system found in the given CRS, or {@code null} if there is none.
+ * If the given CRS is already an instance of {@code TemporalCRS}, then this method returns it as-is.
+ * Otherwise if the given CRS is compound, then this method searches for the first temporal component
+ * in the order of the {@linkplain #getSingleComponents(CoordinateReferenceSystem) single components list}.
+ *
+ * @param crs The coordinate reference system, or {@code null}.
+ * @return The first temporal CRS, or {@code null} if none.
+ *
+ * @category information
+ */
+ public static TemporalCRS getTemporalComponent(final CoordinateReferenceSystem crs) {
+ if (crs instanceof TemporalCRS) {
+ return (TemporalCRS) crs;
+ }
+ if (crs instanceof CompoundCRS) {
+ final CompoundCRS cp = (CompoundCRS) crs;
+ for (final CoordinateReferenceSystem c : cp.getComponents()) {
+ final TemporalCRS candidate = getTemporalComponent(c);
+ if (candidate != null) {
+ return candidate;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the ordered list of single coordinate reference systems for the specified CRS.
* This method performs the following choices:
*
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -124,7 +124,7 @@ public enum CommonCRS {
* <tr><th>Ellipsoid axes unit:</th> <td>{@link SI#METRE}</td></tr>
* </table></blockquote>
*/
- WGS84((short) 4326, (short) 0, (short) 4978, (short) 6326, (short) 7030),
+ WGS84((short) 4326, (short) 4979, (short) 4978, (short) 6326, (short) 7030),
/**
* World Geodetic System 1972.
@@ -140,7 +140,7 @@ public enum CommonCRS {
* <tr><th>Ellipsoid axes unit:</th> <td>{@link SI#METRE}</td></tr>
* </table></blockquote>
*/
- WGS72((short) 4322, (short) 0, (short) 4984, (short) 6322, (short) 7043),
+ WGS72((short) 4322, (short) 4985, (short) 4984, (short) 6322, (short) 7043),
/**
* European Terrestrial Reference System 1989.
@@ -162,7 +162,7 @@ public enum CommonCRS {
* The <cite>Web Map Server</cite> <code>"CRS:83"</code> authority code uses the NAD83 datum,
* while the <code>"IGNF:MILLER"</code> authority code uses the GRS80 datum.}
*/
- ETRS89((short) 4258, (short) 0, (short) 4936, (short) 6258, (short) 7019),
+ ETRS89((short) 4258, (short) 4937, (short) 4936, (short) 6258, (short) 7019),
/**
* North American Datum 1983.
@@ -238,6 +238,13 @@ public enum CommonCRS {
SPHERE((short) 4047, (short) 0, (short) 0, (short) 6047, (short) 7048);
/**
+ * The enum for the default CRS.
+ *
+ * @see #defaultGeographic()
+ */
+ static final CommonCRS DEFAULT = WGS84;
+
+ /**
* The EPSG code of the two-dimensional geographic CRS.
*/
final short geographic;
@@ -358,7 +365,7 @@ public enum CommonCRS {
* @return The default two-dimensional geographic CRS with (<var>longitude</var>, <var>latitude</var>) axis order.
*/
public static GeographicCRS defaultGeographic() {
- return WGS84.normalizedGeographic();
+ return DEFAULT.normalizedGeographic();
}
/**
@@ -438,14 +445,14 @@ public enum CommonCRS {
}
/*
* All constants defined in this enumeration use the same coordinate system, EPSG:6422.
- * We will arbitrarily create this CS only for WGS84 (the most frequently created CRS),
+ * We will arbitrarily create this CS only for the most frequently created CRS,
* and share that CS instance for all other constants.
*/
final EllipsoidalCS cs;
- if (this == WGS84) {
+ if (this == DEFAULT) {
cs = (EllipsoidalCS) StandardDefinitions.createCoordinateSystem((short) 6422);
} else {
- cs = WGS84.geographic().getCoordinateSystem();
+ cs = DEFAULT.geographic().getCoordinateSystem();
}
object = StandardDefinitions.createGeographicCRS(geographic, datum(), cs);
cached = object;
@@ -494,14 +501,14 @@ public enum CommonCRS {
}
/*
* All constants defined in this enumeration use the same coordinate system, EPSG:6423.
- * We will arbitrarily create this CS only for WGS84 (the most frequently created CRS),
+ * We will arbitrarily create this CS only for the most frequently created CRS,
* and share that CS instance for all other constants.
*/
final EllipsoidalCS cs;
- if (this == WGS84) {
+ if (this == DEFAULT) {
cs = (EllipsoidalCS) StandardDefinitions.createCoordinateSystem((short) 6423);
} else {
- cs = WGS84.geographic3D().getCoordinateSystem();
+ cs = DEFAULT.geographic3D().getCoordinateSystem();
}
// Use same name and datum than the geographic CRS.
final GeographicCRS base = geographic();
@@ -551,14 +558,14 @@ public enum CommonCRS {
}
/*
* All constants defined in this enumeration use the same coordinate system, EPSG:6500.
- * We will arbitrarily create this CS only for WGS84 (the most frequently created CRS),
+ * We will arbitrarily create this CS only for the most frequently created CRS,
* and share that CS instance for all other constants.
*/
final CartesianCS cs;
- if (this == WGS84) {
+ if (this == DEFAULT) {
cs = (CartesianCS) StandardDefinitions.createCoordinateSystem((short) 6500);
} else {
- cs = (CartesianCS) WGS84.geocentric().getCoordinateSystem();
+ cs = (CartesianCS) DEFAULT.geocentric().getCoordinateSystem();
}
// Use same name and datum than the geographic CRS.
final GeographicCRS base = geographic();
@@ -675,8 +682,8 @@ public enum CommonCRS {
synchronized (this) {
object = primeMeridian(cached);
if (object == null) {
- if (this != WGS84) {
- object = WGS84.primeMeridian(); // Share the same instance for all constants.
+ if (this != DEFAULT) {
+ object = DEFAULT.primeMeridian(); // Share the same instance for all constants.
} else {
final DatumAuthorityFactory factory = datumFactory();
if (factory != null) try {
@@ -822,12 +829,11 @@ public enum CommonCRS {
* Height measured along the normal to the ellipsoid used in the definition of horizontal datum.
* The unit of measurement is metres.
*
- * <p><b>This datum is not part of ISO 19111 international standard.</b>
- * Usage of this datum is generally not recommended since ellipsoidal heights make little sense without
+ * <p><b>Ellipsoidal height is not part of ISO 19111 international standard.</b>
+ * Such vertical CRS is usually not recommended since ellipsoidal heights make little sense without
* their (<var>latitude</var>, <var>longitude</var>) locations. The ISO specification defines instead
- * three-dimensional {@code GeographicCRS} for that reason. However Apache SIS provides this value
- * because it is sometime useful to temporarily express ellipsoidal heights independently from other
- * ordinate values.</p>
+ * three-dimensional {@code GeographicCRS} for that reason. Users are encouraged to avoid this orphan
+ * ellipsoidal height as much as possible.</p>
*/
ELLIPSOIDAL(false, Vocabulary.Keys.EllipsoidalHeight, Vocabulary.Keys.Ellipsoid),
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -101,7 +101,7 @@ public class AbstractCRS extends Abstrac
private CoordinateSystem coordinateSystem;
/**
- * Other coordinate systems derived from this coordinate systems for other axes conventions.
+ * Other coordinate reference systems derived from this CRS.
* Created only when first needed.
*
* @see #forConvention(AxesConvention)
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -25,6 +25,7 @@ import org.opengis.referencing.cs.Coordi
import org.opengis.referencing.crs.GeocentricCRS;
import org.opengis.referencing.datum.GeodeticDatum;
import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.internal.referencing.Legacy;
import org.apache.sis.referencing.cs.AxesConvention;
import org.apache.sis.referencing.AbstractReferenceSystem;
@@ -222,9 +223,13 @@ public class DefaultGeocentricCRS extend
formatter.append(datum);
formatter.append(datum.getPrimeMeridian());
formatter.append(unit);
- final CoordinateSystem cs = formatter.getConvention().toConformCS(getCoordinateSystem());
- if (!(cs instanceof CartesianCS)) {
- formatter.setInvalidWKT(cs);
+ CoordinateSystem cs = getCoordinateSystem();
+ if (formatter.getConvention().isWKT1()) {
+ if (cs instanceof CartesianCS) {
+ cs = Legacy.forGeocentricCRS((CartesianCS) cs, true);
+ } else {
+ formatter.setInvalidWKT(cs);
+ }
}
final int dimension = cs.getDimension();
for (int i=0; i<dimension; i++) {
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -49,8 +49,9 @@ import org.opengis.referencing.cs.Coordi
* {@link #RIGHT_HANDED} or {@link #NORMALIZED} enumeration value.</p>
*
* {@section Normalized coordinate systems}
- * The definition of <cite>normalized coordinate systems</cite> is somewhat fuzzy.
- * This concept appears in the Web Map Services (WMS) 1.3 specification, quoted here:
+ * <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:
*
* <blockquote><font size="-1"><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
@@ -59,18 +60,9 @@ import org.opengis.referencing.cs.Coordi
* 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.</font></blockquote>
*
- * In addition to WMS, this method is used together with
- * {@link org.apache.sis.referencing.cs.CoordinateSystems#swapAndScaleAxes CoordinateSystems.swapAndScaleAxes(…)}
- * for the creation of transformation steps, as in the example below:
- *
- * {@preformat java
- * Matrix step1 = swapAndScaleAxes(sourceCS, sourceCS.forConvention(NORMALIZED));
- * Matrix step2 = ... some coordinate operation working on normalized axes ...
- * Matrix step3 = swapAndScaleAxes(targetCS.forConvention(NORMALIZED), targetCS);
- * }
- *
- * A rational for normalized axes order and units is explained in the <cite>Axis units and directions</cite>
- * section of {@linkplain org.apache.sis.referencing.operation.projection map projection package description}.
+ * 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}.
*
* {@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
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -206,12 +206,12 @@ public final class CoordinateSystems ext
/**
* Returns an affine transform between two coordinate systems.
- * The two coordinate systems must implement the same GeoAPI coordinate system interface
- * (for example both of them shall implement {@link org.opengis.referencing.cs.CartesianCS},
- * or both of them shall implement {@link org.opengis.referencing.cs.EllipsoidalCS}).
+ * The two coordinate systems must implement the same GeoAPI coordinate system interface.
+ * For example if {@code sourceCRS} is a {@link org.opengis.referencing.cs.CartesianCS},
+ * then {@code targetCRS} must be a {@code CartesianCS} too.
* Only units and axes order (e.g. transforming from
- * ({@linkplain AxisDirection#NORTH NORTH},{@linkplain AxisDirection#WEST WEST}) to
- * ({@linkplain AxisDirection#EAST EAST},{@linkplain AxisDirection#NORTH NORTH})
+ * ({@linkplain AxisDirection#NORTH North}, {@linkplain AxisDirection#WEST West}) to
+ * ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North})
* are taken in account by this method.
*
* <blockquote><font size="-1"><b>Example:</b>
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -82,8 +82,8 @@ public final strictfp class GeneralDirec
} catch (IllegalArgumentException e) {
// This is the expected exception.
final String message = e.getMessage();
- assertTrue(message.contains("POINT(6 10 2"));
- assertTrue(message.contains("‘)’"));
+ assertTrue(message, message.contains("POINT(6 10 2"));
+ assertTrue(message, message.contains("‘)’"));
}
try {
new GeneralDirectPosition("POINT 6 10 2)");
@@ -97,8 +97,9 @@ public final strictfp class GeneralDirec
} catch (IllegalArgumentException e) {
// This is the expected exception.
final String message = e.getMessage();
- assertTrue(message.contains("POINT(6 10 2) x"));
- assertTrue(message.contains("“x”"));
+ assertTrue(message, message.contains("POINT(6 10 2) x"));
+ assertTrue(message, message.contains("“x”") || // English locale
+ message.contains("« x »")); // French locale
}
}
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -426,17 +426,95 @@ public strictfp class GeneralEnvelopeTes
}
/**
+ * Tests {@link GeneralEnvelope#setEnvelope(double...)} with valid ranges,
+ * then with a range which is known to be invalid.
+ */
+ @Test
+ public void testSetEnvelope() {
+ final GeneralEnvelope e = create(2, -4, 3, -3);
+ e.setEnvelope(3, -5, -8, 2);
+ try {
+ e.setEnvelope(1, -10, 2, -20);
+ fail("Invalid range shall not be allowed.");
+ } catch (IllegalArgumentException ex) {
+ // This is the expected exception.
+ final String message = ex.getMessage();
+ assertTrue(message, message.contains("Geodetic latitude"));
+ }
+ // Verify that the envelope still have the old values.
+ assertEnvelopeEquals(e, 3, -5, -8, 2);
+ verifyInvariants(e);
+ }
+
+ /**
+ * Tests {@link GeneralEnvelope#setRange(int, double, double)} with a valid range,
+ * then with a range which is known to be invalid.
+ */
+ @Test
+ public void testSetRange() {
+ final GeneralEnvelope e = create(2, -4, 3, -3);
+ e.setRange(1, -5, 2);
+ try {
+ e.setRange(1, -10, -20);
+ fail("Invalid range shall not be allowed.");
+ } catch (IllegalArgumentException ex) {
+ // This is the expected exception.
+ final String message = ex.getMessage();
+ assertTrue(message, message.contains("Geodetic latitude"));
+ }
+ // Verify that the envelope still have the old values.
+ assertEnvelopeEquals(e, 2, -5, 3, 2);
+ verifyInvariants(e);
+ }
+
+ /**
+ * Tests {@link GeneralEnvelope#setCoordinateReferenceSystem(CoordinateReferenceSystem)}.
+ */
+ @Test
+ @DependsOnMethod("testSetRange")
+ public void testSetCoordinateReferenceSystem() {
+ final GeneralEnvelope e = create(2, -4, 3, -3);
+ e.setCoordinateReferenceSystem(null);
+ /*
+ * Set an invalid latitude range, but the Envelope can not known that fact without CRS.
+ * Only when we will specify the CRS, the envelope will realize that it contains an
+ * invalid range.
+ */
+ e.setRange(1, -10, -20);
+ try {
+ e.setCoordinateReferenceSystem(WGS84);
+ fail("Invalid range shall not be allowed.");
+ } catch (IllegalStateException ex) {
+ // This is the expected exception.
+ final String message = ex.getMessage();
+ assertTrue(message, message.contains("Geodetic latitude"));
+ }
+ /*
+ * Verify that the envelope values are unchanged.
+ * Then fix the range and try again to set the CRS.
+ */
+ assertEquals( 2, e.getLower(0), STRICT);
+ assertEquals(-10, e.getLower(1), STRICT);
+ assertEquals( 3, e.getUpper(0), STRICT);
+ assertEquals(-20, e.getUpper(1), STRICT);
+ e.setRange(1, -20, -10);
+ e.setCoordinateReferenceSystem(WGS84);
+ assertEnvelopeEquals(e, 2, -20, 3, -10);
+ verifyInvariants(e);
+ }
+
+ /**
* Tests modifying the corner of an envelope.
*/
@Test
public void testCornerModifications() {
- final GeneralEnvelope e = create(2, -2, 3, -3);
+ final GeneralEnvelope e = create(2, -4, 3, -3);
e.getLowerCorner().setOrdinate(0, 1);
e.getUpperCorner().setOrdinate(1, -1);
- assertEquals( 1.0, e.getLower(0), 0.0);
- assertEquals(-2.0, e.getLower(1), 0.0);
- assertEquals( 3.0, e.getUpper(0), 0.0);
- assertEquals(-1.0, e.getUpper(1), 0.0);
+ assertEquals( 1, e.getLower(0), STRICT);
+ assertEquals(-4, e.getLower(1), STRICT);
+ assertEquals( 3, e.getUpper(0), STRICT);
+ assertEquals(-1, e.getUpper(1), STRICT);
verifyInvariants(e);
}
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -312,11 +312,11 @@ public final strictfp class AxisDirectio
}
/**
- * Tests {@link AxisDirections#indexOf(CoordinateSystem, AxisDirection)}.
+ * Tests {@link AxisDirections#indexOfColinear(CoordinateSystem, AxisDirection)}.
*/
@Test
- public void testIndexOf() {
- assertEquals(1, AxisDirections.indexOf(HardCodedCS.GEODETIC_3D, AxisDirection.NORTH));
- assertEquals(1, AxisDirections.indexOf(HardCodedCS.GEODETIC_3D, AxisDirection.SOUTH));
+ public void testIndexOfColinear() {
+ assertEquals(1, AxisDirections.indexOfColinear(HardCodedCS.GEODETIC_3D, AxisDirection.NORTH));
+ assertEquals(1, AxisDirections.indexOfColinear(HardCodedCS.GEODETIC_3D, AxisDirection.SOUTH));
}
}
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/ConventionTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/ConventionTest.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/ConventionTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/ConventionTest.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -16,8 +16,9 @@
*/
package org.apache.sis.io.wkt;
-import org.opengis.metadata.citation.Citation;
-import org.apache.sis.metadata.iso.citation.Citations;
+import javax.measure.unit.NonSI;
+import javax.measure.quantity.Angle;
+import javax.measure.quantity.Duration;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -34,43 +35,13 @@ import static org.junit.Assert.*;
*/
public final strictfp class ConventionTest extends TestCase {
/**
- * Tests all citations associated with enum values.
+ * Tests {@link Convention#getForcedUnit(Class)}.
*/
@Test
- public void testGetCitation() {
- for (final Convention convention : Convention.values()) {
- final Citation citation = convention.getAuthority();
- if (convention != Convention.PROJ4 && convention != Convention.INTERNAL) {
- assertTrue(convention.name(), convention.name().equalsIgnoreCase(Citations.getIdentifier(citation)));
- }
- }
- }
-
- /**
- * Tests {@link Convention#forCitation(Citation, Convention)}.
- */
- @Test
- public void testForCitation() {
- assertSame(Convention.OGC, Convention.forCitation(Citations.OGC, null));
- assertSame(Convention.EPSG, Convention.forCitation(Citations.EPSG, null));
- assertSame(Convention.ESRI, Convention.forCitation(Citations.ESRI, null));
- assertSame(Convention.ORACLE, Convention.forCitation(Citations.ORACLE, null));
- assertSame(Convention.NETCDF, Convention.forCitation(Citations.NETCDF, null));
- assertSame(Convention.GEOTIFF, Convention.forCitation(Citations.GEOTIFF, null));
- assertSame(Convention.PROJ4, Convention.forCitation(Citations.PROJ4, null));
- }
-
- /**
- * Tests {@link Convention#forIdentifier(String, Convention)}.
- */
- @Test
- public void testForIdentifier() {
- assertSame(Convention.OGC, Convention.forIdentifier("OGC", null));
- assertSame(Convention.EPSG, Convention.forIdentifier("EPSG", null));
- assertSame(Convention.ESRI, Convention.forIdentifier("ESRI", null));
- assertSame(Convention.ORACLE, Convention.forIdentifier("ORACLE", null));
- assertSame(Convention.NETCDF, Convention.forIdentifier("NETCDF", null));
- assertSame(Convention.GEOTIFF, Convention.forIdentifier("GEOTIFF", null));
- assertSame(Convention.PROJ4, Convention.forIdentifier("PROJ4", null));
+ public void testGetForcedUnit() {
+ assertNull(Convention.WKT2.getForcedUnit(Angle.class));
+ assertNull(Convention.WKT1.getForcedUnit(Angle.class));
+ assertEquals(NonSI.DEGREE_ANGLE, Convention.WKT1_COMMON_UNITS.getForcedUnit(Angle.class));
+ assertNull(Convention.WKT1_COMMON_UNITS.getForcedUnit(Duration.class));
}
}
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/FormatterTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/FormatterTest.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/FormatterTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/FormatterTest.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -50,16 +50,16 @@ public final strictfp class FormatterTes
*/
@Test
public void testAppendMatrix() {
- final Formatter formatter = new Formatter();
- formatter.append(new Matrix4(1, 0, 4, 0,
- -2, 1, 0, 0,
- 0, 0, 1, 7,
- 0, 0, 0, 1));
+ final Matrix m = new Matrix4(
+ 1, 0, 4, 0,
+ -2, 1, 0, 0,
+ 0, 0, 1, 7,
+ 0, 0, 0, 1);
assertWktEquals(
"PARAMETER[“num_row”, 4],\n" +
"PARAMETER[“num_col”, 4],\n" +
"PARAMETER[“elt_0_2”, 4.0],\n" +
"PARAMETER[“elt_1_0”, -2.0],\n" +
- "PARAMETER[“elt_2_3”, 7.0]", formatter.toString());
+ "PARAMETER[“elt_2_3”, 7.0]", m);
}
}
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/SymbolsTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/SymbolsTest.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/SymbolsTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/SymbolsTest.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -17,6 +17,7 @@
package org.apache.sis.io.wkt;
import org.apache.sis.test.TestCase;
+import org.apache.sis.util.StringBuilders;
import org.junit.Test;
import static org.junit.Assert.*;
@@ -36,13 +37,26 @@ public final strictfp class SymbolsTest
*/
@Test
public void testContainsAxis() {
- final Symbols s = Symbols.DEFAULT;
- assertTrue("At beginning of a line.", s.containsAxis( "AXIS[\"Long\", EAST]"));
- assertTrue("Embeded in GEOGCS.", s.containsAxis("GEOGCS[\"WGS84\", AXIS[\"Long\", EAST]]"));
- assertTrue("Using different brackets.", s.containsAxis("GEOGCS[\"WGS84\", AXIS (\"Long\", EAST)]"));
- assertTrue("Mixed cases.", s.containsAxis("GEOGCS[\"WGS84\", aXis[\"Long\", EAST]]"));
- assertFalse("AXIS in quoted text.", s.containsAxis("GEOGCS[\"AXIS\"]"));
- assertFalse("Without opening bracket.", s.containsAxis("GEOGCS[\"WGS84\", AXIS]"));
- assertFalse("No AXIS.", s.containsAxis("GEOGCS[\"WGS84\"]"));
+ assertContainsAxis("At beginning of a line.", true, "AXIS[“Long”, EAST]");
+ assertContainsAxis("Embeded in GEOGCS.", true, "GEOGCS[“WGS84”, AXIS[“Long”, EAST]]");
+ assertContainsAxis("Using different brackets.", true, "GEOGCS[“WGS84”, AXIS (“Long”, EAST)]");
+ assertContainsAxis("Mixed cases.", true, "GEOGCS[“WGS84”, aXis[“Long”, EAST]]");
+ assertContainsAxis("AXIS in quoted text.", false, "GEOGCS[“AXIS”]");
+ assertContainsAxis("Without opening bracket.", false, "GEOGCS[“WGS84”, AXIS]");
+ assertContainsAxis("No AXIS.", false, "GEOGCS[“WGS84”]");
+ }
+
+ /**
+ * Asserts that the call to {@link Symbols#containsAxis(CharSequence)} produce the given result.
+ * This method expects an array using the {@code “…”} quotation marks, which will be replaced by
+ * the standard {@code '"'} quotation mark after we tested the given string.
+ */
+ private static void assertContainsAxis(final String message, final boolean expected, final String wkt) {
+ assertEquals(message, expected, Symbols.DEFAULT.containsAxis(wkt));
+ final StringBuilder buffer = new StringBuilder(wkt);
+ StringBuilders.replace(buffer, '“', '"');
+ StringBuilders.replace(buffer, '”', '"');
+ assertFalse(wkt.contentEquals(buffer));
+ assertEquals(message, expected, Symbols.DEFAULT.containsAxis(buffer));
}
}
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/Assert.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/Assert.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/Assert.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/Assert.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -30,6 +30,8 @@ import org.opengis.referencing.operation
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.opengis.referencing.cs.RangeMeaning;
+import org.apache.sis.io.wkt.Symbols;
+import org.apache.sis.io.wkt.WKTFormat;
import org.apache.sis.geometry.AbstractEnvelope;
import org.apache.sis.geometry.GeneralDirectPosition;
@@ -52,6 +54,18 @@ public strictfp class Assert extends org
private static final double STRICT = 0;
/**
+ * The formatter to be used by {@link #assertWktEquals(Object, String)}.
+ * This formatter uses the {@code “…”} quotation marks instead of {@code "…"}
+ * for easier readability of {@link String} constants in Java code.
+ */
+ private static final WKTFormat WKT_FORMAT = new WKTFormat();
+ static {
+ final Symbols s = new Symbols();
+ s.setPairedQuotes("“”", "\"\"");
+ WKT_FORMAT.setSymbols(s);
+ }
+
+ /**
* For subclass constructor only.
*/
protected Assert() {
@@ -318,38 +332,24 @@ public strictfp class Assert extends org
}
/**
- * Asserts that the WKT of the given object is equal to the expected one. If the given string contains
- * {@code '“'} and {@code '”'} characters (for easier reading), then those characters will be replaced
- * by "ordinary" quote characters ({@code '"'}).
+ * Asserts that the WKT of the given object is equal to the expected one.
+ * This method expected the {@code “…”} quotation marks instead of {@code "…"}
+ * for easier readability of {@link String} constants in Java code.
*
- * @param object The object to format in <cite>Well Known Text</cite> format.
* @param expected The expected text, or {@code null} if {@code object} is expected to be null.
+ * @param object The object to format in <cite>Well Known Text</cite> format, or {@code null}.
*/
- public static void assertWktEquals(final IdentifiedObject object, String expected) {
+ public static void assertWktEquals(final String expected, final Object object) {
if (expected == null) {
assertNull(object);
} else {
assertNotNull(object);
- expected = expected.replace('“', '"').replace('”', '"');
- assertMultilinesEquals(object.getName().getCode(), expected, object.toWKT());
- }
- }
-
- /**
- * Asserts that the given WKT is equal to the expected one. If the given expected string contains
- * {@code '“'} and {@code '”'} characters (for easier reading), then those characters will be replaced
- * by "ordinary" quote characters ({@code '"'}).
- *
- * @param expected The expected text, or {@code null} if {@code actual} is expected to be null.
- * @param actual The actual <cite>Well Known Text</cite> to compare.
- */
- public static void assertWktEquals(String expected, final String actual) {
- if (expected == null) {
- assertNull(actual);
- } else {
- assertNotNull(actual);
- expected = expected.replace('“', '"').replace('”', '"');
- assertMultilinesEquals(expected, actual);
+ final String wkt;
+ synchronized (WKT_FORMAT) {
+ wkt = WKT_FORMAT.format(object);
+ }
+ assertMultilinesEquals((object instanceof IdentifiedObject) ?
+ ((IdentifiedObject) object).getName().getCode() : object.getClass().getSimpleName(), expected, wkt);
}
}
}
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -16,14 +16,16 @@
*/
package org.apache.sis.referencing;
-import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.SingleCRS;
import org.opengis.util.FactoryException;
+import org.apache.sis.referencing.crs.HardCodedCRS;
import org.apache.sis.test.DependsOnMethod;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.apache.sis.test.Assert.*;
/**
@@ -41,7 +43,7 @@ public final strictfp class CRSTest exte
/**
* Asserts that the result of {@link CRS#forCode(String)} is the given CRS.
*/
- private static void verifyForCode(final GeographicCRS expected, final String code) throws FactoryException {
+ private static void verifyForCode(final SingleCRS expected, final String code) throws FactoryException {
assertSame(code, expected, CRS.forCode(code));
}
@@ -52,17 +54,23 @@ public final strictfp class CRSTest exte
*/
@Test
public void testForEpsgCode() throws FactoryException {
- verifyForCode(CommonCRS.WGS84 .geographic(), "EPSG:4326");
- verifyForCode(CommonCRS.WGS84 .geographic(), "urn:ogc:def:crs:EPSG::4326");
- verifyForCode(CommonCRS.WGS84 .geographic(), "http://www.opengis.net/gml/srs/epsg.xml#4326");
- verifyForCode(CommonCRS.WGS72 .geographic(), "EPSG:4322");
- verifyForCode(CommonCRS.SPHERE.geographic(), "EPSG:4047");
- verifyForCode(CommonCRS.NAD83 .geographic(), "EPSG:4269");
- verifyForCode(CommonCRS.NAD27 .geographic(), "EPSG:4267");
- verifyForCode(CommonCRS.ETRS89.geographic(), "EPSG:4258");
- verifyForCode(CommonCRS.ED50 .geographic(), "EPSG:4230");
- assertSame("EPSG:5714", CommonCRS.Vertical.MEAN_SEA_LEVEL.crs(), CRS.forCode("EPSG:5714"));
- assertSame("EPSG:5715", CommonCRS.Vertical.DEPTH.crs(), CRS.forCode("EPSG:5715"));
+ verifyForCode(CommonCRS.WGS84 .geographic(), "EPSG:4326");
+ verifyForCode(CommonCRS.WGS84 .geographic(), "urn:ogc:def:crs:EPSG::4326");
+ verifyForCode(CommonCRS.WGS84 .geographic(), "http://www.opengis.net/gml/srs/epsg.xml#4326");
+ verifyForCode(CommonCRS.WGS72 .geographic(), "EPSG:4322");
+ verifyForCode(CommonCRS.SPHERE.geographic(), "EPSG:4047");
+ verifyForCode(CommonCRS.NAD83 .geographic(), "EPSG:4269");
+ verifyForCode(CommonCRS.NAD27 .geographic(), "EPSG:4267");
+ verifyForCode(CommonCRS.ETRS89.geographic(), "EPSG:4258");
+ verifyForCode(CommonCRS.ED50 .geographic(), "EPSG:4230");
+ verifyForCode(CommonCRS.WGS84 .geocentric(), "EPSG:4978");
+ verifyForCode(CommonCRS.WGS72 .geocentric(), "EPSG:4984");
+ verifyForCode(CommonCRS.ETRS89.geocentric(), "EPSG:4936");
+ verifyForCode(CommonCRS.WGS84 .geographic3D(), "EPSG:4979");
+ verifyForCode(CommonCRS.WGS72 .geographic3D(), "EPSG:4985");
+ verifyForCode(CommonCRS.ETRS89.geographic3D(), "EPSG:4937");
+ verifyForCode(CommonCRS.Vertical.MEAN_SEA_LEVEL.crs(), "EPSG:5714");
+ verifyForCode(CommonCRS.Vertical.DEPTH.crs(), "EPSG:5715");
}
/**
@@ -77,4 +85,68 @@ public final strictfp class CRSTest exte
verifyForCode(CommonCRS.NAD83.normalizedGeographic(), "CRS:83");
verifyForCode(CommonCRS.NAD27.normalizedGeographic(), "CRS:27");
}
+
+ /**
+ * Tests {@link CRS#isHorizontalCRS(CoordinateReferenceSystem)}.
+ */
+ @Test
+ public void testIsHorizontalCRS() {
+ assertFalse(CRS.isHorizontalCRS(HardCodedCRS.TIME));
+ assertFalse(CRS.isHorizontalCRS(HardCodedCRS.ELLIPSOIDAL_HEIGHT));
+ assertTrue (CRS.isHorizontalCRS(HardCodedCRS.WGS84));
+ assertTrue (CRS.isHorizontalCRS(HardCodedCRS.WGS84_φλ));
+ assertFalse(CRS.isHorizontalCRS(HardCodedCRS.WGS84_3D));
+ assertFalse(CRS.isHorizontalCRS(HardCodedCRS.GEOID_4D));
+ assertFalse(CRS.isHorizontalCRS(HardCodedCRS.GEOCENTRIC));
+ }
+
+ /**
+ * Tests {@link CRS#getHorizontalComponent(CoordinateReferenceSystem)}.
+ */
+ @Test
+ @DependsOnMethod("testIsHorizontalCRS")
+ public void testGetHorizontalComponent() {
+ assertNull(CRS.getHorizontalComponent(HardCodedCRS.TIME));
+ assertNull(CRS.getHorizontalComponent(HardCodedCRS.ELLIPSOIDAL_HEIGHT));
+ assertNull(CRS.getHorizontalComponent(HardCodedCRS.GEOCENTRIC));
+
+ assertSame(HardCodedCRS.WGS84, CRS.getHorizontalComponent(HardCodedCRS.WGS84));
+ assertSame(HardCodedCRS.WGS84_φλ, CRS.getHorizontalComponent(HardCodedCRS.WGS84_φλ));
+
+ assertEqualsIgnoreMetadata(HardCodedCRS.WGS84, CRS.getHorizontalComponent(HardCodedCRS.WGS84_3D));
+ }
+
+ /**
+ * Tests {@link CRS#getVerticalComponent(CoordinateReferenceSystem, boolean)}.
+ */
+ @Test
+ public void testGetVerticalComponent() {
+ assertNull(CRS.getVerticalComponent(HardCodedCRS.TIME, false));
+ assertNull(CRS.getVerticalComponent(HardCodedCRS.TIME, true));
+ assertNull(CRS.getVerticalComponent(HardCodedCRS.WGS84, false));
+ assertNull(CRS.getVerticalComponent(HardCodedCRS.WGS84, true));
+
+ assertSame(HardCodedCRS.ELLIPSOIDAL_HEIGHT, CRS.getVerticalComponent(HardCodedCRS.ELLIPSOIDAL_HEIGHT, false));
+ assertSame(HardCodedCRS.ELLIPSOIDAL_HEIGHT, CRS.getVerticalComponent(HardCodedCRS.ELLIPSOIDAL_HEIGHT, true));
+ assertSame(HardCodedCRS.GRAVITY_RELATED_HEIGHT, CRS.getVerticalComponent(HardCodedCRS.GEOID_4D, false));
+ assertSame(HardCodedCRS.GRAVITY_RELATED_HEIGHT, CRS.getVerticalComponent(HardCodedCRS.GEOID_4D, true));
+
+ assertNull(CRS.getVerticalComponent(HardCodedCRS.WGS84_3D, false));
+ assertEqualsIgnoreMetadata(HardCodedCRS.ELLIPSOIDAL_HEIGHT,
+ CRS.getVerticalComponent(HardCodedCRS.WGS84_3D, true));
+ }
+
+ /**
+ * Tests {@link CRS#getTemporalComponent(CoordinateReferenceSystem)}.
+ */
+ @Test
+ public void testGetTemporalComponent() {
+ assertNull(CRS.getTemporalComponent(HardCodedCRS.ELLIPSOIDAL_HEIGHT));
+ assertNull(CRS.getTemporalComponent(HardCodedCRS.WGS84));
+ assertNull(CRS.getTemporalComponent(HardCodedCRS.WGS84_φλ));
+ assertNull(CRS.getTemporalComponent(HardCodedCRS.WGS84_3D));
+
+ assertSame(HardCodedCRS.TIME, CRS.getTemporalComponent(HardCodedCRS.TIME));
+ assertSame(HardCodedCRS.TIME, CRS.getTemporalComponent(HardCodedCRS.GEOID_4D));
+ }
}
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -137,6 +137,13 @@ public final strictfp class HardCodedCRS
getProperties(HardCodedCS.DAYS), HardCodedDatum.UNIX, HardCodedCS.DAYS);
/**
+ * A (λ,φ,h,t) CRS where <var>h</var> is the {@link #GRAVITY_RELATED_HEIGHT}.
+ * This constant uses the "geoid" term as an approximation for the gravity related height.
+ */
+ public static final DefaultCompoundCRS GEOID_4D = new DefaultCompoundCRS(
+ properties("WGS 84 + height + time"), GRAVITY_RELATED_HEIGHT, TIME);
+
+ /**
* A two-dimensional Cartesian coordinate reference system with (column, row) axes.
* By default, this CRS has no transformation path to any other CRS (i.e. a map using
* this CS can't be reprojected to a geographic coordinate reference system for example).
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRSTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRSTest.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRSTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRSTest.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -72,7 +72,7 @@ public final strictfp class HardCodedCRS
*/
@Test
public void testWKT() {
- assertWktEquals(WGS84,
+ assertWktEquals(
"GEOGCS[“WGS 84”,\n" +
" DATUM[“World Geodetic System 1984”,\n" +
" SPHEROID[“WGS84”, 6378137.0, 298.257223563],\n" +
@@ -80,7 +80,8 @@ public final strictfp class HardCodedCRS
" PRIMEM[“Greenwich”, 0.0, AUTHORITY[“EPSG”, “8901”]],\n" +
" UNIT[“degree”, 0.017453292519943295],\n" +
" AXIS[“Geodetic longitude”, EAST],\n" +
- " AXIS[“Geodetic latitude”, NORTH]]");
+ " AXIS[“Geodetic latitude”, NORTH]]",
+ WGS84);
}
/**