using System; using System.Collections.Generic; using LeanCloud.Storage.Internal; namespace LeanCloud { /// /// AVGeoPoint represents a latitude / longitude point that may be associated /// with a key in a AVObject or used as a reference point for geo queries. /// This allows proximity-based queries on the key. /// /// Only one key in a class may contain a GeoPoint. /// public struct AVGeoPoint : IJsonConvertible { /// /// Constructs a AVGeoPoint with the specified latitude and longitude. /// /// The point's latitude. /// The point's longitude. public AVGeoPoint(double latitude, double longitude) : this() { Latitude = latitude; Longitude = longitude; } private double latitude; /// /// Gets or sets the latitude of the GeoPoint. Valid range is [-90, 90]. /// Extremes should not be used. /// public double Latitude { get { return latitude; } set { if (value > 90 || value < -90) { throw new ArgumentOutOfRangeException("value", "Latitude must be within the range [-90, 90]"); } latitude = value; } } private double longitude; /// /// Gets or sets the longitude. Valid range is [-180, 180]. /// Extremes should not be used. /// public double Longitude { get { return longitude; } set { if (value > 180 || value < -180) { throw new ArgumentOutOfRangeException("value", "Longitude must be within the range [-180, 180]"); } longitude = value; } } /// /// Get the distance in radians between this point and another GeoPoint. This is the smallest angular /// distance between the two points. /// /// GeoPoint describing the other point being measured against. /// The distance in between the two points. public AVGeoDistance DistanceTo(AVGeoPoint point) { double d2r = Math.PI / 180; // radian conversion factor double lat1rad = Latitude * d2r; double long1rad = longitude * d2r; double lat2rad = point.Latitude * d2r; double long2rad = point.Longitude * d2r; double deltaLat = lat1rad - lat2rad; double deltaLong = long1rad - long2rad; double sinDeltaLatDiv2 = Math.Sin(deltaLat / 2); double sinDeltaLongDiv2 = Math.Sin(deltaLong / 2); // Square of half the straight line chord distance between both points. // [0.0, 1.0] double a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.Cos(lat1rad) * Math.Cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; a = Math.Min(1.0, a); return new AVGeoDistance(2 * Math.Asin(Math.Sqrt(a))); } IDictionary IJsonConvertible.ToJSON() { return new Dictionary { { "__type", "GeoPoint" }, { "latitude", Latitude }, { "longitude", Longitude } }; } } }