Click here to Skip to main content
15,891,864 members
Articles / Programming Languages / C#

GPS Receivers, Geodesy, and Geocaching: Vincenty’s Formula

Rate me:
Please Sign up or sign in to vote.
5.00/5 (21 votes)
9 Jan 2008CPOL5 min read 94.9K   698   79  
Vincenty's Formula is an iterative solution for calculating the distance and direction between two points along the surface of Earth.
/* Gavaghan.Geodesy by Mike Gavaghan
 * 
 * http://www.gavaghan.org/blog/free-source-code/geodesy-library-vincentys-formula/
 * 
 * This code may be freely used and modified on any personal or professional
 * project.  It comes with no warranty.
 */
using System;

namespace Gavaghan.Geodesy
{
  /// <summary>
  /// Encapsulation of an Angle.  Angles are constructed and serialized in
  /// degrees for human convenience, but a conversion to radians is provided
  /// for mathematical calculations.
  /// 
  /// Angle comparisons are performed in absolute terms - no "wrapping" occurs.
  /// In other words, 360 degress != 0 degrees.
  /// </summary>
  [Serializable]
  public struct Angle : IComparable<Angle>
  {
    /// <summary>Degrees/Radians conversion constant.</summary>
    private const double PiOver180 = Math.PI / 180.0;

    /// <summary>Angle value in degrees.</summary>
    private double mDegrees;

    /// <summary>Zero Angle</summary>
    static public readonly Angle Zero = new Angle(0);

    /// <summary>180 degree Angle</summary>
    static public readonly Angle Angle180 = new Angle(180);

    /// <summary>
    /// Construct a new Angle from a degree measurement.
    /// </summary>
    /// <param name="degrees">angle measurement</param>
    public Angle(double degrees)
    {
      mDegrees = degrees;
    }

    /// <summary>
    /// Construct a new Angle from degrees and minutes.
    /// </summary>
    /// <param name="degrees">degree portion of angle measurement</param>
    /// <param name="minutes">minutes portion of angle measurement (0 <= minutes < 60)</param>
    public Angle(int degrees, double minutes)
    {
      mDegrees = minutes / 60.0;

      mDegrees = (degrees < 0) ? (degrees - mDegrees) : (degrees + mDegrees);
    }

    /// <summary>
    /// Construct a new Angle from degrees, minutes, and seconds.
    /// </summary>
    /// <param name="degrees">degree portion of angle measurement</param>
    /// <param name="minutes">minutes portion of angle measurement (0 <= minutes < 60)</param>
    /// <param name="seconds">seconds portion of angle measurement (0 <= seconds < 60)</param>
    public Angle(int degrees, int minutes, double seconds)
    {
      mDegrees = (seconds / 3600.0) + (minutes / 60.0);

      mDegrees = (degrees < 0) ? (degrees - mDegrees) : (degrees + mDegrees);
    }

    /// <summary>
    /// Get/set angle measured in degrees.
    /// </summary>
    public double Degrees
    {
      get { return mDegrees; }
      set { mDegrees = value; }
    }

    /// <summary>
    /// Get/set angle measured in radians.
    /// </summary>
    public double Radians
    {
      get { return mDegrees * PiOver180; }
      set { mDegrees = value / PiOver180; }
    }

    /// <summary>
    /// Get the absolute value of the angle.
    /// </summary>
    public Angle Abs()
    {
      return new Angle(Math.Abs(mDegrees));
    }

    /// <summary>
    /// Compare this angle to another angle.
    /// </summary>
    /// <param name="other">other angle to compare to.</param>
    /// <returns>result according to IComparable contract/></returns>
    public int CompareTo(Angle other)
    {
      return mDegrees.CompareTo(other.mDegrees);
    }

    /// <summary>
    /// Calculate a hash code for the angle.
    /// </summary>
    /// <returns>hash code</returns>
    public override int GetHashCode()
    {
      return (int) (mDegrees * 1000033);
    }

    /// <summary>
    /// Compare this Angle to another Angle for equality.  Angle comparisons
    /// are performed in absolute terms - no "wrapping" occurs.  In other
    /// words, 360 degress != 0 degrees.
    /// </summary>
    /// <param name="obj">object to compare to</param>
    /// <returns>'true' if angles are equal</returns>
    public override bool Equals(object obj)
    {
      if (!(obj is Angle)) return false;

      Angle other = (Angle)obj;

      return mDegrees == other.mDegrees;
    }

    /// <summary>
    /// Get coordinates as a string.
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
      return mDegrees.ToString();
    }

    #region Operators
    public static Angle operator +(Angle lhs, Angle rhs)
    {
      return new Angle(lhs.mDegrees + rhs.mDegrees);
    }

    public static Angle operator -(Angle lhs, Angle rhs)
    {
      return new Angle(lhs.mDegrees - rhs.mDegrees);
    }

    public static bool operator >(Angle lhs, Angle rhs)
    {
      return lhs.mDegrees > rhs.mDegrees;
    }

    public static bool operator >=(Angle lhs, Angle rhs)
    {
      return lhs.mDegrees >= rhs.mDegrees;
    }

    public static bool operator <(Angle lhs, Angle rhs)
    {
      return lhs.mDegrees < rhs.mDegrees;
    }

    public static bool operator <=(Angle lhs, Angle rhs)
    {
      return lhs.mDegrees <= rhs.mDegrees;
    }

    public static bool operator ==(Angle lhs, Angle rhs)
    {
      return lhs.mDegrees == rhs.mDegrees;
    }

    public static bool operator !=(Angle lhs, Angle rhs)
    {
      return lhs.mDegrees != rhs.mDegrees;
    }

    /// <summary>
    /// Imlplicity cast a double as an Angle measured in degrees.
    /// </summary>
    /// <param name="degrees">angle in degrees</param>
    /// <returns>double cast as an Angle</returns>
    public static implicit operator Angle(double degrees)
    {
      return new Angle(degrees);
    }
    #endregion
  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Mike Gavaghan opines on C# and .Net in his blog Talk Nerdy To Me[^]. He is a Microsoft Certified Professional Developer working as a C#/.Net software consultant based in Dallas, Texas.

Since 1992, he has supported clients in diverse businesses including financial services, travel, airlines, and telecom. He has consulted at both mammoth enterprises and small startups (and sees merits and problems in both).

You may also view his profile on LinkedIn[^].

Comments and Discussions