/// <summary>
/// Eine Geokoordinate aus Längen- und Breitengrad
/// </summary>
public class GeoCoordinate
{
private GeoPoint m_Latitude;
private GeoPoint m_Longitude;
public const double EARTHRADIUSKM = 6378.137;
public const double NMFACTOR = 1.852216;
public const double EARTHRADIUSNM = EARTHRADIUSKM / NMFACTOR;
public const double EARTHPLATTUNG = 1.0 / 298.257223563;
#region Constructor
/// <summary>
/// Erstellt eine neue Geokoordinate mit den angegebenen Koordinaten
/// </summary>
/// <param name="latitude">Breitengrad in Dezimalgrad</param>
/// <param name="longitude">Längengrad in Dezimalgrad</param>
public GeoCoordinate( double latitude, double longitude )
{
m_Latitude = new GeoPoint( latitude < 0 ? "S" : "N", latitude );
m_Longitude = new GeoPoint( longitude < 0 ? "E" : "W", longitude );
}
/// <summary>
/// Erstellt eine neue Geokoordinate aus den angegebenen GeoPoints
/// </summary>
/// <param name="latitude">Breitengrad</param>
/// <param name="longitude">Längengrad</param>
public GeoCoordinate( GeoPoint latitude, GeoPoint longitude )
{
if( latitude.Indicator != "N" && latitude.Indicator != "S" )
throw new ArgumentException( "Latitude must be N or S!" );
if( longitude.Indicator != "W" && longitude.Indicator != "E" )
throw new ArgumentException( "Longitude must be W or E!" );
m_Latitude = latitude;
m_Longitude = longitude;
}
#endregion
#region Static Methods
/// <summary>
/// Berechnet die Länge des Orthodroms zwischen zwei Punkten
/// </summary>
/// <remarks>Versucht eine Berechnung nach WGS84</remarks>
/// <param name="c1">Erster Punkt</param>
/// <param name="c2">Zweiter Punkt</param>
/// <returns>Entfernung in Kilometern</returns>
public static double DistanceKM( GeoCoordinate c1, GeoCoordinate c2 )
{
double dist = 0.0;
try
{
dist = CalcDistanceWGS84( c1, c2, EARTHRADIUSKM );
}
catch( Exception ex )
{
dist = CalcDistance( c1, c2 ) * EARTHRADIUSKM;
}
return dist;
}
/// <summary>
/// Berechnet die Länge des Orthodroms zwischen zwei Punkten
/// </summary>
/// <remarks>Versucht eine Berechnung nach WGS84</remarks>
/// <param name="c1">Erster Punkt</param>
/// <param name="c2">Zweiter Punkt</param>
/// <returns>Entfernung in nautischen Meilen</returns>
public static double DistanceNM( GeoCoordinate c1, GeoCoordinate c2 )
{
double dist = 0.0;
try
{
dist = CalcDistanceWGS84( c1, c2, EARTHRADIUSKM ) / NMFACTOR;
}
catch( Exception ex )
{
dist = CalcDistance( c1, c2 ) * EARTHRADIUSNM;
}
return dist;
}
/// <summary>
/// Berechnet den Kurswinkel zwischen zwei Punkten
/// </summary>
/// <param name="c1">Erster Punkt</param>
/// <param name="c2">Zweiter Punkt</param>
/// <returns>Kurswinkel in Grad (Rechtsweisend)</returns>
public static double CourseAngle( GeoCoordinate c1, GeoCoordinate c2 )
{
double lat1 = GetRAD( c1.m_Latitude.DecGrad );
double lat2 = GetRAD( c2.m_Latitude.DecGrad );
double alpha = GetDEG( Math.Acos(
( Math.Sin( lat2 ) - Math.Sin( lat1 ) * Math.Cos( CalcDistance( c1, c2 ) ) ) /
( Math.Cos( lat1 ) * Math.Sin( CalcDistance( c1, c2 ) ) ) ) );
if( lat1 > lat2 )
return 360.0 - alpha;
else
return alpha;
}
#region Static Helper
private static double CalcDistance( GeoCoordinate c1, GeoCoordinate c2 )
{
double lat1 = GetRAD( c1.m_Latitude.DecGrad );
double lat2 = GetRAD( c2.m_Latitude.DecGrad );
double lon1 = GetRAD( c1.m_Longitude.DecGrad );
double lon2 = GetRAD( c2.m_Longitude.DecGrad );
return Math.Acos(
Math.Sin( lat1 ) * Math.Sin( lat2 ) +
Math.Cos( lat1 ) * Math.Cos( lat2 ) * Math.Cos( lon2 - lon1 ) );
}
private static double CalcDistanceWGS84( GeoCoordinate c1, GeoCoordinate c2, double earthRadius )
{
double lat1 = c1.m_Latitude.DecGrad;
double lat2 = c2.m_Latitude.DecGrad;
double lon1 = c1.m_Longitude.DecGrad;
double lon2 = c2.m_Longitude.DecGrad;
double F = GetRAD( ( lat1 + lat2 ) / 2.0 );
double G = GetRAD( ( lat1 - lat2 ) / 2.0 );
double l = GetRAD( ( lon1 - lon2 ) / 2.0 );
double S = ( Math.Pow( Math.Sin( G ), 2 ) * Math.Pow( Math.Cos( l ), 2 ) ) +
( Math.Pow( Math.Cos( F ), 2 ) * Math.Pow( Math.Sin( l ), 2 ) );
double C = ( Math.Pow( Math.Cos( G ), 2 ) * Math.Pow( Math.Cos( l ), 2 ) ) +
( Math.Pow( Math.Sin( F ), 2 ) * Math.Pow( Math.Sin( l ), 2 ) );
double w = Math.Atan( Math.Sqrt( S / C ) );
double D = 2 * w * earthRadius;
double R = ( Math.Sqrt( S * C ) ) / w;
double H1 = ( 3 * R - 1 ) / ( 2 * C );
double H2 = ( 3 * R + 1 ) / ( 2 * S );
return D * (
1 + EARTHPLATTUNG * H1 * Math.Pow( Math.Sin( F ), 2 ) * Math.Pow( Math.Cos( G ), 2 ) -
EARTHPLATTUNG * H2 * Math.Pow( Math.Cos( F ), 2 ) * Math.Pow( Math.Sin( G ), 2 ) );
}
private static double GetRAD( double deg )
{
return deg / 180.0 * Math.PI;
}
private static double GetDEG( double rad )
{
return rad * 180.0 / Math.PI;
}
#endregion
#endregion
#region Class Methods
/// <summary>
/// Berechnet die Länge des Orthodroms zwischen diesem und einem anderen Punkt
/// </summary>
/// <remarks>Versucht eine Berechnung nach WGS84</remarks>
/// <param name="c1">Erster Punkt</param>
/// <returns>Entfernung in Kilometern</returns>
/// <seealso cref="GeoCoordinate.DistanceKM"/>
public double DistanceKM( GeoCoordinate c1 )
{
return GeoCoordinate.DistanceKM( this, c1 );
}
/// <summary>
/// Berechnet die Länge des Orthodroms zwischen diesem und einem anderen Punkt
/// </summary>
/// <remarks>Versucht eine Berechnung nach WGS84</remarks>
/// <param name="c1">Erster Punkt</param>
/// <returns>Entfernung in nautischen Meilen</returns>
/// <seealso cref="GeoCoordinate.DistanceNM"/>
public double DistanceNM( GeoCoordinate c1 )
{
return GeoCoordinate.DistanceNM( this, c1 );
}
/// <summary>
/// Berechnet den Kurswinkel zwischen diesem und einem anderen Punkt
/// </summary>
/// <param name="c1">Erster Punkt</param>
/// <returns>Kurswinkel in Grad (Rechtsweisend)</returns>
/// <seealso cref="GeoCoordinate.CourseAngle" />
public double CourseAngle( GeoCoordinate c1 )
{
return GeoCoordinate.CourseAngle( this, c1 );
}
#endregion
#region Overridden Methods
public override string ToString()
{
return m_Latitude.ToString() + " " + m_Longitude.ToString();
}
#endregion
/// <summary>
/// Ein Koordinatenpunkt in Grad, Minuten und Sekunden
/// </summary>
public class GeoPoint
{
#region Fields
private string m_Indicator;
private double m_Decimal;
#endregion
#region Properties
/// <summary>
/// Dezimale Repräsentation des Punktes
/// </summary>
public double DecGrad
{
get
{
return m_Decimal;
}
}
/// <summary>
/// Indikator, ob N/S bzw. W/E
/// </summary>
public string Indicator
{
get
{
return m_Indicator;
}
}
/// <summary>
/// Die vollen Grad des Koordinatenpunktes
/// </summary>
public int Grad
{
get
{
return Convert.ToInt32( Math.Floor( Math.Abs( m_Decimal ) ) );
}
}
/// <summary>
/// Die Minuten des Koordinatenpunktes
/// </summary>
public int Minute
{
get
{
double calc = Math.Abs( m_Decimal );
calc -= Math.Floor( calc );
return Convert.ToInt32( Math.Floor( calc * 60.0 ) );
}
}
/// <summary>
/// Die Dezimalsekunden des Koordinatenpunktes
/// </summary>
public double Sekunde
{
get
{
double calc = Math.Abs( m_Decimal );
calc -= Math.Floor( calc );
calc -= ( Math.Floor( calc * 60.0 ) / 60.0 );
return Math.Round( calc * 3600.0, 2 );
}
}
#endregion
#region Constructors
/// <summary>
/// Erstellt einen Koordinatenpunkt auf der angegebenen Halbkugel aus Dezimalgrad
/// </summary>
/// <param name="indicator">N/S oder W/E</param>
/// <param name="decGrad">Koordinate in Dezimalgrad</param>
public GeoPoint( string indicator, double decGrad )
{
m_Indicator = indicator;
m_Decimal = Math.Abs( decGrad );
switch( indicator )
{
case "S":
case "E":
m_Decimal *= -1.0;
break;
}
}
/// <summary>
/// Erstellt einen Koordinatenpunkt auf der angebenen Halbkugel aus einer Gradangabe
/// </summary>
/// <param name="indicator">N/S oder W/E</param>
/// <param name="grad">Die vollen Grad</param>
/// <param name="minute">Minuten</param>
/// <param name="sekunde">Dezimalsekunden</param>
public GeoPoint( string indicator, int grad, int minute, double sekunde )
{
InitByGrad( indicator, grad, minute, sekunde );
}
/// <summary>
/// Erstellt einen Koordinatenpunkt aus einem String
/// </summary>
/// <param name="point">
/// <para>String in folgendem Format:</para>
/// <para><IND><GRAD>[MINUTE][SEKUNDEN]</para>
/// <para>IND: N/S/W/E (ein Zeichen)</para>
/// <para>GRAD: Grad (2 stellig)</para>
/// <para>MINUTE: Minuten(2 stellig)</para>
/// <para>SEKUNDE: Sekunden(2...n stellig, ohne Komma)</para>
/// <para></para><para>Beispiel: N6044122323</para>
/// </param>
public GeoPoint( string point )
{
string indicator = "";
int grad = 0;
int minute = 0;
double sekunde = 0.0;
if( point[ 0 ] != 'N' && point[ 0 ] != 'S' && point[ 0 ] != 'W' && point[ 0 ] != 'E' )
throw new ArgumentException( "String must start with N,S,W or E" );
indicator = point.Substring( 0, 1 );
if( point.Length == 3 )
grad = Int32.Parse( point.Substring( 1, 2 ) );
if( point.Length == 5 )
{
grad = Int32.Parse( point.Substring( 1, 2 ) );
minute = Int32.Parse( point.Substring( 3, 2 ) );
}
if( point.Length > 6 )
{
grad = Int32.Parse( point.Substring( 1, 2 ) );
minute = Int32.Parse( point.Substring( 3, 2 ) );
string sekString = point.Substring( 5 );
sekunde = Double.Parse( sekString.Substring( 0, 2 ) );
if( sekString.Length > 2 )
sekunde += Double.Parse( "0," + sekString.Substring( 2 ) );
}
InitByGrad( indicator, grad, minute, sekunde );
}
#endregion
#region Private Helper
private void InitByGrad( string indicator, int grad, int minute, double sekunde )
{
m_Indicator = indicator;
if( indicator != "N" && indicator != "S" && indicator != "W" && indicator != "E" )
throw new ArgumentException( "LOC must be N,S,W or E" );
m_Decimal = grad + ( minute / 60.0 ) + ( sekunde / 3600.0 );
switch( indicator )
{
case "S":
case "E":
m_Decimal *= -1.0;
break;
}
}
#endregion
#region Overriden Methods
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append( m_Indicator + " " );
sb.Append( Grad + "° " );
sb.Append( Minute + "' " );
sb.Append( Sekunde + "''" );
return sb.ToString();
}
#endregion
}
}