Author: desruisseaux
Date: Mon Jan 13 14:50:41 2014
New Revision: 1557738

URL: http://svn.apache.org/r1557738
Log:
Modify CoordinateSystems.angle(...) API in order to let user know when the 
angle sign give no indication
about whether the coordinate system is right-handed or left-handed, and clarify 
javadoc.

Added:
    
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ElevationAngle.java
   (with props)
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/cs/AxesConvention.java
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DirectionAlongMeridian.java
    
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/CoordinateSystemsTest.java
    
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DirectionAlongMeridianTest.java
    
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Angle.java
    
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
    
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java
    
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java

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=1557738&r1=1557737&r2=1557738&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] Mon Jan 13 14:50:41 2014
@@ -195,6 +195,18 @@ public final class AxisDirections extend
     }
 
     /**
+     * Returns {@code true} if the given direction is {@code OTHER} or a 
user-defined direction.
+     *
+     * @param  dir The direction to test, or {@code null}.
+     * @return {@code true} if the given direction is {@code OTHER} or a 
user-defined direction.
+     */
+    public static boolean isCustom(final AxisDirection dir) {
+        if (dir == null) return false;
+        final int ordinal = dir.ordinal();
+        return ordinal <= OTHER.ordinal() || ordinal > DISPLAY_DOWN.ordinal();
+    }
+
+    /**
      * Returns {@code true} if the given direction is a spatial axis direction 
(including vertical and geocentric axes).
      * The current implementation conservatively returns {@code true} for 
every non-null directions except a hard-coded
      * set of directions which are known to be non-spatial. We conservatively 
accept unknown axis directions because

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -72,8 +72,9 @@ public enum AxesConvention {
     /**
      * Axes are reordered for a <cite>right-handed</cite> coordinate system. 
Axis orientations and ranges are unchanged.
      * This enum is often used for deriving a coordinate system with the 
(<var>longitude</var>, <var>latitude</var>) or
-     * (<var>x</var>,<var>y</var>) axis order. However a right-handed 
coordinate system does not guarantee
-     * that longitude or <var>x</var> axis will be first (see for example the 
(North, West) case below).
+     * (<var>x</var>,<var>y</var>) axis order. While it works in many cases, 
note that a right-handed coordinate system
+     * does not guarantee that longitude or <var>x</var> axis will be first in 
every cases. The most notable exception
+     * is the (North, West) case.
      *
      * {@note We do not provide a "<cite>longitude or <var>x</var> axis 
first</cite>" enumeration value because
      *        such criterion is hard to apply to inter-cardinal directions and 
has no meaning for map projections

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -24,6 +24,8 @@ import javax.measure.converter.Conversio
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.operation.Matrix;
+import org.apache.sis.measure.Angle;
+import org.apache.sis.measure.ElevationAngle;
 import org.apache.sis.measure.Units;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Classes;
@@ -96,12 +98,12 @@ public final class CoordinateSystems ext
     }
 
     /**
-     * Returns the arithmetic (counterclockwise) angle from the first axis 
direction to the second direction,
-     * in decimal <strong>degrees</strong>. This method returns a value 
between -180° and +180°,
-     * or {@link Double#NaN NaN} if no angle can be computed.
+     * Returns the arithmetic (counterclockwise) angle from the first axis 
direction to the second direction.
+     * This method returns a value between -180° and +180°, or {@code null} if 
no angle can be computed.
      *
-     * <p>A positive angle between two compass directions denotes a 
right-handed system,
-     * while a negative angle denotes a left-handed system. Examples:</p>
+     * {@section Horizontal directions}
+     * For any pair of compass directions which are not opposite directions, a 
positive angle denotes
+     * a right-handed system while a negative angle denotes a left-handed 
system. Examples:
      *
      * <ul>
      *   <li>The angle from {@link AxisDirection#EAST EAST} to {@link 
AxisDirection#NORTH NORTH} is 90°</li>
@@ -109,16 +111,22 @@ public final class CoordinateSystems ext
      *   <li>The angle from "<cite>North along 90° East</cite>" to 
"<cite>North along 0°</cite>" is 90°.</li>
      * </ul>
      *
-     * {@section Vertical directions}
-     * By convention, this method defines the angle from any compass direction 
to the {@link AxisDirection#UP UP}
-     * vertical direction (the <cite>altitude</cite> or 
<cite>elevation</cite>) as 90°, and the angle of any compass
-     * direction to the {@link AxisDirection#DOWN DOWN} vertical direction as 
-90°. The angle between two opposite
-     * vertical directions is ±180°. Those directions are approximative since 
this method does not take the Earth
-     * ellipsoidal or geoidal shape in account.
+     * {@section Horizontal and vertical directions}
+     * By convention this method defines the angle from any compass direction 
to the {@link AxisDirection#UP UP}
+     * vertical direction as 90°, and the angle of any compass direction to 
the {@link AxisDirection#DOWN DOWN}
+     * vertical direction as -90°. The sign of those angles gives no 
indication about whether the coordinate system
+     * is right-handed or left-handed. Those angles are returned as instances 
of {@link ElevationAngle}.
+     *
+     * <p>All angles are approximative since this method does not take the 
Earth ellipsoidal or geoidal shape in
+     * account.</p>
      *
      * {@section Invariants}
-     * {@code angle(A, B) == -angle(B, A)} for any return value different than 
{@code NaN}.
-     * This invariant holds also for angles of ±180°, even if an angle of 
-180° is equivalent to +180°.
+     * For any non-null return value:
+     * <ul>
+     *   <li>{@code angle(A, A) == 0°}</li>
+     *   <li>{@code angle(A, opposite(A)) == ±180°}</li>
+     *   <li>{@code angle(A, B) == -angle(B, A)}</li>
+     * </ul>
      *
      * @param  source The source axis direction.
      * @param  target The target axis direction.
@@ -126,7 +134,7 @@ public final class CoordinateSystems ext
      *         the source direction in order to make it point toward the 
target direction, or
      *         {@link Double#NaN} if this value can not be computed.
      */
