GeoPoint.cs 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. using System;
  2. using System.Collections.Generic;
  3. namespace InABox.Core
  4. {
  5. public class GeoPoint
  6. {
  7. public GeoPoint(double latitude = 0.0, double longitude = 0.0)
  8. {
  9. Latitude = latitude;
  10. Longitude = longitude;
  11. }
  12. public double Longitude { get; set; }
  13. public double Latitude { get; set; }
  14. public GeoPoint Copy() => new GeoPoint(Latitude, Longitude);
  15. public static double DistanceBetween(GeoPoint from, GeoPoint to, UnitOfLength? unitOfLength = null)
  16. {
  17. var baseRad = Math.PI * from.Latitude / 180;
  18. var targetRad = Math.PI * to.Latitude / 180;
  19. var theta = from.Longitude - to.Longitude;
  20. var thetaRad = Math.PI * theta / 180;
  21. var dist =
  22. Math.Sin(baseRad) * Math.Sin(targetRad) + Math.Cos(baseRad) *
  23. Math.Cos(targetRad) * Math.Cos(thetaRad);
  24. dist = Math.Acos(dist);
  25. dist = dist * 180 / Math.PI;
  26. dist = dist * 60 * 1.1515;
  27. var unit = unitOfLength ?? UnitOfLength.Kilometers;
  28. return unit.ConvertFromMiles(dist);
  29. }
  30. public double DistanceTo(GeoPoint to, UnitOfLength? unitOfLength = null)
  31. => DistanceBetween(this, to, unitOfLength);
  32. private static double WGS84_RADIUS = 6370997.0;
  33. private static double EarthCircumFence = 2* WGS84_RADIUS * Math.PI;
  34. public GeoPoint Move(double mEastWest, double mNorthSouth){
  35. double degreesPerMeterForLat = EarthCircumFence/360.0;
  36. double shrinkFactor = Math.Cos((Latitude*Math.PI/180.0));
  37. double degreesPerMeterForLon = degreesPerMeterForLat * shrinkFactor;
  38. double newLat = Latitude + mNorthSouth * (1.0/degreesPerMeterForLat);
  39. double newLng = Longitude + mEastWest * (1.0/degreesPerMeterForLon);
  40. return new GeoPoint(newLat, newLng);
  41. }
  42. }
  43. public class GeoFenceDefinition
  44. {
  45. public List<GeoPoint> Coordinates { get;} = new List<GeoPoint>();
  46. public bool Contains(GeoPoint p)
  47. {
  48. if (Coordinates.Count < 2)
  49. return false;
  50. double minX = Coordinates[0].Longitude;
  51. double maxX = Coordinates[0].Longitude;
  52. double minY = Coordinates[0].Latitude;
  53. double maxY = Coordinates[0].Latitude;
  54. for (int i = 1; i < Coordinates.Count; i++)
  55. {
  56. GeoPoint q = Coordinates[i];
  57. minX = Math.Min(q.Longitude, minX);
  58. maxX = Math.Max(q.Longitude, maxX);
  59. minY = Math.Min(q.Latitude, minY);
  60. maxY = Math.Max(q.Latitude, maxY);
  61. }
  62. if (p.Longitude < minX || p.Longitude > maxX || p.Latitude < minY || p.Latitude > maxY)
  63. {
  64. return false;
  65. }
  66. bool inside = false;
  67. for (int i = 0, j = Coordinates.Count - 1; i < Coordinates.Count; j = i++)
  68. {
  69. if ((Coordinates[i].Latitude > p.Latitude) != (Coordinates[j].Latitude > p.Latitude) &&
  70. p.Longitude < (Coordinates[j].Longitude - Coordinates[i].Longitude) * (p.Latitude - Coordinates[i].Latitude) / (Coordinates[j].Latitude - Coordinates[i].Latitude) + Coordinates[i].Longitude)
  71. {
  72. inside = !inside;
  73. }
  74. }
  75. return inside;
  76. }
  77. }
  78. }