using System; using System.Collections.Generic; namespace InABox.Core { public class GeoPoint { public GeoPoint(double latitude = 0.0, double longitude = 0.0) { Latitude = latitude; Longitude = longitude; } public double Longitude { get; set; } public double Latitude { get; set; } public GeoPoint Copy() => new GeoPoint(Latitude, Longitude); public static double DistanceBetween(GeoPoint from, GeoPoint to, UnitOfLength? unitOfLength = null) { var baseRad = Math.PI * from.Latitude / 180; var targetRad = Math.PI * to.Latitude / 180; var theta = from.Longitude - to.Longitude; var thetaRad = Math.PI * theta / 180; var dist = Math.Sin(baseRad) * Math.Sin(targetRad) + Math.Cos(baseRad) * Math.Cos(targetRad) * Math.Cos(thetaRad); dist = Math.Acos(dist); dist = dist * 180 / Math.PI; dist = dist * 60 * 1.1515; var unit = unitOfLength ?? UnitOfLength.Kilometers; return unit.ConvertFromMiles(dist); } public double DistanceTo(GeoPoint to, UnitOfLength? unitOfLength = null) => DistanceBetween(this, to, unitOfLength); private static double WGS84_RADIUS = 6370997.0; private static double EarthCircumFence = 2* WGS84_RADIUS * Math.PI; public GeoPoint Move(double mEastWest, double mNorthSouth){ double degreesPerMeterForLat = EarthCircumFence/360.0; double shrinkFactor = Math.Cos((Latitude*Math.PI/180.0)); double degreesPerMeterForLon = degreesPerMeterForLat * shrinkFactor; double newLat = Latitude + mNorthSouth * (1.0/degreesPerMeterForLat); double newLng = Longitude + mEastWest * (1.0/degreesPerMeterForLon); return new GeoPoint(newLat, newLng); } } public class GeoFenceDefinition { public List Coordinates { get;} = new List(); public bool Contains(GeoPoint p) { if (Coordinates.Count < 2) return false; double minX = Coordinates[0].Longitude; double maxX = Coordinates[0].Longitude; double minY = Coordinates[0].Latitude; double maxY = Coordinates[0].Latitude; for (int i = 1; i < Coordinates.Count; i++) { GeoPoint q = Coordinates[i]; minX = Math.Min(q.Longitude, minX); maxX = Math.Max(q.Longitude, maxX); minY = Math.Min(q.Latitude, minY); maxY = Math.Max(q.Latitude, maxY); } if (p.Longitude < minX || p.Longitude > maxX || p.Latitude < minY || p.Latitude > maxY) { return false; } bool inside = false; for (int i = 0, j = Coordinates.Count - 1; i < Coordinates.Count; j = i++) { if ((Coordinates[i].Latitude > p.Latitude) != (Coordinates[j].Latitude > p.Latitude) && p.Longitude < (Coordinates[j].Longitude - Coordinates[i].Longitude) * (p.Latitude - Coordinates[i].Latitude) / (Coordinates[j].Latitude - Coordinates[i].Latitude) + Coordinates[i].Longitude) { inside = !inside; } } return inside; } } }