/// <summary> /// Bounding Polygon /// Get all the hashString covered by the polygon in numberOfChars /// </summary> /// <param name="polygon">array of coordinates describes the polygon</param> /// <param name="numberOfChars"></param> /// <returns>array of hash string</returns> public static string[] Bpolygon(Coordinates[] polygon, int numberOfChars = 9) { var hashList = new List <string>(); // Get all bounding boxes that are possible be covered by polygon Coordinates max = new Coordinates { Lat = -90, Lon = -180 }; Coordinates min = new Coordinates { Lat = 90, Lon = 180 }; foreach (Coordinates c in polygon) { max.Lat = Math.Max(max.Lat, c.Lat); max.Lon = Math.Max(max.Lon, c.Lon); min.Lat = Math.Min(min.Lat, c.Lat); min.Lon = Math.Min(min.Lon, c.Lon); } string[] bboxHash = GeoHash.Bboxes(min.Lat, min.Lon, max.Lat, max.Lon, numberOfChars); foreach (string hash in bboxHash) { BoundingBox box = GeoHash.DecodeBbox(hash); if (BoxOverlapPolygon(box, polygon)) { hashList.Add(hash); } } return(hashList.ToArray()); }
/// <summary> /// Bounding Box Coordinates /// Get all coordinates covered by the box in numberOfChars /// </summary> /// <param name="minLat"></param> /// <param name="minLon"></param> /// <param name="maxLat"></param> /// <param name="maxLon"></param> /// <param name="numberOfChars"></param> /// <returns>all coordinates covered by the box in numberOfChars</returns> public Coordinates[] BboxCoordinates(double minLat, double minLon, double maxLat, double maxLon, int numberOfChars = 9) { var coorList = new List <Coordinates>(); string[] hashList = GeoHash.Bboxes(minLat, minLon, maxLat, maxLat, numberOfChars); foreach (string hash in hashList) { // TODO: search all level or search current level only? Coordinates[] coors = GetCoordinates(hash); BoundingBox box = GeoHash.DecodeBbox(hash); if (BoxInBoxRange(box, minLat, minLon, maxLat, maxLon)) { // All covered by box coorList.AddRange(coors); } else { // Not all covered by box foreach (Coordinates c in coors) { if (CoordinateInBoxRange(c, minLat, minLon, maxLat, maxLon)) { coorList.Add(c); } } } } return(coorList.ToArray()); }
/// <summary> /// Find the length of the shortest side of a box /// </summary> /// <param name="hash"></param> /// <returns>length in meter</returns> public static double FindMinSideLength(string hash) { BoundingBox box = GeoHash.DecodeBbox(hash); double west = Measure(box.Minimum.Lat, box.Minimum.Lon, box.Maximum.Lat, box.Minimum.Lon); double east = Measure(box.Minimum.Lat, box.Maximum.Lon, box.Maximum.Lat, box.Maximum.Lon); double south = Measure(box.Minimum.Lat, box.Minimum.Lon, box.Minimum.Lat, box.Maximum.Lon); double north = Measure(box.Maximum.Lat, box.Maximum.Lon, box.Maximum.Lat, box.Minimum.Lon); return(Math.Min(Math.Min(west, east), Math.Min(north, south))); }
/// <summary> /// Get all bounding boxes covered by polygon in numberOfChars /// </summary> /// <param name="polygon">array of coordinates describes the polygon</param> /// <param name="numberOfChars"></param> /// <returns>array of hash string</returns> public static BoundingBox[] BpolygonBoxes(Coordinates[] polygon, int numberOfChars = 9) { var boxList = new List <BoundingBox>(); string[] hashList = Bpolygon(polygon, numberOfChars); foreach (string hash in hashList) { boxList.Add(GeoHash.DecodeBbox(hash)); } return(boxList.ToArray()); }
/// <summary> /// Get all bounding boxes covered by box /// </summary> /// <param name="minLat"></param> /// <param name="minLon"></param> /// <param name="maxLat"></param> /// <param name="maxLon"></param> /// <param name="numberOfChars"></param> /// <returns></returns> public static BoundingBox[] BboxBoxes(double minLat, double minLon, double maxLat, double maxLon, int numberOfChars = 9) { var boxList = new List <BoundingBox>(); string[] hashList = GeoHash.Bboxes(minLat, minLon, maxLat, maxLon, numberOfChars); foreach (string hash in hashList) { boxList.Add(GeoHash.DecodeBbox(hash)); } return(boxList.ToArray()); }
/// <summary> /// Get all bounding boxes that covers the circle /// </summary> /// <param name="latitude">latitude of center point</param> /// <param name="longitude">longitude of center point</param> /// <param name="radius">radius in meters</param> /// <param name="numberOfChars">number of characters of hash string</param> /// <returns>bounding box object array</returns> public static BoundingBox[] BcircleBoxes(double latitude, double longitude, double radius, int numberOfChars = 9) { var boxList = new List <BoundingBox>(); string[] hashList = Bcircle(latitude, longitude, radius, numberOfChars); foreach (string hash in hashList) { boxList.Add(GeoHash.DecodeBbox(hash)); } return(boxList.ToArray()); }
public static void BoundingCircleTest() { Coordinates c = new Coordinates { Lat = mLat, Lon = mLon }; Console.WriteLine("point latitude " + c.Lat + ", longitude " + c.Lon); var encoded = GeoHash.Encode(c.Lat, c.Lon, mLevel); Console.WriteLine("encoded = " + encoded); var decoded = GeoHash.Decode(encoded); var latitude = decoded.Coordinates.Lat; var longitude = decoded.Coordinates.Lon; Console.WriteLine("decoded box latitude " + latitude + ", longitude " + longitude); BoundingBox box = GeoHash.DecodeBbox(encoded); var maxLat = box.Maximum.Lat; var minLat = box.Minimum.Lat; var maxLon = box.Maximum.Lon; var minLon = box.Minimum.Lon; // Measure the box size in meters var oneSide = DataBase.Measure(maxLat, minLon, minLat, minLon); var anotherSide = DataBase.Measure(maxLat, maxLon, maxLat, minLon); // Bounding circle var watch = System.Diagnostics.Stopwatch.StartNew(); string[] hashList = DataBase.Bcircle(c.Lat, c.Lon, mRadius, mLevel); watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; //foreach (var h in hashList) //{ // Console.WriteLine(h); //} Console.WriteLine("box size: " + oneSide + " meters * " + anotherSide + " meters"); Console.WriteLine("bounding circle radius " + mRadius + " meters, level " + mLevel); Console.WriteLine("Get bounding circle, time elapsed: " + elapsedMs + " ms | " + hashList.Length + " results get"); string filename = "bounding circle" + c.Lat.ToString() + "-" + c.Lon.ToString() + "-" + mRadius.ToString() + "-" + mLevel.ToString(); KMLGenerator.GenerateKMLBoundingCircle(hashList, c.Lat, c.Lon, mRadius, filename); Console.WriteLine("save as file name " + filename); }
/// <summary> /// Bounding Circle Coordinates /// Get all coordinates covered by the circle in numberOfChars /// </summary> /// <param name="latitude">latitude of center point</param> /// <param name="longitude">longitude of center point</param> /// <param name="radius">radius in meters</param> /// <param name="numberOfChars">number of characters of hash string</param> /// <param name="limit">max number of coordinates return</param> /// <returns>array of coordinate object</returns> public Coordinates[] BcircleCoordinates(double latitude, double longitude, double radius, int numberOfChars = 9, int limit = 0) { var coorList = new List <Coordinates>(); string[] hashList = Bcircle(latitude, longitude, radius, numberOfChars); foreach (string hash in hashList) { // TODO: search all level or search current level only? Coordinates[] coors = GetCoordinates(hash); BoundingBox box = GeoHash.DecodeBbox(hash); if (BoxAllInCircleRange(box, latitude, longitude, radius)) { // All covered by circle coorList.AddRange(coors); } else { // Not all covered by circle foreach (Coordinates c in coors) { if (Measure(c.Lat, c.Lon, latitude, longitude) <= radius) { coorList.Add(c); } } } } if (limit == 0) { return(coorList.ToArray()); } coorList.Sort((x, y) => Measure(x.Lat, x.Lon, latitude, longitude).CompareTo(Measure(y.Lat, y.Lon, latitude, longitude))); if (coorList.Count >= limit) { return(coorList.GetRange(0, limit).ToArray()); } return(coorList.ToArray()); }
/** * Draw bounding circle * Generate kml from a list of boxhash */ public static void GenerateKMLBoundingCircle(string[] hashList, double latitude, double longitude, double radius, string fileName) { string kmlStr = $@"<?xml version=""1.0"" encoding=""UTF-8""?> <kml xmlns=""http://www.opengis.net/kml/2.2"" > <Document> <name>BoundingCircle</name> <Style id=""yellowLineGreenPoly""> <LineStyle> <color> 7f00ffff </color> <width> 4 </width> </LineStyle> <PolyStyle> <color> 7f00ff00 </color> </PolyStyle> </Style> <Placemark> <styleUrl>#yellowLineGreenPoly</styleUrl> <MultiGeometry>"; foreach (string hash in hashList) { kmlStr += "\n"; kmlStr += @" <LineString> <extrude> 1 </extrude > <tessellate> 1 </tessellate> <altitudeMode> absolute </altitudeMode> <coordinates> "; var box = GeoHash.DecodeBbox(hash); kmlStr += box.Maximum.Lon.ToString(); kmlStr += ","; kmlStr += box.Maximum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += box.Maximum.Lon.ToString(); kmlStr += ","; kmlStr += box.Minimum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += box.Minimum.Lon.ToString(); kmlStr += ","; kmlStr += box.Minimum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += box.Minimum.Lon.ToString(); kmlStr += ","; kmlStr += box.Maximum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += box.Maximum.Lon.ToString(); kmlStr += ","; kmlStr += box.Maximum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += @" </coordinates> </LineString>"; } kmlStr += "\n"; kmlStr += @" <LineString> <extrude> 1 </extrude > <tessellate> 1 </tessellate> <altitudeMode> absolute </altitudeMode> <coordinates> "; // Draw the circle for (double degree = 0; degree < 360; degree += 0.5) { var coor = DataBase.DistanceToPoint(latitude, longitude, radius, degree); kmlStr += coor.Lon.ToString(); kmlStr += ","; kmlStr += coor.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; //Console.WriteLine(Measure(latitude, longitude, coor.Lat, coor.Lon)); } kmlStr += @" </coordinates> </LineString>"; // Draw center kmlStr += "<Point><coordinates>" + longitude.ToString() + "," + latitude.ToString() + "</coordinates></Point>"; kmlStr += @" </MultiGeometry> </Placemark> </Document> </kml>"; using (StreamWriter sw = new StreamWriter(fileName + ".kml")) { sw.WriteLine(kmlStr); } }
/** * Draw bounding boxes * Generate kml from a list of boxhash */ public static void GenerateKMLBoundingBoxes(string[] hashList, Coordinates coorMin, Coordinates coorMax, string fileName) { string kmlStr = $@"<?xml version=""1.0"" encoding=""UTF-8""?> <kml xmlns=""http://www.opengis.net/kml/2.2"" > <Document> <name>BoundingBoxes</name> <Style id=""yellowLineGreenPoly""> <LineStyle> <color> 7f00ffff </color> <width> 4 </width> </LineStyle> <PolyStyle> <color> 7f00ff00 </color> </PolyStyle> </Style> <Placemark> <styleUrl>#redLineGreenPoly</styleUrl> <MultiGeometry>"; foreach (string hash in hashList) { //Console.WriteLine(hash+","); kmlStr += "\n"; kmlStr += @" <LineString> <extrude> 1 </extrude > <tessellate> 1 </tessellate> <altitudeMode> absolute </altitudeMode> <coordinates> "; var box = GeoHash.DecodeBbox(hash); kmlStr += box.Maximum.Lon.ToString(); kmlStr += ","; kmlStr += box.Maximum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += box.Maximum.Lon.ToString(); kmlStr += ","; kmlStr += box.Minimum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += box.Minimum.Lon.ToString(); kmlStr += ","; kmlStr += box.Minimum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += box.Minimum.Lon.ToString(); kmlStr += ","; kmlStr += box.Maximum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += box.Maximum.Lon.ToString(); kmlStr += ","; kmlStr += box.Maximum.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += @" </coordinates> </LineString>"; } // Draw bounding box kmlStr += "\n"; kmlStr += @" <LineString> <extrude> 1 </extrude > <tessellate> 1 </tessellate> <altitudeMode> absolute </altitudeMode> <coordinates> "; kmlStr += coorMin.Lon.ToString(); kmlStr += ","; kmlStr += coorMin.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += coorMin.Lon.ToString(); kmlStr += ","; kmlStr += coorMax.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += coorMax.Lon.ToString(); kmlStr += ","; kmlStr += coorMax.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += coorMax.Lon.ToString(); kmlStr += ","; kmlStr += coorMin.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += coorMin.Lon.ToString(); kmlStr += ","; kmlStr += coorMin.Lat.ToString(); kmlStr += ",20"; kmlStr += "\n"; kmlStr += @" </coordinates> </LineString>"; kmlStr += @" </MultiGeometry> </Placemark> </Document> </kml>"; using (StreamWriter sw = new StreamWriter(fileName + ".kml")) { sw.WriteLine(kmlStr); } }
/// <summary> /// Bounding Circle /// Get all the hashString covered by the circle in numberOfChars /// </summary> /// <param name="latitude">latitude of center point</param> /// <param name="longitude">longitude of center point</param> /// <param name="radius">radius in meters</param> /// <param name="numberOfChars">number of characters of hash string</param> /// <returns>hash string array</returns> public static string[] Bcircle(double latitude, double longitude, double radius, int numberOfChars = 9) { var hashList = new List <string>(); string hashCenter = GeoHash.Encode(latitude, longitude, numberOfChars); hashList.Add(hashCenter); GeohashDecodeResult latLon = GeoHash.Decode(hashCenter); // Find left and right end // Find west(left) end Coordinates leftCoor = DistanceToPoint(latitude, longitude, radius, 270); string hashLeft = GeoHash.Encode(leftCoor.Lat, leftCoor.Lon, numberOfChars); NGeoHash.BoundingBox boxLeft = GeoHash.DecodeBbox(hashLeft); // Find east(right) end Coordinates rightCoor = DistanceToPoint(latitude, longitude, radius, 90); string hashRight = GeoHash.Encode(rightCoor.Lat, rightCoor.Lon, numberOfChars); NGeoHash.BoundingBox boxRight = GeoHash.DecodeBbox(hashRight); // Find steps(from left to right) double perLon = latLon.Error.Lon * 2; // box size(in degree) on west-east direction var lonStep = Math.Round((boxRight.Minimum.Lon - boxLeft.Minimum.Lon) / perLon); double perLat = latLon.Error.Lat * 2; // box size(in dgree) on north–south direction for (var lon = 0; lon <= lonStep; lon++) { // Find current box string currentBoxHash = GeoHash.Neighbor(hashLeft, new[] { 0, lon }); NGeoHash.BoundingBox currentBox = GeoHash.DecodeBbox(currentBoxHash); // Find north(upper) end // Find up neighbor // Check if in range int i = 0; NGeoHash.BoundingBox upBox = currentBox; string upBoxHash = currentBoxHash; while (BoxInCircleRange(upBox, latitude, longitude, radius)) { if (!hashList.Contains(upBoxHash)) { hashList.Add(upBoxHash); } //Console.WriteLine("Add+ " + upBoxHash); i++; upBoxHash = GeoHash.Neighbor(currentBoxHash, new[] { i, 0 }); upBox = GeoHash.DecodeBbox(upBoxHash); } // Find south(down) end // Find steps(north to south) int j = 0; NGeoHash.BoundingBox downBox = currentBox; string downBoxHash = currentBoxHash; while (BoxInCircleRange(downBox, latitude, longitude, radius)) { if (!hashList.Contains(downBoxHash)) { hashList.Add(downBoxHash); } //Console.WriteLine("Add- " + downBoxHash); j--; downBoxHash = GeoHash.Neighbor(currentBoxHash, new[] { j, 0 }); downBox = GeoHash.DecodeBbox(downBoxHash); } } // Check each point on the circle, see if covers more box // Find step length of radius double stepOfRadius = FindMinSideLength(hashCenter) * 0.9; // Find step of cricle, devide 360 degree to how many parts double stepOfCircle = 360 / (Math.PI * 2 * radius / stepOfRadius); for (double degree = 0; degree <= 360; degree += stepOfCircle) { Coordinates coor = DistanceToPoint(latitude, longitude, radius, degree); string hash = GeoHash.Encode(coor.Lat, coor.Lon, numberOfChars); if (!hashList.Contains(hash)) { hashList.Add(hash); } } return(hashList.ToArray()); }