Author: desruisseaux
Date: Tue Jan 28 23:07:36 2014
New Revision: 1562306

URL: http://svn.apache.org/r1562306
Log:
Port of CRS.isHorizontal, CRS.getProjectedCRS, CRS.getVerticalCRS and 
CRS.getTemporalCRS methods.

Modified:
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
    
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
    sis/ip-review/rev/33571/CRS.xhtml

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java?rev=1562306&r1=1562305&r2=1562306&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
 [UTF-8] Tue Jan 28 23:07:36 2014
@@ -334,17 +334,16 @@ public final class AxisDirections extend
      * @param  direction The direction of the axis to search.
      * @return The dimension of the axis using the given direction or its 
opposite, or -1 if none.
      */
-    public static int indexOf(final CoordinateSystem cs, final AxisDirection 
direction) {
+    public static int indexOfColinear(final CoordinateSystem cs, final 
AxisDirection direction) {
         int fallback = -1;
         if (cs != null) {
-            final AxisDirection opposite = opposite(direction);
             final int dimension = cs.getDimension();
             for (int i=0; i<dimension; i++) {
                 final AxisDirection d = cs.getAxis(i).getDirection();
                 if (direction.equals(d)) {
                     return i;
                 }
-                if (fallback < 0 && opposite != null && opposite.equals(d)) {
+                if (fallback < 0 && d.equals(opposite(direction))) {
                     fallback = i;
                 }
             }

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java?rev=1562306&r1=1562305&r2=1562306&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
 [UTF-8] Tue Jan 28 23:07:36 2014
@@ -16,19 +16,32 @@
  */
 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.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.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.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.Static;
@@ -38,6 +51,25 @@ import static org.apache.sis.util.Argume
 
 /**
  * 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)
@@ -91,6 +123,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
@@ -154,6 +188,163 @@ 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)
+     *
+     * @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>
+     *
+     * @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.
+     *
+     * In case of doubt, this method conservatively returns {@code false}.
+     *
+     * @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 #getHorizontalCRS(CoordinateReferenceSystem)
+     *
+     * @category information
+     */
+    public static boolean isHorizontalCRS(CoordinateReferenceSystem crs) {
+        if (crs instanceof GeographicCRS || crs instanceof ProjectedCRS) {
+            return crs.getCoordinateSystem().getDimension() == 2;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the first projected coordinate reference system found in a the 
given CRS,
+     * or {@code null} if there is none.
+     *
+     * @param  crs The coordinate reference system, or {@code null}.
+     * @return The first projected CRS, or {@code null} if none.
+     *
+     * @category information
+     */
+    public static ProjectedCRS getProjectedCRS(final CoordinateReferenceSystem 
crs) {
+        if (crs instanceof ProjectedCRS) {
+            return (ProjectedCRS) crs;
+        }
+        if (crs instanceof CompoundCRS) {
+            final CompoundCRS cp = (CompoundCRS) crs;
+            for (final CoordinateReferenceSystem c : cp.getComponents()) {
+                final ProjectedCRS candidate = getProjectedCRS(c);
+                if (candidate != null) {
+                    return candidate;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the first vertical coordinate reference system found in a the 
given CRS,
+     * or {@code null} if there is none.
+     *
+     * {@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 getVerticalCRS(…)} 
does when the
+     * {@code allowEllipsoidal} 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 allowEllipsoidal} argument to {@code true}. In such case, this 
{@code getVerticalCRS(…)}
+     * method will create a temporary {@code VerticalCRS} from the first 
three-dimensional {@code GeographicCRS}
+     * <em>in last resort</em>, only if it failed to 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  allowEllipsoidal {@code true} for allowing the creation of 
orphan CRS for ellipsoidal heights.
+     *         This is usually not recommended.
+     * @return The first vertical CRS, or {@code null} if none.
+     *
+     * @category information
+     */
+    public static VerticalCRS getVerticalCRS(final CoordinateReferenceSystem 
crs, final boolean allowEllipsoidal) {
+        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 = getVerticalCRS(c, a);
+                    if (candidate != null) {
+                        return candidate;
+                    }
+                }
+            } while ((a = !a) == allowEllipsoidal);
+        }
+        if (allowEllipsoidal && 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.
+     *
+     * @param  crs The coordinate reference system, or {@code null}.
+     * @return The first temporal CRS, or {@code null} if none.
+     *
+     * @category information
+     */
+    public static TemporalCRS getTemporalCRS(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 = getTemporalCRS(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/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java?rev=1562306&r1=1562305&r2=1562306&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
 [UTF-8] Tue Jan 28 23:07:36 2014
@@ -822,12 +822,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/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java?rev=1562306&r1=1562305&r2=1562306&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
 [UTF-8] Tue Jan 28 23:07:36 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/ip-review/rev/33571/CRS.xhtml
URL: 
http://svn.apache.org/viewvc/sis/ip-review/rev/33571/CRS.xhtml?rev=1562306&r1=1562305&r2=1562306&view=diff
==============================================================================
--- sis/ip-review/rev/33571/CRS.xhtml (original)
+++ sis/ip-review/rev/33571/CRS.xhtml Tue Jan 28 23:07:36 2014
@@ -11,7 +11,7 @@
     <div>
       <h1>CRS changes for revisions 33570:33571</h1>
       <p>This change, identified with the "<cite>fix for GEOT-2613</cite>" 
commit message,
-         has been rejected because it is wrong. This change was applied in the 
following method:</p>
+         has been discarded. This change was applied in the following 
method:</p>
 
       <blockquote><pre>public static SingleCRS 
getHorizontalCRS(CoordinateReferenceSystem crs);</pre></blockquote>
 


Reply via email to