net.grelf
Class Angle

java.lang.Object
  extended by net.grelf.Angle
All Implemented Interfaces:
java.io.Serializable, java.lang.Cloneable, java.lang.Comparable<Angle>
Direct Known Subclasses:
Dec, RA

public class Angle
extends java.lang.Object
implements java.lang.Cloneable, java.lang.Comparable<Angle>, java.io.Serializable

In java.lang.(Strict)Math you have to keep track of whether an angle is in degrees or radians when you use trigonometrical functions; the present class knows what to do, so you can forget about it! This should reduce the potential for errors of the degrees/radians kind.

Rationale
A continual refrain in Jean Meeus' excellent series of books on astronomical computation is the risk of errors due to the fact that angles are usually given in degrees but trigonometry requires radians. It is vital to keep track of this in programs and ensure that conversions between units happen correctly. There is nothing to tell from a numerical value by itself what the units are supposed to be.
A first defence against radian/degree confusion is to include the unit names in the names of variables. Eg, latitudeDegrees = 45. That helps to keep track of what the units are supposed to be at any point in a calculation but it does not ensure that they are in fact correct.
So for taking a cosine you could write
x = cos (toRadians (latitudeDegrees))
and the "Degrees" in the variable name helps you to remember to call the function to convert it to radians first. But it does not guarantee that you will do that. Importantly, the compiler cannot detect such an error because whether the toRadians () function is called or not, the argument to cos () is a number and that's all the compiler requires.
In object-oriented languages there is a better remedy: make angles into objects rather than merely numbers. The class definition for Angle can then contain trigonometrical functions that know what units the angle is in and therefore can always do the right thing:
Angle latitude = new Angle (45.0, DEGREES);
x = latitude.cos ();
Now the conversion to, and use of, appropriate units is hidden inside the class/object. We don't need to know whether internally the value is held in degrees or radians (though for performance in intensive geometrical calculations it probably ought to be radians). Provided that the class has been thoroughly (unit-) tested the kind of mistake we were discussing simply cannot occur. (In the example DEGREES is meant to be a constant - in Java it would be an enum.)
Astronomical quantities such as RA and Dec are angles and so they too should be declared as classes: subclasses of Angle.
In the object-oriented language Java (and as far as I know in all commonly used programming languages) this idea has NOT been adopted in the standard library. A Java class called Math has (static) trigonometrical functions taking angles in radians as their arguments. I contend that a much better basis for astronomical computing should declare Angle as outlined above. Angle uses Math internally but any further geometrical programming should only use objects of class Angle. The application programmer should never directly use Math for trigonometry. Inverse functions should be defined as functions (in Java, static methods) creating new Angle objects:
Angle phi = Angle.atan (x);
A further benefit of using Angle as a class, and therefore as a data type, is that where functions take several parameters which would otherwise just be a list of numbers, it then becomes clear that particular ones are angles. That again reduces errors, of the kind where the parameters are written in the wrong order.

See Also:
Serialized Form

Nested Class Summary
static class Angle.Units
           
 
Field Summary
static char DEGREE_SYMBOL
           
static double FOUR_PI
           
static double TWO_PI
           
protected  MeasuredValue valueRadians
           
 
Constructor Summary
Angle(double value, Angle.Units units)
           
Angle(double value, double stdErr, Angle.Units units)
           
 
Method Summary
static Angle acos(double cos)
          Inverse cosine.
 Angle add(Angle other)
          Returns new Angle which is the sum of the present one and other.
static Maths.Statistics angleStatistics(Angle... angles)
          Calculate the min, max, mean and stdDev (all in degrees) of an array of angles, taking into account periodicity.
static Maths.Statistics angleStatistics(java.util.Collection<Angle> angles)
          Calculate the min, max, mean and stdDev (all in degrees) of a set or list of angles, taking into account periodicity.
static Angle asin(double sin)
          Inverse sine.
static Angle atan(double tan)
          Inverse tangent.
static Angle atan2(double y, double x)
          Inverse tangent.
 Angle clone()
          Returns a new Angle with th same fields.
 int compareTo(Angle other)
          Implements java.lang.Comparable
 double cos()
          Cosine.
 Angle difference(Angle other)
          Similar to subtract but the result is in the range -180..180 degrees.
 boolean equals(java.lang.Object obj)
           
 double getDegrees()
          Get the value in degrees.
 double getHours()
          Get the value in hours.
 double getRadians()
          Get the value in radians.
 double getStdErrDegrees()
          Get the standard error in degrees.
 double getStdErrHours()
          Get the standard error in hours.
 double getStdErrRadians()
          Get the standard error in radians.
 int hashCode()
           
 Angle in360()
          Returns a new Angle whose value lies in range 0..360 degrees (or 0..2pi radians).
 Angle multiply(double factor)
          Returns a new Angle that is the result of multiplying the current one by a factor.
