/* * Author: G. Monz (DK7IO), 2016-07-30 * This file is distributed without any warranty. * */ using System; using System.Collections.Generic; namespace ScoutBase.Core { /// /// The position of a geographical coordinate in a rectangle. /// public enum PositionInRectangle { /// /// TopLeft /// TopLeft, /// /// TopMiddle /// TopMiddle, /// /// TopRight /// TopRight, /// /// BottomLeft /// BottomLeft, /// /// BottomMiddle /// BottomMiddle, /// /// BottomRight /// BottomRight, /// /// MiddleLeft /// MiddleLeft, /// /// MiddleRight /// MiddleRight, /// /// MiddleMiddle /// MiddleMiddle, } /// /// The options to format a degree value. /// public enum AngleFormat { /// /// Sign, degrees (at least one integer digit). /// sD, /// /// Sign, degrees (at least two integer digits). /// sDD, /// /// Sign, degrees (at least one integer digit), minutes (at least one integer digit). /// sDM, /// /// Sign, degrees (at least two integer digits), minutes (two integer digits). /// sDDMM, /// /// Sign, degrees (at least one integer digit), minutes (at least one integer digit), seconds (at least one integer digit). /// sDMS, /// /// Sign, degrees (at least two integer digits), minutes (two integer digits), seconds (two integer digits). /// sDDMMSS, } /// /// A representation of a geographical point. /// [Serializable] public class GeographicalPoint { #region Constants #region Earth /// /// Mean Earth radius in km, according WGS84. /// public const double MeanEarthRadius_WGS84 = 6371.0008; #endregion #region Units /// /// The length of a statute mile in kilometres. /// public const double StatuteMilesToKilometres = 1.609344; /// /// The length of a nautical mile in kilometres. /// public const double NauticalMilesToKilometres = 1.852; #endregion #region Coordinate limits /// /// Lower latitude limit. /// public const int LowerLatitudeLimit = -90; /// /// Upper latitude limit. /// public const int UpperLatitudeLimit = +90; /// /// Lower longitude limit. /// public const int LowerLongitudeLimit = -180; /// /// Upper longitude limit. /// public const int UpperLongitudeLimit = +180; #endregion #endregion #region Information texts /// /// Information about an invalid value of the latitude. /// internal static string InvalidLatitudeText = "Invalid value. " + "Allowed interval: [-" + Math.Abs(LowerLatitudeLimit) + "...+" + Math.Abs(UpperLatitudeLimit) + "]"; /// /// Information about an invalid value of the longitude. /// internal static string InvalidLongitudeText = "Invalid value. " + "Allowed interval: [-" + Math.Abs(LowerLongitudeLimit) + "...+" + Math.Abs(UpperLongitudeLimit) + "]"; #endregion double _latitude; /// /// The geographical latitude, in degrees. /// /// /// If the latitude exceeds its allowed interval /// (can occur in setter only). /// public double Latitude { get { return _latitude; } set { CheckLatitude(value); _latitude = value; } } double _longitude; /// /// The geographical longitude, in degrees. /// /// /// If the longitude exceeds its allowed interval /// (can occur in setter only). /// public double Longitude { get { return _longitude; } set { CheckLongitude(value); _longitude = value; } } /// /// The name of the instance. /// public string Name { get; set; } /// /// Creates a new instance. /// Geographical latitude and longitude is 0. /// public GeographicalPoint() { } /// /// Creates a new instance, based on geographical coordinates. /// /// The geographical latitude. /// The geographical longitude. /// If latitude or longitude exceeds its allowed interval. public GeographicalPoint(double latitude, double longitude) : this() { Latitude = latitude; Longitude = longitude; } /// /// Creates a new instance, based on geographical coordinates in degrees and minutes. /// There is no check on the numerical correctness of the arguments. /// /// True if the sign of the latitude is negative. False if positive. /// The degrees of the latitude. /// The minutes of the latitude. /// True if the sign of the longitude is negative. False if positive. /// The degrees of the longitude. /// The minutes of the longitude. /// If the resulting latitude or longitude exceeds its allowed interval. public GeographicalPoint( bool latitudeIsNegative, int latitudeDegrees, double latitudeMinutes, bool longitudeIsNegative, int longitudeDegrees, double longitudeMinutes ) : this() { Latitude = Utilities.GetDegrees(latitudeIsNegative, latitudeDegrees, latitudeMinutes); Longitude = Utilities.GetDegrees(longitudeIsNegative, longitudeDegrees, longitudeMinutes); } /// /// Creates a new instance, based on geographical coordinates in degrees, minutes and seconds. /// There is no check on the numerical correctness of the arguments. /// /// True if the sign of the latitude is negative. False if positive. /// The degrees of the latitude. /// The minutes of the latitude. /// The seconds of the latitude. /// True if the sign of the longitude is negative. False if positive. /// The degrees of the longitude. /// The minutes of the longitude. /// The seconds of the longitude. /// If the resulting latitude or longitude exceeds its allowed interval. public GeographicalPoint( bool latitudeIsNegative, int latitudeDegrees, int latitudeMinutes, double latitudeSeconds, bool longitudeIsNegative, int longitudeDegrees, int longitudeMinutes, double longitudeSeconds ) : this() { Latitude = Utilities.GetDegrees(latitudeIsNegative, latitudeDegrees, latitudeMinutes, latitudeSeconds); Longitude = Utilities.GetDegrees(longitudeIsNegative, longitudeDegrees, longitudeMinutes, longitudeSeconds); } /// /// Creates a new instance, based on a 'Maidenhead Locator'. /// /// The 'Maidenhead Locator'. /// The position of the geographical coordinates in the locator. /// /// If the length of the locator text is null or not an even number. /// If the locator text contains invalid characters. /// public GeographicalPoint(string maidenheadLocator, PositionInRectangle positionInRectangle) : this() { double latitude; double longitude; MaidenheadLocator.LatLonFromLoc(maidenheadLocator, positionInRectangle, out latitude, out longitude); Latitude = latitude; Longitude = longitude; } /// /// Gives a precision sorted list of 'Maidenhead Locators', based on the geographical coordinates. /// /// If true: generate small (if false: big) letters for 'Subsquares', 'Subsubsquare', etc. /// The list of 'Maidenhead Locators'. /// If the latitude or longitude exceeds its allowed interval. public List GetMaidenheadLocators(bool smallLettersForSubsquares) { var result = new List(MaidenheadLocator.MaxPrecision); { for (int precision = MaidenheadLocator.MinPrecision; precision <= MaidenheadLocator.MaxPrecision; precision++) { string maidenheadLocator = GetMaidenheadLocator(smallLettersForSubsquares, precision); result.Add(maidenheadLocator); } } return result; } /// /// Converts the geographical coordinates to a 'Maidenhead Locator'. /// /// If true: generate small (if false: big) letters for 'Subsquares', 'Subsubsquare', etc. /// The precision for conversion, must be >=1 and <=10. /// The 'Maidenhead Locator'. /// If the latitude or longitude exceeds its allowed interval. public string GetMaidenheadLocator(bool smallLettersForSubsquares, int precision) { string result = MaidenheadLocator.LocFromLatLon(Latitude, Longitude, smallLettersForSubsquares, precision); return result; } /// /// Gives a text representation of the instance. /// /// A member. /// The number of decimal places (after decimal point) for the last unit. /// The text between latitude and longitude. /// If true: Use 7 Bit ASCII characters only instead of special characters. /// The text representation. public string ToString( AngleFormat angleFormat, int decimalPlaces, string separator, bool forceAsciiCharacters ) { string result = GetFormattedText(Latitude, angleFormat, decimalPlaces, forceAsciiCharacters) + " N" + separator + GetFormattedText(Longitude, angleFormat, decimalPlaces, forceAsciiCharacters) + " E" ; return result; } /// /// Shifts geographical coordinates within a rectangle. /// /// The geographical latitude. /// The geographical longitude. /// The desired value. /// The rectangle height. /// The rectangle width. internal static void ShiftPositionInRectangle( ref double latitude, ref double longitude, PositionInRectangle positionInRectangle, double height, double width ) { switch (positionInRectangle) { case PositionInRectangle.TopLeft: case PositionInRectangle.TopMiddle: case PositionInRectangle.TopRight: latitude += height; break; } switch (positionInRectangle) { case PositionInRectangle.MiddleLeft: case PositionInRectangle.MiddleMiddle: case PositionInRectangle.MiddleRight: latitude += height / 2; break; } switch (positionInRectangle) { case PositionInRectangle.TopRight: case PositionInRectangle.MiddleRight: case PositionInRectangle.BottomRight: longitude += width; break; } switch (positionInRectangle) { case PositionInRectangle.TopMiddle: case PositionInRectangle.MiddleMiddle: case PositionInRectangle.BottomMiddle: longitude += width / 2; break; } } /// /// Checks geographical coordinates. /// /// The geographical latitude. /// The geographical longitude. /// If latitude or longitude exceeds its allowed interval. public static bool Check(double latitude, double longitude) { return CheckLatitude(latitude) && CheckLongitude(longitude); } /// /// Checks a geographical latitude. /// /// The geographical latitude. /// If the latitude exceeds its allowed interval. public static bool CheckLatitude(double latitude) { return (latitude >= LowerLatitudeLimit) && (latitude <= UpperLatitudeLimit); } /// /// Checks a geographical longitude. /// /// The geographical longitude. /// If the longitude exceeds its allowed interval. public static bool CheckLongitude(double longitude) { return (longitude >= LowerLongitudeLimit) && (longitude <= UpperLongitudeLimit); } #region GetDistance /// /// Calculates the distance to a 'Maidenhead Locator'. /// /// The 'Maidenhead Locator'. /// >The position of the geographical coordinates in the locator. /// The distance in km. /// /// If the length of the locator text is null or not an even number. /// If the locator text contains invalid characters. /// public double GetDistance(string maidenheadLocator, PositionInRectangle positionInRectangle) { GeographicalPoint geographicalPoint = new GeographicalPoint(maidenheadLocator, positionInRectangle); double result = GetDistance(geographicalPoint); return result; } /// /// Calculates the distance to another instance. /// /// The instance. /// The distance in km. /// If the another instance is null. public double GetDistance(GeographicalPoint geographicalPoint) { if (geographicalPoint == null) { throw new ArgumentNullException("geographicalPoint"); } else { double result = GetDistance(geographicalPoint.Latitude, geographicalPoint.Longitude); return result; } } /// /// Calculates the distance to another geographical coordinate. /// /// The latitude of the another geographical coordinate. /// The longitude of the another geographical coordinate. /// The distance in km. public double GetDistance(double latitude, double longitude) { double result = GetDistance( Latitude, Longitude, latitude, longitude ); return result; } /// /// Calculates the distance from a 'Maidenhead Locator' 1 to a 'Maidenhead Locator' 2. /// /// The 'Maidenhead Locator' 1. /// The position of the geographical coordinates in the locator 1. /// The 'Maidenhead Locator' 2. /// >The position of the geographical coordinates in the locator 2. /// The distance in km. /// /// If the length of any locator text is null or not an even number. /// If any locator text contains invalid characters. /// public static double GetDistance( string maidenheadLocator1, PositionInRectangle positionInRectangle1, string maidenheadLocator2, PositionInRectangle positionInRectangle2 ) { var geographicalPoint1 = new GeographicalPoint(maidenheadLocator1, positionInRectangle1); var geographicalPoint2 = new GeographicalPoint(maidenheadLocator2, positionInRectangle2); double result = GetDistance(geographicalPoint1, geographicalPoint2); return result; } /// /// Calculates the distance between two instances. /// /// The 1. /// The 2. /// The distance in km. /// If any of the instances is null. public static double GetDistance( GeographicalPoint geographicalPoint1, GeographicalPoint geographicalPoint2 ) { if (geographicalPoint1 == null) { throw new ArgumentNullException("geographicalPoint1"); } else if (geographicalPoint2 == null) { throw new ArgumentNullException("geographicalPoint2"); } else { double result = GetDistance( geographicalPoint1.Latitude, geographicalPoint1.Longitude, geographicalPoint2.Latitude, geographicalPoint2.Longitude ); return result; } } /// /// Calculates the distance between two geographical coordinates. /// /// The latitude of coordinate 1. /// The longitude of coordinate 1. /// The latitude of coordinate 2. /// The longitude of coordinate 2. /// The distance in km. public static double GetDistance( double latitude1, double longitude1, double latitude2, double longitude2 ) { const double degreeToRadians = Math.PI / 180; double latitude1Radians = latitude1 * degreeToRadians; double longitude1Radians = longitude1 * degreeToRadians; double latitude2Radians = latitude2 * degreeToRadians; double longitude2Radians = longitude2 * degreeToRadians; double cosD = Math.Sin(latitude1Radians) * Math.Sin(latitude2Radians) + Math.Cos(longitude1Radians - longitude2Radians) * Math.Cos(latitude1Radians) * Math.Cos(latitude2Radians) ; double dUnitCircle; { //Limit for use of more precisely formula const double limitArcMinutes = 10.0; if ( Math.Abs(cosD) < Math.Cos(limitArcMinutes / 60.0 * degreeToRadians) ) { //Common formula dUnitCircle = Math.Acos(cosD); } else { //More precisely formula for angles near 0 or 180 degrees, respectively. //Warning: Formula is valid for exactely these cases only! dUnitCircle = Math.Sqrt( Math.Pow( (longitude2Radians - longitude1Radians) * Math.Cos((latitude1Radians + latitude2Radians) / 2), 2 ) + Math.Pow( latitude2Radians - latitude1Radians, 2 ) ); } } double result = dUnitCircle * MeanEarthRadius_WGS84; return result; } #endregion #region GetAzimuth /// /// Calculates the azimuth to a 'Maidenhead Locator'. /// /// The 'Maidenhead Locator'. /// >The position of the geographical coordinates in the locator. /// The azimuth in degrees. /// /// If the length of the locator text is null or not an even number. /// If the locator text contains invalid characters. /// public double GetAzimuth(string maidenheadLocator, PositionInRectangle positionInRectangle) { var geographicalPoint = new GeographicalPoint(maidenheadLocator, positionInRectangle); double result = GetAzimuth(geographicalPoint); return result; } /// /// Calculates the azimuth to another instance. /// /// The instance. /// The azimuth in degrees. /// If the another instance is null. public double GetAzimuth(GeographicalPoint geographicalPoint) { if (geographicalPoint == null) { throw new ArgumentNullException("geographicalPoint"); } else { double result = GetAzimuth(geographicalPoint.Latitude, geographicalPoint.Longitude); return result; } } /// /// Calculates the azimuth to another geographical coordinate. /// /// The latitude of the another geographical coordinate. /// The longitude of the another geographical coordinate. /// The azimuth in degrees. public double GetAzimuth(double latitude, double longitude) { double result = GetAzimuth( Latitude, Longitude, latitude, longitude ); return result; } /// /// Calculates the azimuth from a 'Maidenhead Locator' 1 to a 'Maidenhead Locator' 2. /// /// The 'Maidenhead Locator' 1. /// The position of the geographical coordinates in the locator 1. /// The 'Maidenhead Locator' 2. /// >The position of the geographical coordinates in the locator 2. /// The azimuth in degrees. /// /// If the length of any locator text is null or not an even number. /// If any locator text contains invalid characters. /// public static double GetAzimuth( string maidenheadLocator1, PositionInRectangle positionInRectangle1, string maidenheadLocator2, PositionInRectangle positionInRectangle2 ) { var geographicalPoint1 = new GeographicalPoint(maidenheadLocator1, positionInRectangle1); var geographicalPoint2 = new GeographicalPoint(maidenheadLocator2, positionInRectangle2); double result = GetAzimuth(geographicalPoint1, geographicalPoint2); return result; } /// /// Calculates the azimuth between two instances. /// /// The 1. /// The 2. /// The azimuth in degrees. /// If any of the instances is null. public static double GetAzimuth( GeographicalPoint geographicalPoint1, GeographicalPoint geographicalPoint2 ) { if (geographicalPoint1 == null) { throw new ArgumentNullException("geographicalPoint1"); } else if (geographicalPoint2 == null) { throw new ArgumentNullException("geographicalPoint2"); } else { double result = GetAzimuth( geographicalPoint1.Latitude, geographicalPoint1.Longitude, geographicalPoint2.Latitude, geographicalPoint2.Longitude ); return result; } } /// /// Calculates the azimuth from a geographical coordinate 1 to a geographical coordinate 2. /// /// The latitude of coordinate 1. /// The longitude of coordinate 1. /// The latitude of coordinate 2. /// The longitude of coordinate 2. /// The azimuth in degrees. public static double GetAzimuth( double latitude1, double longitude1, double latitude2, double longitude2 ) { double result; { if ( (latitude1 == latitude2 && longitude1 == longitude2) || (latitude1 == UpperLatitudeLimit && latitude2 == UpperLatitudeLimit) || (latitude1 == LowerLatitudeLimit && latitude2 == LowerLatitudeLimit) ) { result = double.NaN; } else { const double degreeToRadians = Math.PI / 180; double latitude1Radians = latitude1 * degreeToRadians; double longitude1Radians = longitude1 * degreeToRadians; double latitude2Radians = latitude2 * degreeToRadians; double longitude2Radians = longitude2 * degreeToRadians; double x = Math.Cos(latitude1Radians) * Math.Sin(latitude2Radians) - Math.Sin(latitude1Radians) * Math.Cos(latitude2Radians) * Math.Cos(longitude2Radians - longitude1Radians); double y = Math.Cos(latitude2Radians) * Math.Sin(longitude2Radians - longitude1Radians); double z = Math.Atan2(y, x); if (z < 0) { z += 2 * Math.PI; } result = z / degreeToRadians; } } return result; } #endregion #region GetWaypointProjection /// /// Gets a waypoint projection, based on a azimuth and a distance, respectively. /// /// The azimuth in degrees [0...360). /// The distance in km. /// The waypoint projection as a instance. /// If the azimuth exceeds its allowed interval. public GeographicalPoint GetWaypointProjection( double azimuth, double distance ) { var geographicalPoint = new GeographicalPoint(Latitude, Longitude); var result = GetWaypointProjection( geographicalPoint, azimuth, distance ); return result; } /// /// Gets a waypoint projection, based on a 'Maidenhead Locator', /// a azimuth and a distance, respectively. /// /// The 'Maidenhead Locator'. /// The position of the geographical coordinates in the locator. /// The azimuth in degrees [0...360). /// The distance in km. /// The waypoint projection as a instance. /// /// If the length of the locator text is null or not an even number. /// If the locator text contains invalid characters. /// /// If the azimuth exceeds its allowed interval. public static GeographicalPoint GetWaypointProjection( string maidenheadLocator, PositionInRectangle positionInRectangle, double azimuth, double distance ) { var geographicalPoint = new GeographicalPoint(maidenheadLocator, positionInRectangle); var result = GetWaypointProjection( geographicalPoint, azimuth, distance ); return result; } /// /// Gets a waypoint projection, based on a geographical coordinate, /// a azimuth and a distance, respectively. /// /// The latitude of the geographical coordinate. /// The longitude of the geographical coordinate. /// The azimuth in degrees [0...360). /// The distance in km. /// The waypoint projection as a instance. /// If the azimuth exceeds its allowed interval. public static GeographicalPoint GetWaypointProjection( double latitude, double longitude, double azimuth, double distance ) { var geographicalPoint = new GeographicalPoint(latitude, longitude); var result = GetWaypointProjection( geographicalPoint, azimuth, distance ); return result; } /// /// Gets a waypoint projection, based on a instance, /// a azimuth and a distance, respectively. /// /// The instance. /// The azimuth in degrees [0...360). /// The distance in km. /// The waypoint projection as a instance. /// If the instance is null. /// If the azimuth exceeds its allowed interval. public static GeographicalPoint GetWaypointProjection( GeographicalPoint geographicalPoint, double azimuth, double distance ) { if (geographicalPoint == null) { throw new ArgumentNullException("geographicalPoint"); } else if (azimuth < 0 || azimuth >= 360) { throw new ArgumentException("Allowed interval: [0...360)", "azimuth"); } else { const double degreeToRadians = Math.PI / 180; double latitude1 = geographicalPoint.Latitude; double longitude1 = geographicalPoint.Longitude; double c = distance / MeanEarthRadius_WGS84; double a = Math.Acos( Math.Sin(latitude1 * degreeToRadians) * Math.Cos(c) + Math.Cos(latitude1 * degreeToRadians) * Math.Sin(c) * Math.Cos(azimuth * degreeToRadians) ); double gamma = Math.Acos( (Math.Cos(c) - Math.Cos(a) * Math.Sin(latitude1 * degreeToRadians)) / (Math.Sin(a) * Math.Cos(latitude1 * degreeToRadians)) ); double latitude2 = Math.PI / 2 - a; double longitude2 = longitude1 * degreeToRadians; if (!double.IsNaN(gamma)) { if (azimuth * degreeToRadians < Math.PI) { longitude2 += gamma; } else if (azimuth * degreeToRadians > Math.PI) { longitude2 -= gamma; } } var result = new GeographicalPoint( latitude2 / degreeToRadians, longitude2 / degreeToRadians); return result; } } #endregion /// /// Retrieves the symbol for a mathematical sign. /// /// True if the sign is negative. False if positive. /// The symbol. public static string GetSignSymbol(bool isNegative) { string result = isNegative ? "-" : "+"; return result; } /// /// Retrieves a formatted text for a degree value /// according to a given angle format. /// /// The degree value (with decimal places). /// A member. /// The number of decimal places (after decimal point) for the last unit. /// If true: Use 7 Bit ASCII characters only instead of special characters. /// The formatted text. public static string GetFormattedText(double decDegrees, AngleFormat angleFormat, int decimalPlaces, bool forceAsciiCharacters) { string degreeSymbol, minuteSymbol, secondsSymbol; if (forceAsciiCharacters) { degreeSymbol = "d"; minuteSymbol = "'"; secondsSymbol = "\""; } else { degreeSymbol = "\x00B0".ToString(); //DEGREE SIGN minuteSymbol = "\x2032".ToString(); //PRIME secondsSymbol = "\x2033".ToString(); //DOUBLE PRIME } string separator = " "; string result; switch (angleFormat) { case AngleFormat.sD: { bool isNegative; double degrees; Utilities.DegreesToD(decDegrees, out isNegative, out degrees); result = GetSignSymbol(isNegative) + string.Format(Utilities.GetFormatString(1, decimalPlaces), degrees) + degreeSymbol ; } break; case AngleFormat.sDD: { bool isNegative; double degrees; Utilities.DegreesToD(decDegrees, out isNegative, out degrees); result = GetSignSymbol(isNegative) + string.Format(Utilities.GetFormatString(2, decimalPlaces), degrees) + degreeSymbol ; } break; case AngleFormat.sDM: { bool isNegative; int degrees; double minutes; Utilities.DegreesToDM(decDegrees, out isNegative, out degrees, out minutes); Utilities.Round(decimalPlaces, ref degrees, ref minutes); result = GetSignSymbol(isNegative) + string.Format(Utilities.GetFormatString(1, 0), degrees) + degreeSymbol + separator + string.Format(Utilities.GetFormatString(1, decimalPlaces), minutes) + minuteSymbol ; } break; case AngleFormat.sDDMM: { bool isNegative; int degrees; double minutes; Utilities.DegreesToDM(decDegrees, out isNegative, out degrees, out minutes); Utilities.Round(decimalPlaces, ref degrees, ref minutes); result = GetSignSymbol(isNegative) + string.Format(Utilities.GetFormatString(2, 0), degrees) + degreeSymbol + separator + string.Format(Utilities.GetFormatString(2, decimalPlaces), minutes) + minuteSymbol ; } break; case AngleFormat.sDMS: { bool isNegative; int degrees; int minutes; double seconds; Utilities.DegreesToDMS(decDegrees, out isNegative, out degrees, out minutes, out seconds); Utilities.Round(decimalPlaces, ref degrees, ref minutes, ref seconds); result = GetSignSymbol(isNegative) + string.Format(Utilities.GetFormatString(1, 0), degrees) + degreeSymbol + separator + string.Format(Utilities.GetFormatString(1, 0), minutes) + minuteSymbol + separator + string.Format(Utilities.GetFormatString(1, decimalPlaces), seconds) + secondsSymbol ; } break; case AngleFormat.sDDMMSS: { bool isNegative; int degrees; int minutes; double seconds; Utilities.DegreesToDMS(decDegrees, out isNegative, out degrees, out minutes, out seconds); Utilities.Round(decimalPlaces, ref degrees, ref minutes, ref seconds); result = GetSignSymbol(isNegative) + string.Format(Utilities.GetFormatString(2, 0), degrees) + degreeSymbol + separator + string.Format(Utilities.GetFormatString(2, 0), minutes) + minuteSymbol + separator + string.Format(Utilities.GetFormatString(2, decimalPlaces), seconds) + secondsSymbol ; } break; default: throw new NotSupportedException(angleFormat.ToString()); } return result; } /// /// Checks if two given locations (by GeographicalPoint) are equal /// /// The 1st location. /// The 2nd location. /// True if the given locations are equal . public static bool IsEqual(GeographicalPoint point1, GeographicalPoint point2) { return IsEqual(point1.Latitude, point1.Longitude, point2.Latitude, point2.Longitude); } /// /// Checks if two given locations (by lat/lon) are equal /// /// The geographic latitude of 1st location. /// The geographic longitude of 1st location. /// The geographic latitude of 2nd location. /// The geographic longitude of 2nd location. /// True if the given locations are equal . public static bool IsEqual(double latitude1, double longitude1, double latitude2, double longitude2) { if ((latitude1 == double.NaN) || (longitude1 == double.NaN) || (latitude2 == double.NaN) || (longitude2 == double.NaN)) return false; return (Math.Abs(latitude1 - latitude2) < 0.00001) && (Math.Abs(longitude1 - longitude2) < 0.00001); } /// /// Gives a new List instance for a single instance. /// /// The instance. /// The new List instance. public static IEnumerable GetNewList(GeographicalPoint geographicalPoint) { var result = new List(); if (geographicalPoint != null) { result.Add(geographicalPoint); } return result; } } }