Feedback

C# - Entfernung, Kurswinkelberechnung geographische Koordinaten

Veröffentlicht von am 20.11.2009
(2 Bewertungen)
Mit diesen 2 Klassen können geographische Koordinaten in Längen- und Breitengraden angelegt werden, desweiteren können Entfernungen zwischen 2 Punkten in KM oder NM errechnet werden sowie der Rechtsweisende Kurswinkel errechnet werden.
GFU-Schulungen  [Anzeige]

Visual Studio Team Foundation Server 2017/2015 (TFS) für Administratoren - Kompakt

Nach dieser Schulung beherrschen Sie die Grundlagen des TFS. Sie erledigen administrative Aufgaben schnell und sicher.

VB.NET Komplett

Sie stehen vo der Aufgabe, individuelle Anwendungen für Windows zu schreiben. Hier ist VB.NET die optimale Sprache. Sie erlernt sich recht leicht und passt sich komplett in die .NET Umgebung von Microsoft ein. Nach der Schulung entwickeln Sie anwenderfreundliche Programme in VB.NET . Mit den objektorientierten Modellen in VB.NET erzeugen Sie außerdem wiederverwendbare Komponenten.

/// <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>&lt;IND&gt;&lt;GRAD&gt;[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
    }
}
Abgelegt unter Geographie, Kurswinkel, Koordinaten.

3 Kommentare zum Snippet

Jörg Dähler schrieb am 10.03.2010:
Hi Sascha, die Kurswinkelberechnung liefert falsche Ergebnisse. Ich hab es nicht weiter untersucht nur festgestellt. Wäre prima wenn du das noch mal überprüfst.

Gruß
Jörg
nasowasauch schrieb am 23.02.2011:
Hallo Sascha,

damit die Kurswinkelberechnung richtige Ergebnisse liefert muss die CourseAngle Funktion folgendermassen aussehen:

public static double CourseAngle( GeoCoordinate c1, GeoCoordinate c2 )
{
double lat1 = GetRAD( c1.m_Latitude.DecGrad );
double lat2 = GetRAD( c2.m_Latitude.DecGrad );
double long1 = GetRAD( c1.m_Longitude.DecGrad );
double long2 = GetRAD( c2.m_Longitude.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( long1 > long2 )
return 360.0 - alpha;
else
return alpha;
}
DimpiM schrieb am 26.05.2014:
Servus miteinander,
die Kursberechnung ist so auch noch nicht ganz richtig.
Laut Wikipedia (http://de.wikipedia.org/wiki/Kurswinkel) muss die Distanz nochmal durch den Erdradius (6378137) geteilt werden...
D.h.

double alpha = GetDEG(Math.Acos(
(Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(CalcDistance(c1, c2) / Double.Parse("6378137"))) /
(Math.Cos(lat1) * Math.Sin(CalcDistance(c1, c2) / Double.Parse("6378137")))));

 

Logge dich ein, um hier zu kommentieren!