/// <summary> /// Filter out any points outside of the queried area from the input list. /// </summary> /// <param name="list">List of items return by Amazon DynamoDB. It may contains points outside of the actual area queried.</param> /// <param name="geoQueryRequest">List of items within the queried area.</param> /// <returns></returns> private IEnumerable <IDictionary <string, AttributeValue> > Filter(IEnumerable <IDictionary <string, AttributeValue> > list, GeoQueryRequest geoQueryRequest) { var result = new List <IDictionary <String, AttributeValue> >(); S2LatLngRect?latLngRect = null; S2LatLng? centerLatLng = null; double radiusInMeter = 0; if (geoQueryRequest is QueryRectangleRequest) { latLngRect = S2Util.GetBoundingLatLngRect(geoQueryRequest); } foreach (var item in list) { var geoJson = item[_config.GeoJsonAttributeName].S; var geoPoint = GeoJsonMapper.GeoPointFromString(geoJson); var latLng = S2LatLng.FromDegrees(geoPoint.lat, geoPoint.lng); if (latLngRect != null && latLngRect.Value.Contains(latLng)) { result.Add(item); } else if (centerLatLng != null && radiusInMeter > 0 && centerLatLng.Value.GetEarthDistance(latLng) <= radiusInMeter) { result.Add(item); } } return(result); }
/// <summary> /// An utility method to get a bounding box of latitude and longitude from a given GeoQueryRequest. /// </summary> /// <param name="geoQueryRequest">It contains all of the necessary information to form a latitude and longitude box.</param> /// <returns></returns> public static S2LatLngRect GetBoundingLatLngRect(GeoQueryRequest geoQueryRequest) { if (geoQueryRequest is QueryRectangleRequest) { var queryRectangleRequest = (QueryRectangleRequest)geoQueryRequest; var minPoint = queryRectangleRequest.MinPoint; var maxPoint = queryRectangleRequest.MaxPoint; var latLngRect = default(S2LatLngRect); if (minPoint != null && maxPoint != null) { var minLatLng = S2LatLng.FromDegrees(minPoint.Latitude, minPoint.Longitude); var maxLatLng = S2LatLng.FromDegrees(maxPoint.Latitude, maxPoint.Longitude); latLngRect = new S2LatLngRect(minLatLng, maxLatLng); } return(latLngRect); } else if (geoQueryRequest is QueryRadiusRequest) { var queryRadiusRequest = (QueryRadiusRequest)geoQueryRequest; var centerPoint = queryRadiusRequest.CenterPoint; var radiusInMeter = queryRadiusRequest.RadiusInMeter; var centerLatLng = S2LatLng.FromDegrees(centerPoint.Latitude, centerPoint.Longitude); var latReferenceUnit = centerPoint.Latitude > 0.0 ? -1.0 : 1.0; var latReferenceLatLng = S2LatLng.FromDegrees(centerPoint.Latitude + latReferenceUnit, centerPoint.Longitude); var lngReferenceUnit = centerPoint.Longitude > 0.0 ? -1.0 : 1.0; var lngReferenceLatLng = S2LatLng.FromDegrees(centerPoint.Latitude, centerPoint.Longitude + lngReferenceUnit); var latForRadius = radiusInMeter / centerLatLng.GetEarthDistance(latReferenceLatLng); var lngForRadius = radiusInMeter / centerLatLng.GetEarthDistance(lngReferenceLatLng); var minLatLng = S2LatLng.FromDegrees(centerPoint.Latitude - latForRadius, centerPoint.Longitude - lngForRadius); var maxLatLng = S2LatLng.FromDegrees(centerPoint.Latitude + latForRadius, centerPoint.Longitude + lngForRadius); return(new S2LatLngRect(minLatLng, maxLatLng)); } return(S2LatLngRect.Empty); }
private async Task RunGeoQuery(GeoQueryRequest request, GeoQueryResult geoQueryResult, GeohashRange range, CancellationToken cancellationToken) { var queryRequest = request.QueryRequest.CopyQueryRequest(); var hashKey = S2Manager.GenerateHashKey(range.RangeMin, _config.HashKeyLength); var results = await _dynamoDBManager.QueryGeohashAsync(queryRequest, hashKey, range, cancellationToken).ConfigureAwait(false); foreach (var queryResult in results) { cancellationToken.ThrowIfCancellationRequested(); // This is a concurrent collection geoQueryResult.QueryResults.Add(queryResult); var filteredQueryResult = Filter(queryResult.Items, request); // this is a concurrent collection foreach (var r in filteredQueryResult) { geoQueryResult.Items.Add(r); } } }
/// <summary> /// An utility method to get a bounding box of latitude and longitude from a given GeoQueryRequest. /// </summary> /// <param name="geoQueryRequest">It contains all of the necessary information to form a latitude and longitude box.</param> /// <returns></returns> public static S2LatLngRect GetBoundingLatLngRect(GeoQueryRequest geoQueryRequest) { if (geoQueryRequest is QueryRectangleRequest) { var queryRectangleRequest = (QueryRectangleRequest)geoQueryRequest; var minPoint = queryRectangleRequest.MinPoint; var maxPoint = queryRectangleRequest.MaxPoint; var latLngRect = default(S2LatLngRect); if (minPoint != null && maxPoint != null) { var minLatLng = S2LatLng.FromDegrees(minPoint.lat, minPoint.lng); var maxLatLng = S2LatLng.FromDegrees(maxPoint.lat, maxPoint.lng); latLngRect = new S2LatLngRect(minLatLng, maxLatLng); } return(latLngRect); } return(S2LatLngRect.Empty); }
private async Task <GeoQueryResult> DispatchQueries(IEnumerable <GeohashRange> ranges, GeoQueryRequest geoQueryRequest, CancellationToken cancellationToken) { var geoQueryResult = new GeoQueryResult(); var futureList = new List <Task>(); var internalSource = new CancellationTokenSource(); var internalToken = internalSource.Token; var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, internalToken); foreach (var outerRange in ranges) { foreach (var range in outerRange.TrySplit(_config.HashKeyLength)) { var task = RunGeoQuery(geoQueryRequest, geoQueryResult, range, cts.Token); futureList.Add(task); } } Exception inner = null; try { for (var i = 0; i < futureList.Count; i++) { try { await futureList[i].ConfigureAwait(false); } catch (Exception e) { inner = e; // cancel the others internalSource.Cancel(true); } } } catch (Exception ex) { inner = inner ?? ex; throw new ClientException("Querying Amazon DynamoDB failed.", inner); } return(geoQueryResult); }