//
//Angle class   --   copyright 2001, Information Disciplines, Inc.

//  This class supports operations on plane angles.

public class Angle{
  double  value;                 //  normalized radians
 

//  For compatibility with the Java Math library and other software,
//  range is (-pi,pi] not [0,2pi), enforced by the following function:  

  void normalize()
    {final double twoPi = Math.PI + Math.PI;          
     while (value <= -Math.PI) value += twoPi;
     while (value >   Math.PI) value -= twoPi;
    }     


//  Constructors
//  ------------

public  Angle(final double rad)  {value = rad; normalize();}
public  Angle()                  {this(0.0);}
public  Angle(final Angle theta) {this(theta.value);}

public  Angle(final int deg, //  Degrees, minutes, seconds
              final int min, //    (Signs should agree
              final int sec) //       for conventional notation.)
      {double seconds = sec + 60 * (min + 60 * deg);
              value = seconds * Math.PI / 648000.0;
              normalize(); 
      }
public  Angle(final int deg, final int min) {this(deg,min,0);}


//  Accessors
//  ---------
 
 public double toDegrees()  {return  180.0 * (value / Math.PI);}
 public double toRadians()  {return  value;}

//  If the following functions are used often, performance can be improved
//  by caching the results -- See IDI Date class for example.

 public short  degrees() {return  (short)(toDegrees());}
 public short  minutes()
        {long result = ((long)(Math.abs(toDegrees()) * 60.0) % 60);
              return (short) (value >=0 ? result : -result);
        }
 public short  seconds()
        {long result = ((long)(Math.round(Math.abs(toDegrees()) * 3600.0)) % 60);
              return (short) (value >=0 ? result : -result);
        }

       
//  Trigonometric functions (for notational consistency and to hide internal 
//  -----------------------  representation.  User can use other old functions
//                           by extracting value with  toRadians() accessor)

  public double cos()          {return Math.cos (value);}
  public double sin()          {return Math.sin (value);}
  public double tan()          {return Math.tan (value);}

  public static Angle  arccos(final double x) {return new Angle(Math.acos(x));}
  public static Angle  arcsin(final double x) {return new Angle(Math.asin(x));}
  public static Angle  arctan(final double y, 
                       final double x)    {return new Angle(Math.atan2(y,x));}
  public static Angle  arctan(final double y) {return new Angle(arctan(y,1.0));}




//  Conversion functions
//  --------------------
 public String toString()  
        {final String degreeSymbol = "\370";       
         return (value < 0 ? "-" : "")
              + Math.abs(degrees()) + degreeSymbol
              + Math.abs(minutes()) + '\''
              + Math.abs(seconds()) + '\"';}
 

//  Relational operators
//  --------------------
//  WARNING:  Floating point equality test is undependable
//            Ordering is ambiguous and not transitive, due to normalization.

 public boolean equals(final Angle rs)         {return value == rs.value;}

 public boolean lessThan(final Angle rs)       {return value  < rs.value;}
 public boolean greaterThan(final Angle rs)    {return value  > rs.value;}



//  Operators follow the standard additive pattern
//  ---------

 public Angle addSet(final Angle rs) 
                      {value+=rs.value; normalize(); return this;}
 public Angle subSet (final Angle rs) 
                      {value-=rs.value; normalize(); return this;}
 public Angle mpySet(final double rs) 
                      {value*=rs;       normalize(); return this;}
 public Angle  divSet (final double rs) 
                      {value/=rs;       normalize(); return this;}

 public Angle  minus ()                {return new Angle(-value);}

 public Angle  add(final Angle  rs) {return new Angle(this).addSet(rs);}
 public Angle  sub(final Angle  rs) {return new Angle(this).subSet(rs);}
 public Angle  mpy(final double rs) {return new Angle(this).mpySet(rs);}
 public Angle  div(final double rs) {return new Angle(this).divSet(rs);}
 public double div(final Angle rs)  {return value / rs.value;}


//  The following two functions support standard Java contracts, but are
//  not necessary, since easier-to-use equivalents appear above.

 public boolean equals(final Object rs)
                {return rs instanceof Angle && value ==((Angle) rs).value;}
 public int     compareTo(Object obj)
                {Angle theta = (Angle) obj;
                 return  lessThan(theta)  ? -1
                   :  greaterThan(theta)  ?  1
                   :                         0;
                }
}
//