public List <Coordinate> GenerateBootstrapRoute(Geofence geofence, double circleSize = 70) { var geometryFactory = GeometryFactory.Default; var xMod = Math.Sqrt(0.75); var yMod = Math.Sqrt(0.568); var points = new List <Coordinate>(); var polygon = geofence.Feature.Geometry.Coordinates; var line = geometryFactory.CreateLineString(polygon); var coords = geofence.BBox.Coordinates; var minLat = coords.Min(x => x.X); var minLon = coords.Min(x => x.Y); var maxLat = coords.Max(x => x.X); var maxLon = coords.Max(x => x.Y); var currentLatLng = new NetTopologySuite.Geometries.Coordinate(maxLat, maxLon); var lastLatLng = new NetTopologySuite.Geometries.Coordinate(minLat, minLon); var startLatLng = Destination(currentLatLng, 90, circleSize * 1.5); var endLatLng = Destination(Destination(lastLatLng, 270, circleSize * 1.5), 180, circleSize); var row = 0; var heading = 270; var i = 0; while (currentLatLng.X > endLatLng.X) { do { var point = new Point(currentLatLng); var distance = point.Distance(line); if (distance <= circleSize || distance == 0 || polygon.Contains(currentLatLng)) { points.Add(new Coordinate(currentLatLng.X, currentLatLng.Y)); } currentLatLng = Destination(currentLatLng, heading, xMod * circleSize * 2); i++; } while ((heading == 270 && currentLatLng.Y > endLatLng.Y) || (heading == 90 && currentLatLng.Y < startLatLng.Y)); currentLatLng = Destination(currentLatLng, 180, yMod * circleSize * 2); heading = row % 2 == 1 ? 270 : 90; currentLatLng = Destination(currentLatLng, heading, xMod * circleSize * 3); row++; } return(points); }
/// <summary> /// Returns the point that is a distance and heading away from /// the given origin point. /// </summary> /// <param name="latlng">Origin coordinate</param> /// <param name="heading">Heading in degrees, clockwise from 0 degrees north.</param> /// <param name="distance">Distance in meters</param> /// <returns>The destination coordinate</returns> private static NetTopologySuite.Geometries.Coordinate Destination(NetTopologySuite.Geometries.Coordinate latlng, double heading, double distance) { heading = (heading + 360) % 360; const double rad = Math.PI / 180; const double radInv = 180 / Math.PI; const int r = 6378137; // approximation of Earth's radius var lon1 = latlng.Y * rad; var lat1 = latlng.X * rad; var rheading = heading * rad; var sinLat1 = Math.Sin(lat1); var cosLat1 = Math.Cos(lat1); var cosDistR = Math.Cos(distance / r); var sinDistR = Math.Sin(distance / r); var lat2 = Math.Asin((sinLat1 * cosDistR) + (cosLat1 * sinDistR * Math.Cos(rheading))); var lon2 = lon1 + Math.Atan2(Math.Sin(rheading) * sinDistR * cosLat1, cosDistR - (sinLat1 * Math.Sin(lat2))); lon2 *= radInv; lon2 = lon2 > 180 ? lon2 - 360 : lon2 < -180 ? lon2 + 360 : lon2; return(new NetTopologySuite.Geometries.Coordinate(lat2 * radInv, lon2)); }