-    public static double angle(final AxisDirection source, final AxisDirection 
target) {
+    public static Angle angle(final AxisDirection source, final AxisDirection 
target) {
         ensureNonNull("source", source);
         ensureNonNull("target", target);
         /*
@@ -135,47 +143,48 @@ public final class CoordinateSystems ext
          */
         int c = AxisDirections.angleForCompass(source, target);
         if (c != Integer.MIN_VALUE) {
-            return c * (360.0 / AxisDirections.COMPASS_COUNT);
-        }
-        /*
-         * Check for UP and DOWN, with special case if one of the direction is 
a compass one.
-         */
-        final boolean v1 = AxisDirections.isVertical(source);
-        final boolean v2 = AxisDirections.isVertical(target);
-        if (v1 | v2) {
-            if (v1 & v2) {
-                return (source == target) ? 0 : (target == AxisDirection.UP) ? 
180 : -180;
-            }
-            if (AxisDirections.isCompass(v1 ? target : source)) {
-                return (v1 ? source : target) == AxisDirection.UP ? 90 : -90;
-            }
+            return new Angle(c * (360.0 / AxisDirections.COMPASS_COUNT));
         }
         /*
          * Check for GEOCENTRIC_X, GEOCENTRIC_Y, GEOCENTRIC_Z.
          */
         c = AxisDirections.angleForGeocentric(source, target);
         if (c != Integer.MIN_VALUE) {
-            return c * 90.0;
+            return new Angle(c * 90);
         }
         /*
          * Check for DISPLAY_UP, DISPLAY_DOWN, etc.
          */
         c = AxisDirections.angleForDisplay(source, target);
         if (c != Integer.MIN_VALUE) {
-            return c * (360.0 / AxisDirections.DISPLAY_COUNT);
+            return new Angle(c * (360 / AxisDirections.DISPLAY_COUNT));
         }
         /*
          * Check for "South along 90° East", etc. directions. We do this test 
last
          * because it performs a relatively costly parsing of axis direction 
name.
          */
-        final DirectionAlongMeridian src = 
DirectionAlongMeridian.parse(source);
-        if (src != null) {
-            final DirectionAlongMeridian tgt = 
DirectionAlongMeridian.parse(target);
-            if (tgt != null) {
-                return src.getAngle(tgt);
+        final DirectionAlongMeridian srcMeridian = 
DirectionAlongMeridian.parse(source);
+        final DirectionAlongMeridian tgtMeridian = 
DirectionAlongMeridian.parse(target);
+        if (srcMeridian != null && tgtMeridian != null) {
+            return new Angle(srcMeridian.angle(tgtMeridian));
+        }
+        /*
+         * Check for UP and DOWN, with special case if one of the direction is 
a compass one.
+         */
+        final boolean srcVrt = AxisDirections.isVertical(source);
+        final boolean tgtVrt = AxisDirections.isVertical(target);
+        if (tgtVrt) {
+            if (srcVrt) {
+                return new Angle(source.equals(target) ? 0 : 
target.equals(AxisDirection.UP) ? 180 : -180);
+            } else if (AxisDirections.isCompass(source) || srcMeridian != 
null) {
+                return target.equals(AxisDirection.UP) ? ElevationAngle.ZENITH 
: ElevationAngle.NADIR;
+            }
+        } else if (srcVrt) {
+            if (AxisDirections.isCompass(target) || tgtMeridian != null) {
+                return source.equals(AxisDirection.UP) ? ElevationAngle.NADIR 
: ElevationAngle.ZENITH;
             }
         }
-        return Double.NaN;
+        return null;
     }
 
     /**

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -22,8 +22,9 @@ import javax.xml.bind.annotation.XmlRoot
 import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
-import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.internal.referencing.AxisDirections;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.measure.Angle;
 
 
 /**
@@ -194,11 +195,16 @@ public class DefaultCartesianCS extends 
             final AxisDirection axis0 = getAxis(i).getDirection();
             for (int j=i; ++j<dimension;) {
                 final AxisDirection axis1 = getAxis(j).getDirection();
-                final double angle = CoordinateSystems.angle(axis0, axis1); // 
May be NaN, which we accept.
-                if (Math.abs(Math.abs(angle) - 90) > 
Formulas.ANGULAR_TOLERANCE) {
-                    throw new IllegalArgumentException(Errors.format(
-                            Errors.Keys.NonPerpendicularDirections_2, axis0, 
axis1));
+                final Angle angle = CoordinateSystems.angle(axis0, axis1);
+                if (angle != null) {
+                    if (Math.abs(angle.degrees()) == 90) {
+                        continue; // Axes are perpendicular.
+                    }
+                } else if (AxisDirections.isCustom(axis0) || 
AxisDirections.isCustom(axis1)) {
+                    continue; // If we do not recognize an axis, assume that 
the user know what he is doing.
                 }
+                throw new IllegalArgumentException(Errors.format(
+                        Errors.Keys.NonPerpendicularDirections_2, axis0, 
axis1));
             }
         }
     }

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DirectionAlongMeridian.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DirectionAlongMeridian.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DirectionAlongMeridian.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DirectionAlongMeridian.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -21,6 +21,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.opengis.referencing.cs.AxisDirection;
 import org.apache.sis.util.iso.Types;
+import org.apache.sis.measure.Longitude;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.referencing.AxisDirections;
 
@@ -127,7 +128,7 @@ final class DirectionAlongMeridian imple
             // since we are supposed to return 'null' in this situation.
             return null;
         }
-        if (!(meridian >= -180 && meridian <= 180)) {
+        if (!(meridian >= Longitude.MIN_VALUE && meridian <= 
Longitude.MAX_VALUE)) {
             // Meridian is NaN or is not in the valid range.
             return null;
         }
@@ -172,24 +173,14 @@ final class DirectionAlongMeridian imple
      *
      * {@example The angle from "<cite>North along 90 deg East</cite>" to 
"<cite>North along 0 deg</cite> is 90°.}
      */
-    public double getAngle(final DirectionAlongMeridian other) {
+    public double angle(final DirectionAlongMeridian other) {
         if (!baseDirection.equals(other.baseDirection)) {
             return Double.NaN;
         }
         /*
-         * We want the following pair of axis:
-         * (NORTH along 90°E, NORTH along 0°)
-         * to give a positive angle of 90°
+         * Example: angle between (NORTH along 90°E, NORTH along 0°) shall be 
+90°
          */
-        double angle = meridian - other.meridian;
-        /*
-         * Forces to the [-180° .. +180°] range.
-         */
-        if (angle < -180) {
-            angle += 360;
-        } else if (angle > 180) {
-            angle -= 360;
-        }
+        double angle = Longitude.normalize(meridian - other.meridian);
         /*
          * Reverses the sign for axis oriented toward SOUTH,
          * so a positive angle is a right-handed system.
@@ -220,7 +211,7 @@ final class DirectionAlongMeridian imple
         if (c != 0) {
             return c;
         }
-        final double angle = getAngle(that);
+        final double angle = angle(that);
         if (angle < 0) return +1;  // Really the opposite sign.
         if (angle > 0) return -1;  // Really the opposite sign.
         return 0;
@@ -275,7 +266,7 @@ final class DirectionAlongMeridian imple
             buffer.append(md);
         }
         buffer.append('°');
-        if (md != 0 && md != 180) {
+        if (md != 0 && md != Longitude.MAX_VALUE) {
             buffer.append(meridian < 0 ? 'W' : 'E');
         }
         name = buffer.toString();

Modified: 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/CoordinateSystemsTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/CoordinateSystemsTest.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/CoordinateSystemsTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/CoordinateSystemsTest.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -21,6 +21,8 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.measure.Angle;
+import org.apache.sis.measure.ElevationAngle;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -49,7 +51,7 @@ public final strictfp class CoordinateSy
     /**
      * Tolerance threshold for strict floating point comparisons.
      */
-    static final double STRICT = 0;
+    private static final double STRICT = 0;
 
     /**
      * Tests {@link CoordinateSystems#parseAxisDirection(String)}.
@@ -78,27 +80,29 @@ public final strictfp class CoordinateSy
      */
     @Test
     public void testAngle() {
-        assertAngleEquals(  0,   AxisDirection.EAST,             
AxisDirection.EAST);
-        assertAngleEquals( 90,   AxisDirection.EAST,             
AxisDirection.NORTH);
-        assertAngleEquals( 90,   AxisDirection.WEST,             
AxisDirection.SOUTH);
-        assertAngleEquals(180,   AxisDirection.SOUTH,            
AxisDirection.NORTH);
-        assertAngleEquals(180,   AxisDirection.WEST,             
AxisDirection.EAST);
-        assertAngleEquals( 45,   AxisDirection.NORTH_EAST,       
AxisDirection.NORTH);
-        assertAngleEquals( 22.5, AxisDirection.NORTH_NORTH_EAST, 
AxisDirection.NORTH);
-        assertAngleEquals( 45,   AxisDirection.SOUTH,            
AxisDirection.SOUTH_EAST);
-        assertAngleEquals(NaN,   AxisDirection.NORTH,            
AxisDirection.FUTURE);
-        assertAngleEquals(  0,   AxisDirection.UP,               
AxisDirection.UP);
-        assertAngleEquals(  0,   AxisDirection.DOWN,             
AxisDirection.DOWN);
-        assertAngleEquals(180,   AxisDirection.DOWN,             
AxisDirection.UP);
-        assertAngleEquals(NaN,   AxisDirection.DOWN,             
AxisDirection.FUTURE);
-        assertAngleEquals(180,   AxisDirection.DISPLAY_DOWN,     
AxisDirection.DISPLAY_UP);
-        assertAngleEquals(-90,   AxisDirection.DISPLAY_RIGHT,    
AxisDirection.DISPLAY_DOWN);
-        assertAngleEquals(NaN,   AxisDirection.DISPLAY_UP,       
AxisDirection.DOWN);
-        assertAngleEquals(NaN,   AxisDirection.PAST,             
AxisDirection.FUTURE); // Not spatial directions.
-        assertAngleEquals( 90,   AxisDirection.GEOCENTRIC_X,     
AxisDirection.GEOCENTRIC_Y);
-        assertAngleEquals( 90,   AxisDirection.GEOCENTRIC_Y,     
AxisDirection.GEOCENTRIC_Z);
-        assertAngleEquals(  0,   AxisDirection.GEOCENTRIC_Y,     
AxisDirection.GEOCENTRIC_Y);
-        assertAngleEquals(NaN,   AxisDirection.GEOCENTRIC_Z,     
AxisDirection.UP);
+        assertAngleEquals(false,   0,   AxisDirection.EAST,             
AxisDirection.EAST);
+        assertAngleEquals(false,  90,   AxisDirection.EAST,             
AxisDirection.NORTH);
+        assertAngleEquals(false,  90,   AxisDirection.WEST,             
AxisDirection.SOUTH);
+        assertAngleEquals(false, 180,   AxisDirection.SOUTH,            
AxisDirection.NORTH);
+        assertAngleEquals(false, 180,   AxisDirection.WEST,             
AxisDirection.EAST);
+        assertAngleEquals(false,  45,   AxisDirection.NORTH_EAST,       
AxisDirection.NORTH);
+        assertAngleEquals(false,  22.5, AxisDirection.NORTH_NORTH_EAST, 
AxisDirection.NORTH);
+        assertAngleEquals(false,  45,   AxisDirection.SOUTH,            
AxisDirection.SOUTH_EAST);
+        assertAngleEquals(false, NaN,   AxisDirection.NORTH,            
AxisDirection.FUTURE);
+        assertAngleEquals(true,   90,   AxisDirection.SOUTH,            
AxisDirection.UP);
+        assertAngleEquals(true,  -90,   AxisDirection.SOUTH,            
AxisDirection.DOWN);
+        assertAngleEquals(false,   0,   AxisDirection.UP,               
AxisDirection.UP);
+        assertAngleEquals(false,   0,   AxisDirection.DOWN,             
AxisDirection.DOWN);
+        assertAngleEquals(false, 180,   AxisDirection.DOWN,             
AxisDirection.UP);
+        assertAngleEquals(false, NaN,   AxisDirection.DOWN,             
AxisDirection.FUTURE);
+        assertAngleEquals(false, 180,   AxisDirection.DISPLAY_DOWN,     
AxisDirection.DISPLAY_UP);
+        assertAngleEquals(false, -90,   AxisDirection.DISPLAY_RIGHT,    
AxisDirection.DISPLAY_DOWN);
+        assertAngleEquals(false, NaN,   AxisDirection.DISPLAY_UP,       
AxisDirection.DOWN);
+        assertAngleEquals(false, NaN,   AxisDirection.PAST,             
AxisDirection.FUTURE); // Not spatial directions.
+        assertAngleEquals(false,  90,   AxisDirection.GEOCENTRIC_X,     
AxisDirection.GEOCENTRIC_Y);
+        assertAngleEquals(false,  90,   AxisDirection.GEOCENTRIC_Y,     
AxisDirection.GEOCENTRIC_Z);
+        assertAngleEquals(false,   0,   AxisDirection.GEOCENTRIC_Y,     
AxisDirection.GEOCENTRIC_Y);
+        assertAngleEquals(false, NaN,   AxisDirection.GEOCENTRIC_Z,     
AxisDirection.UP);
     }
 
     /**
@@ -107,38 +111,50 @@ public final strictfp class CoordinateSy
     @Test
     @DependsOnMethod({"testParseAxisDirection", "testAngle"})
     public void testAngleAlongMeridians() {
-        assertAngleEquals( 90.0, "West",                    "South");
-        assertAngleEquals(-90.0, "South",                   "West");
-        assertAngleEquals( 45.0, "South",                   "South-East");
-        assertAngleEquals(-22.5, "North-North-West",        "North");
-        assertAngleEquals(-22.5, "North_North_West",        "North");
-        assertAngleEquals(-22.5, "North North West",        "North");
-        assertAngleEquals( 90.0, "North along 90 deg East", "North along 0 
deg");
-        assertAngleEquals( 90.0, "South along 180 deg",     "South along 90 
deg West");
-        assertAngleEquals(   90, "North along 90°E",        "North along 0°");
-        assertAngleEquals(  135, "North along 90°E",        "North along 
45°W");
-        assertAngleEquals( -135, "North along 45°W",        "North along 
90°E");
+        assertAngleEquals(false,   90.0, "West",                    "South");
+        assertAngleEquals(false,  -90.0, "South",                   "West");
+        assertAngleEquals(false,   45.0, "South",                   
"South-East");
+        assertAngleEquals(true,    90.0, "West",                    "Up");
+        assertAngleEquals(true,   -90.0, "West",                    "Down");
+        assertAngleEquals(false,  -22.5, "North-North-West",        "North");
+        assertAngleEquals(false,  -22.5, "North_North_West",        "North");
+        assertAngleEquals(false,  -22.5, "North North West",        "North");
+        assertAngleEquals(false,   90.0, "North along 90 deg East", "North 
along 0 deg");
+        assertAngleEquals(false,   90.0, "South along 180 deg",     "South 
along 90 deg West");
+        assertAngleEquals(false,   90.0, "North along 90°E",        "North 
along 0°");
+        assertAngleEquals(false,  135.0, "North along 90°E",        "North 
along 45°W");
+        assertAngleEquals(false, -135.0, "North along 45°W",        "North 
along 90°E");
+        assertAngleEquals(true,    90.0, "North along 45°W",        "Up");
+        assertAngleEquals(true,   -90.0, "North along 45°W",        "Down");
     }
 
     /**
      * Asserts that the angle between the parsed directions is equals to the 
given value.
      * This method tests also the angle by interchanging the axis directions.
      */
-    private static void assertAngleEquals(final double expected, final String 
source, final String target) {
+    private static void assertAngleEquals(final boolean isElevation, final 
double expected,
+            final String source, final String target)
+    {
         final AxisDirection dir1 = parseAxisDirection(source);
         final AxisDirection dir2 = parseAxisDirection(target);
         assertNotNull(source, dir1);
         assertNotNull(target, dir2);
-        assertAngleEquals(expected, dir1, dir2);
+        assertAngleEquals(isElevation, expected, dir1, dir2);
     }
 
     /**
      * Asserts that the angle between the given directions is equals to the 
given value.
      * This method tests also the angle by interchanging the given directions.
      */
-    private static void assertAngleEquals(final double expected, final 
AxisDirection source, final AxisDirection target) {
-        assertEquals(+expected, angle(source, target), STRICT);
-        assertEquals(-expected, angle(target, source), STRICT);
+    private static void assertAngleEquals(final boolean isElevation, final 
double expected,
+            final AxisDirection source, final AxisDirection target)
+    {
+        final Angle forward = angle(source, target);
+        final Angle inverse = angle(target, source);
+        assertEquals(isElevation, forward instanceof ElevationAngle);
+        assertEquals(isElevation, inverse instanceof ElevationAngle);
+        assertEquals(+expected, (forward != null) ? forward.degrees() : 
Double.NaN, STRICT);
+        assertEquals(-expected, (inverse != null) ? inverse.degrees() : 
Double.NaN, STRICT);
     }
 
     /**

Modified: 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DirectionAlongMeridianTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DirectionAlongMeridianTest.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DirectionAlongMeridianTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DirectionAlongMeridianTest.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -35,9 +35,9 @@ import static org.junit.Assert.*;
 @DependsOn(org.apache.sis.internal.referencing.AxisDirectionsTest.class)
 public final strictfp class DirectionAlongMeridianTest extends TestCase {
     /**
-     * For floating point comparisons.
+     * Tolerance threshold for strict floating point comparisons.
      */
-    private static final double EPS = 1E-10;
+    private static final double STRICT = 0;
 
     /**
      * Tests the {@link DirectionAlongMeridian#parse(AxisDirection)} method.
@@ -99,8 +99,8 @@ public final strictfp class DirectionAlo
     private static void assertOrdered(final String dir1, final String dir2) {
         final DirectionAlongMeridian m1 = DirectionAlongMeridian.parse(dir1);
         final DirectionAlongMeridian m2 = DirectionAlongMeridian.parse(dir2);
-        assertEquals(+90, m1.getAngle(m2), EPS);
-        assertEquals(-90, m2.getAngle(m1), EPS);
+        assertEquals(+90, m1.angle(m2), STRICT);
+        assertEquals(-90, m2.angle(m1), STRICT);
         assertEquals( -1, m1.compareTo(m2));
         assertEquals( +1, m2.compareTo(m1));
         assertFalse (m1.equals(m2));

Modified: 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Angle.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Angle.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Angle.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Angle.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -31,18 +31,18 @@ import static org.apache.sis.math.MathFu
 
 /**
  * An angle in decimal degrees. An angle is the amount of rotation needed to 
bring one line or plane
- * into coincidence with another, generally measured in degrees, sexagesimal 
degrees or grads.
- * Various kind of angles are used in geographic information systems,
+ * into coincidence with another. Various kind of angles are used in 
geographic information systems,
  * some of them having a specialized class in Apache SIS:
  *
  * <ul>
- *   <li>{@linkplain Latitude} is an angle which ranges from 0° at the equator 
to 90° at the poles.</li>
- *   <li>{@linkplain Longitude} is an angle measured east-west from a prime 
meridian
- *       (usually Greenwich, but not necessarily).</li>
+ *   <li>{@linkplain Latitude} is an angle ranging from 0° at the equator to 
90° at the poles.</li>
+ *   <li>{@linkplain Longitude} is an angle measured east-west from a prime 
meridian (usually Greenwich, but not necessarily).</li>
  *   <li><cite>Azimuth</cite> is a direction given by an angle between 0° and 
360° measured clockwise from North.</li>
- *   <li><cite>Bearing</cite> is a direction given by an angle between 0° and 
90° in a quadrant defined by a cardinal
- *       direction. Bearing is also sometime used for an angle relative to a 
vessel forward direction.</li>
+ *   <li><cite>Bearing</cite> is a direction given by an angle between 0° and 
90° in a quadrant defined by a cardinal direction.</li>
+ *   <li><cite>Bearing</cite> is also sometime used in navigation for an angle 
relative to the vessel forward direction.</li>
+ *   <li><cite>Deflection angle</cite> is the angle between a line and the 
prolongation of a preceding line.</li>
  *   <li><cite>Interior angle</cite> is an angle measured between two lines of 
sight.</li>
+ *   <li><cite>Elevation angle</cite> is the angular height from the 
horizontal plane to an object above the horizon.</li>
  * </ul>
  *
  * {@section Formatting angles}

Modified: 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -195,7 +195,7 @@ public class AngleFormat extends Format 
     private static final int[] SYMBOLS = {'D', 'M', 'S', '#', '?'};
 
     /**
-     * Defines constants that are used as attribute keys in the iterator 
returned from
+     * Constants that are used as attribute keys in the iterator returned from
      * {@link AngleFormat#formatToCharacterIterator(Object)}.
      *
      * @author  Martin Desruisseaux (Geomatys)

Added: 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ElevationAngle.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ElevationAngle.java?rev=1557738&view=auto
==============================================================================
--- 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ElevationAngle.java
 (added)
+++ 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ElevationAngle.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.measure;
+
+
+/**
+ * The angular height of an object measured from the horizontal.
+ * For visible objects it is an angle between 0 and 90 degrees.
+ *
+ * {@note <cite>Elevation angle</cite> and <cite>altitude angle</cite> may be 
used interchangeably.
+ *        Both <cite>altitude</cite> and <cite>elevation</cite> words are also 
used to describe the
+ *        height in meters above sea level.}
+ *
+ * {@section Immutability and thread safety}
+ * This final class is immutable and thus inherently thread-safe.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.4
+ * @version 0.4
+ * @module
+ */
+public final class ElevationAngle extends Angle {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = 442355803542468396L;
+
+    /**
+     * An elevation angle of 90° for an imaginary point directly above a 
location.
+     * This is the opposite of {@link #NADIR} direction.
+     */
+    public static final ElevationAngle ZENITH = new ElevationAngle(90);
+
+    /**
+     * An elevation angle of -90° for an imaginary point directly below a 
location.
+     * This is the opposite of {@link #ZENITH} direction.
+     */
+    public static final ElevationAngle NADIR = new ElevationAngle(-90);
+
+    /**
+     * Constructs a new elevation angle with the specified angular value.
+     *
+     * @param θ Elevation angle value in decimal degrees.
+     */
+    public ElevationAngle(final double θ) {
+        super(θ);
+    }
+
+    /**
+     * Constructs a newly allocated {@code ElevationAngle} object that contain 
the angular value
+     * represented by the string. The string should represent an angle in 
either fractional degrees
+     * (e.g. 45.5°) or degrees with minutes and seconds (e.g. 45°30').
+     *
+     * @param  string A string to be converted to an {@code ElevationAngle}.
+     * @throws NumberFormatException if the string does not contain a parsable 
angle,
+     *         or represents an elevation angle.
+     */
+    public ElevationAngle(final String string) throws NumberFormatException {
+        super(string);
+    }
+}

Propchange: 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ElevationAngle.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ElevationAngle.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -40,7 +40,7 @@ package org.apache.sis.measure;
  * {@linkplain org.apache.sis.referencing.crs.DefaultGeographicCRS geographic},
  * or <cite>geocentric</cite> if the coordinate reference system is
  * {@linkplain org.apache.sis.referencing.crs.DefaultGeocentricCRS geocentric}.
- * If the context is unknown, geodetic latitude can usually be assumed.
+ * If the context is unknown, then geodetic latitude can usually be assumed.
  *
  * {@section Immutability and thread safety}
  * This final class is immutable and thus inherently thread-safe.

Modified: 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java?rev=1557738&r1=1557737&r2=1557738&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
 [UTF-8] Mon Jan 13 14:50:41 2014
@@ -123,7 +123,7 @@ public class RangeFormat extends Format 
     private static final int UNIT_FIELD = 2;
 
     /**
-     * Defines constants that are used as attribute keys in the iterator 
returned from
+     * Constants that are used as attribute keys in the iterator returned from
      * {@link RangeFormat#formatToCharacterIterator(Object)}.
      *
      * @author  Martin Desruisseaux (Geomatys)


Reply via email to