/// <summary> /// Calculates destination point given distance and bearing from start point. /// </summary> /// <param name="Bearing">Initial GPS bearing in degrees to the destination point. The valid range of values is [0, 360). See Bearing* constants.</param> /// <param name="Distance">Distance in metres between the start point and the destination point.</param> /// <returns>GPS location of the destination point.</returns> /// <remarks>Formula source: http://www.movable-type.co.uk/scripts/latlong.html .</remarks> public GpsLocation GoVector(double Bearing, double Distance) { double lat1 = (double)Latitude; double lon1 = (double)Longitude; double lat1Rad = lat1.ToRadians(); double lon1Rad = lon1.ToRadians(); double brnRad = Bearing.ToRadians(); // Formula: // φ2 = asin(sin φ1 ⋅ cos δ + cos φ1 ⋅ sin δ ⋅ cos θ) // λ2 = λ1 + atan2(sin θ ⋅ sin δ ⋅ cos φ1, cos δ − sin φ1 ⋅ sin φ2) // where φ is latitude, λ is longitude, θ is the bearing(clockwise from north), δ is the angular distance d / R; d being the distance travelled, R the earth’s radius double lat2Rad = Math.Asin(Math.Sin(lat1Rad) * Math.Cos(Distance / EarthRadius) + Math.Cos(lat1Rad) * Math.Sin(Distance / EarthRadius) * Math.Cos(brnRad)); double lon2Rad = lon1Rad + Math.Atan2(Math.Sin(brnRad) * Math.Sin(Distance / EarthRadius) * Math.Cos(lat1Rad), Math.Cos(Distance / EarthRadius) - Math.Sin(lat1Rad) * Math.Sin(lat2Rad)); double lat2 = lat2Rad.ToDegrees(); double lon2 = lon2Rad.ToDegrees(); // Normalize longitude. lon2 = (lon2 + 540.0) % 360.0 - 180.0; if (lon2 == -180.0) { lon2 = 180.0; } GpsLocation res = new GpsLocation((decimal)lat2, (decimal)lon2); return(res); }
/// <summary> /// Calculates distance to another location in metres using Haversine formula. /// </summary> /// <param name="TargetLocation">Target location to which the distance is calculated.</param> /// <returns>Distance from this location to the target location in metres.</returns> /// <remarks>Formula source: http://www.movable-type.co.uk/scripts/latlong.html .</remarks> public double DistanceTo(GpsLocation TargetLocation) { double lat1 = (double)Latitude; double lon1 = (double)Longitude; double lat2 = (double)TargetLocation.Latitude; double lon2 = (double)TargetLocation.Longitude; // Haversine formula: // a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2) // c = 2 ⋅ atan2(√a, √(1−a)) // d = R ⋅ c // where φ is latitude, λ is longitude, R is earth’s radius (mean radius = 6,371 km). double lat1Rad = lat1.ToRadians(); double lat2Rad = lat2.ToRadians(); double latDiffRad = (lat2 - lat1).ToRadians(); double lonDiffRad = (lon2 - lon1).ToRadians(); double a = Math.Sin(latDiffRad / 2) * Math.Sin(latDiffRad / 2) + Math.Cos(lat1Rad) * Math.Cos(lat2Rad) * Math.Sin(lonDiffRad / 2) * Math.Sin(lonDiffRad / 2); double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); double res = EarthRadius * c; return(res); }
/// <summary> /// Calculates final bearing from the start point to the destination point. /// </summary> /// <param name="Destination">Destination location.</param> /// <returns>Final bearing from the start point to the destination point.</returns> /// <remarks>Formula source: http://www.movable-type.co.uk/scripts/latlong.html .</remarks> public double FinalBearingTo(GpsLocation Destination) { // For final bearing, simply take the initial bearing from the end point to the start point and reverse it (using θ = (θ+180) % 360). double reverseBrng = Destination.InitialBearingTo(this); double res = (reverseBrng + 180.0) % 360.0; return(res); }
public override bool Equals(object obj) { if (!(obj is GpsLocation)) { return(false); } GpsLocation val = (GpsLocation)obj; return(Latitude.Equals(val.Latitude) && Longitude.Equals(val.Longitude)); }
/// <summary> /// Calculates GPS square from the given centre location using a radius. /// </summary> /// <param name="Radius">Half of a distance between oposite sides.</param> public GpsSquare(GpsLocation Centre, double Radius) { // We calculate positions of square mid points of top and bottom sides - i.e. points in the center of square sides. MidTop = Centre.GoVector(GpsLocation.BearingNorth, Radius); MidBottom = Centre.GoVector(GpsLocation.BearingSouth, Radius); // From these mid points, we navigate use West and East bearing to go to the square corners. LeftTop = MidTop.GoVector(GpsLocation.BearingWest, Radius); RightTop = MidTop.GoVector(GpsLocation.BearingEast, Radius); LeftBottom = MidBottom.GoVector(GpsLocation.BearingWest, Radius); RightBottom = MidBottom.GoVector(GpsLocation.BearingEast, Radius); }
/// <summary> /// Basic square constructor. /// </summary> /// <param name="LeftTop">Location of the left-top corner of the square.</param> /// <param name="RightTop">Location of the right-top corner of the square.</param> /// <param name="LeftBottom">Location of the left-bottom corner of the square.</param> /// <param name="RightBottom">Location of the right-bottom corner of the square.</param> public GpsSquare(GpsLocation LeftTop, GpsLocation RightTop, GpsLocation LeftBottom, GpsLocation RightBottom) { this.LeftTop = LeftTop; this.RightTop = RightTop; this.LeftBottom = LeftBottom; this.RightBottom = RightBottom; double bearing = LeftTop.InitialBearingTo(RightTop); double distance = LeftTop.DistanceTo(RightTop) / 2; MidTop = LeftTop.GoVector(bearing, distance); bearing = LeftBottom.InitialBearingTo(RightBottom); distance = LeftBottom.DistanceTo(RightBottom) / 2; MidBottom = LeftBottom.GoVector(bearing, distance); }
/// <summary> /// Calculates GPS square from the given centre location using a radius. /// </summary> /// <param name="Radius">Half of a distance between oposite sides.</param> /// <returns></returns> public GpsSquare GetSquare(double Radius) { // We calculate positions of square mid points of top and bottom sides - i.e. points in the center of square sides. GpsLocation midTop = GoVector(BearingNorth, Radius); GpsLocation midBottom = GoVector(BearingSouth, Radius); // From these mid points, we navigate use West and East bearing to go to the square corners. GpsLocation leftTop = midTop.GoVector(BearingWest, Radius); GpsLocation rightTop = midTop.GoVector(BearingEast, Radius); GpsLocation leftBottom = midBottom.GoVector(BearingWest, Radius); GpsLocation rightBottom = midBottom.GoVector(BearingEast, Radius); GpsSquare res = new GpsSquare(leftTop, rightTop, leftBottom, rightBottom); return(res); }
/// <summary> /// Calculates initial bearing from the start point to the destination point. /// </summary> /// <param name="Destination">Destination location.</param> /// <returns>Initial bearing from the start point to the destination point.</returns> /// <remarks>Formula source: http://www.movable-type.co.uk/scripts/latlong.html .</remarks> public double InitialBearingTo(GpsLocation Destination) { double lat1 = (double)Latitude; double lon1 = (double)Longitude; double lat2 = (double)Destination.Latitude; double lon2 = (double)Destination.Longitude; double lat1Rad = lat1.ToRadians(); double lon1Rad = lon1.ToRadians(); double lat2Rad = lat2.ToRadians(); double lon2Rad = lon2.ToRadians(); // Formula: θ = atan2(sin Δλ ⋅ cos φ2 , cos φ1 ⋅ sin φ2 − sin φ1 ⋅ cos φ2 ⋅ cos Δλ) // where φ1, λ1 is the start point, φ2, λ2 the end point(Δλ is the difference in longitude) double y = Math.Sin(lon2Rad - lon1Rad) * Math.Cos(lat2Rad); double x = Math.Cos(lat1Rad) * Math.Sin(lat2Rad) - Math.Sin(lat1Rad) * Math.Cos(lat2Rad) * Math.Cos(lon2Rad - lon1Rad); double res = Math.Atan2(y, x).ToDegrees(); // Normalize. res = (res + 360.0) % 360.0; return(res); }
/// <summary> /// Calculates distance between two locations. /// </summary> /// <param name="LocationA">First location.</param> /// <param name="LocationB">Second location.</param> /// <returns>Distance between the two locations in metres.</returns> public static double DistanceBetween(GpsLocation LocationA, GpsLocation LocationB) { return(LocationA.DistanceTo(LocationB)); }