public async Task <IEnumerable <GeoClusterLocation> > GetGeoLocationClustersAsync( GetGeoLocationClustersRequest request, CancellationToken cancellationToken) { IEnumerable <MediaGeoLocation> medias = await _mediaStore.FindMediaInGeoBoxAsync( request.Box, 100000, cancellationToken); var clusters = new List <GeoClusterLocation>(); if (medias.Count() < 500 && request.Precision > 10) { //Add every item as cluster foreach (MediaGeoLocation media in medias) { clusters.Add(new GeoClusterLocation() { Hash = GeoHash.Encode( media.Coordinates.Latitude, media.Coordinates.Longitude), Coordinates = media.Coordinates, Id = media.Id, Count = 1 }); } } else { medias.ToList().ForEach(x => x.GeoHash = x.GeoHash.Substring(0, request.Precision)); IEnumerable <IGrouping <string, MediaGeoLocation> > grouped = medias .GroupBy(x => x.GeoHash); foreach (IGrouping <string, MediaGeoLocation>?group in grouped) { GeohashDecodeResult decoded = GeoHash.Decode(group.Key); var cluster = new GeoClusterLocation { Hash = group.Key, Count = group.Count(), Coordinates = new GeoCoordinate { Latitude = decoded.Coordinates.Lat, Longitude = decoded.Coordinates.Lon } }; if (group.Count() == 1) { cluster.Id = group.First().Id; } clusters.Add(cluster); } } return(clusters); }
/// <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()); }