static Angle parseAngle(java.lang.String s)
          Allow all possible formatting of the String.
 double sin()
          Sine.
 Angle subtract(Angle other)
          Returns a new Angle which is the result of subtracting other from this.
 double tan()
          Tangent.
 java.lang.String toString()
          Units are radians.
 java.lang.String toString(Angle.Units requiredUnits)
          Get a String representing the angle in the required units.
 
Methods inherited from class java.lang.Object
finalize, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

TWO_PI

public static final double TWO_PI
See Also:
Constant Field Values

FOUR_PI

public static final double FOUR_PI
See Also:
Constant Field Values

DEGREE_SYMBOL

public static final char DEGREE_SYMBOL
See Also:
Constant Field Values

valueRadians

protected MeasuredValue valueRadians
Constructor Detail

Angle

public Angle(double value,
             Angle.Units units)

Angle

public Angle(double value,
             double stdErr,
             Angle.Units units)
Method Detail

getDegrees

public double getDegrees()
Get the value in degrees.


getHours

public double getHours()
Get the value in hours.


getRadians

public double getRadians()
Get the value in radians.


getStdErrDegrees

public double getStdErrDegrees()
Get the standard error in degrees.


getStdErrHours

public double getStdErrHours()
Get the standard error in hours.


getStdErrRadians

public double getStdErrRadians()
Get the standard error in radians.


parseAngle

public static Angle parseAngle(java.lang.String s)
                        throws java.lang.NumberFormatException
Allow all possible formatting of the String. Eg,
123.45678 (decimal degrees if part before point is less than 10000)
123:27:18.3
-123 27 18.3
123d27m18.3s
+1232718.3 (sexagesimal)
023d27m18.3
2d27m18.3
123 27m18.3 (can be any single non-digit separators between sub-fields)
2:07:04.3
but not 274.3 which would have to be 20704.3 to be unambiguous. Leading sign is allowed.

Throws:
java.lang.NumberFormatException

cos

public double cos()
Cosine.


sin

public double sin()
Sine.


tan

public double tan()
Tangent.


acos

public static Angle acos(double cos)
Inverse cosine.


asin

public static Angle asin(double sin)
Inverse sine.


atan

public static Angle atan(double tan)
Inverse tangent.


atan2

public static Angle atan2(double y,
                          double x)
Inverse tangent.


in360

public Angle in360()
Returns a new Angle whose value lies in range 0..360 degrees (or 0..2pi radians).


add

public Angle add(Angle other)
Returns new Angle which is the sum of the present one and other. Result is not necessarily in the range 0..360 degrees.


subtract

public Angle subtract(Angle other)
Returns a new Angle which is the result of subtracting other from this. Result is not necessarily in the range 0..360 degrees.


multiply

public Angle multiply(double factor)
Returns a new Angle that is the result of multiplying the current one by a factor. Result is not necessarily in the range 0..360 degrees.


difference

public Angle difference(Angle other)
Similar to subtract but the result is in the range -180..180 degrees.


compareTo

public int compareTo(Angle other)
Implements java.lang.Comparable

Specified by:
compareTo in interface java.lang.Comparable<Angle>

angleStatistics

public static Maths.Statistics angleStatistics(java.util.Collection<Angle> angles)
Calculate the min, max, mean and stdDev (all in degrees) of a set or list of angles, taking into account periodicity. Uses Maths.angleDifference () from a working mean of the first angle. Does NOT use the erroneous method you can find on the web that averages sin and cos and then takes atan2.


angleStatistics

public static Maths.Statistics angleStatistics(Angle... angles)
Calculate the min, max, mean and stdDev (all in degrees) of an array of angles, taking into account periodicity. Uses Maths.angleDifference () from a working mean of the first angle. Does NOT use the erroneous method you can find on the web that averages sin and cos and then takes atan2.


clone

public Angle clone()
Returns a new Angle with th same fields.

Overrides:
clone in class java.lang.Object

toString

public java.lang.String toString()
Units are radians.

Overrides:
toString in class java.lang.Object

toString

public java.lang.String toString(Angle.Units requiredUnits)
Get a String representing the angle in the required units.


hashCode

public int hashCode()
Overrides:
hashCode in class java.lang.Object

equals

public boolean equals(java.lang.Object obj)
Overrides:
equals in class java.lang.Object