public virtual void TestSimpleCircle(SpatialContext ctx) { base.ctx = ctx; double[] theXs = new double[] { -10, 0, 10 }; foreach (double x in theXs) { double[] theYs = new double[] { -20, 0, 20 }; foreach (double y in theYs) { TestCircle(x, y, 0); TestCircle(x, y, 5); } } TestCircleReset(ctx); //INTERSECTION: //Start with some static tests that have shown to cause failures at some point: Assert.Equal( /*"getX not getY",*/ SpatialRelation.INTERSECTS, ctx.MakeCircle(107, -81, 147).Relate(ctx.MakeRectangle(92, 121, -89, 74))); TestCircleIntersect(); Assert.Equal(ctx.MakeCircle(1, 2, 10), ctx.MakeCircle(1, 2, 6).GetBuffered(4, ctx)); TestEmptiness(ctx.MakeCircle(double.NaN, double.NaN, random.nextBoolean() ? 0 : double.NaN)); }
protected void TestCircle(double x, double y, double dist) { Circle c = ctx.MakeCircle(x, y, dist); String msg = c.ToString(); Circle c2 = ctx.MakeCircle(ctx.MakePoint(x, y), dist); Assert.Equal(c, c2); Assert.Equal(c.GetHashCode(), c2.GetHashCode()); Assert.Equal(/*msg,*/ dist > 0, c.HasArea()); double area = c.GetArea(ctx); Assert.True(/*msg,*/ c.HasArea() == (area > 0.0)); Rectangle bbox = c.GetBoundingBox(); Assert.Equal(/*msg,*/ dist > 0, bbox.GetArea(ctx) > 0); Assert.True(area <= bbox.GetArea(ctx)); if (!ctx.IsGeo()) { //if not geo then units of dist == units of x,y AssertEqualsRatio(msg, bbox.GetHeight(), dist * 2); AssertEqualsRatio(msg, bbox.GetWidth(), dist * 2); } assertRelation(msg, SpatialRelation.CONTAINS, c, c.GetCenter()); assertRelation(msg, SpatialRelation.CONTAINS, bbox, c); }
public static void testCircleReset(SpatialContext ctx) { Circle c = ctx.MakeCircle(3, 4, 5); Circle c2 = ctx.MakeCircle(5, 6, 7); c2.Reset(3, 4, 5); // to c1 Assert.Equal(c, c2); Assert.Equal(c.GetBoundingBox(), c2.GetBoundingBox()); }
public static void TestCircleReset(SpatialContext ctx) { ICircle c = ctx.MakeCircle(3, 4, 5); ICircle c2 = ctx.MakeCircle(5, 6, 7); c2.Reset(3, 4, 5); // to c1 Assert.Equal(c, c2); Assert.Equal(c.BoundingBox, c2.BoundingBox); }
private void Search() { IndexReader indexReader = DirectoryReader.Open(directory); IndexSearcher indexSearcher = new IndexSearcher(indexReader); Sort idSort = new Sort(new SortField("id", SortFieldType.INT32)); //--Filter by circle (<= distance from a point) { //Search with circle //note: SpatialArgs can be parsed from a string SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, ctx.MakeCircle(-80.0, 33.0, DistanceUtils.Dist2Degrees(200, DistanceUtils.EARTH_MEAN_RADIUS_KM))); Filter filter = strategy.MakeFilter(args); TopDocs docs = indexSearcher.Search(new MatchAllDocsQuery(), filter, 10, idSort); AssertDocMatchedIds(indexSearcher, docs, 2); //Now, lets get the distance for the 1st doc via computing from stored point value: // (this computation is usually not redundant) Document doc1 = indexSearcher.Doc(docs.ScoreDocs[0].Doc); String doc1Str = doc1.GetField(strategy.FieldName).GetStringValue(); //assume doc1Str is "x y" as written in newSampleDocument() int spaceIdx = doc1Str.IndexOf(' '); double x = double.Parse(doc1Str.Substring(0, spaceIdx - 0), CultureInfo.InvariantCulture); double y = double.Parse(doc1Str.Substring(spaceIdx + 1), CultureInfo.InvariantCulture); double doc1DistDEG = ctx.CalcDistance(args.Shape.Center, x, y); assertEquals(121.6d, DistanceUtils.Degrees2Dist(doc1DistDEG, DistanceUtils.EARTH_MEAN_RADIUS_KM), 0.1); //or more simply: assertEquals(121.6d, doc1DistDEG * DistanceUtils.DEG_TO_KM, 0.1); } //--Match all, order by distance ascending { IPoint pt = ctx.MakePoint(60, -50); ValueSource valueSource = strategy.MakeDistanceValueSource(pt, DistanceUtils.DEG_TO_KM); //the distance (in km) Sort distSort = new Sort(valueSource.GetSortField(false)).Rewrite(indexSearcher); //false=asc dist TopDocs docs = indexSearcher.Search(new MatchAllDocsQuery(), 10, distSort); AssertDocMatchedIds(indexSearcher, docs, 4, 20, 2); //To get the distance, we could compute from stored values like earlier. // However in this example we sorted on it, and the distance will get // computed redundantly. If the distance is only needed for the top-X // search results then that's not a big deal. Alternatively, try wrapping // the ValueSource with CachingDoubleValueSource then retrieve the value // from the ValueSource now. See LUCENE-4541 for an example. } //demo arg parsing { SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, ctx.MakeCircle(-80.0, 33.0, 1)); SpatialArgs args2 = new SpatialArgsParser().Parse("Intersects(BUFFER(POINT(-80 33),1))", ctx); assertEquals(args.toString(), args2.toString()); } indexReader.Dispose(); }
private SpatialArgs GetArgs(int docId, int distanceInKms) { Document doc; int index = docId; //we may land at a document that has no spatial field. In which case we keep increasing the index until we find one that does have a spatial field. do { doc = base.indexSearcher.IndexReader.Document(index % indexSearcher.MaxDoc, null); index++; } while (doc.GetField(StrategyPrefix) == null); SpatialContext ctx = _spatialStrategy.GetSpatialContext(); string[] parts = doc.Get(StrategyPrefix, null) .Split(' '); Point pt = ctx.MakePoint(double.Parse(parts[0]), double.Parse(parts[1])); Circle circle = ctx.MakeCircle(pt, DistanceUtils.Dist2Degrees(distanceInKms, DistanceUtils.EARTH_MEAN_RADIUS_KM)); var args = new SpatialArgs(SpatialOperation.Intersects, circle); return(args); }
public void TestSimpleCircle(SpatialContext ctx) { base.ctx = ctx; double[] theXs = new double[] { -10, 0, 10 }; foreach (double x in theXs) { double[] theYs = new double[] { -20, 0, 20 }; foreach (double y in theYs) { TestCircle(x, y, 0); TestCircle(x, y, 5); } } testCircleReset(ctx); //INTERSECTION: //Start with some static tests that have shown to cause failures at some point: Assert.Equal( /*"getX not getY",*/ SpatialRelation.INTERSECTS, ctx.MakeCircle(107, -81, 147).Relate(ctx.MakeRectangle(92, 121, -89, 74))); TestCircleIntersect(); }
public IList <SearchItem> SearchByLocation(string queryString, double longitude, double latitude, double searchRadiusKm, int maxHits = 10) { IList <SearchItem> results; using (var searcher = new IndexSearcher(Directory, true)) using (var analyser = new StandardAnalyzer(LuceneVersion)) { var distance = DistanceUtils.Dist2Degrees(searchRadiusKm, DistanceUtils.EARTH_MEAN_RADIUS_KM); var searchArea = _spatialContext.MakeCircle(longitude, latitude, distance); var fields = new[] { Name }; var parser = new MultiFieldQueryParser(LuceneVersion, fields, analyser); parser.DefaultOperator = QueryParser.Operator.OR; // Allow multiple terms. var query = ParseQuery(queryString, parser); var spatialArgs = new SpatialArgs(SpatialOperation.Intersects, searchArea); var spatialQuery = _strategy.MakeQuery(spatialArgs); var valueSource = _strategy.MakeRecipDistanceValueSource(searchArea); var valueSourceFilter = new ValueSourceFilter(new QueryWrapperFilter(spatialQuery), valueSource, 0, 1); var filteredSpatial = new FilteredQuery(query, valueSourceFilter); var spatialRankingQuery = new FunctionQuery(valueSource); BooleanQuery bq = new BooleanQuery(); bq.Add(filteredSpatial, Occur.MUST); bq.Add(spatialRankingQuery, Occur.MUST); var hits = searcher.Search(bq, maxHits).ScoreDocs; results = MapResultsToSearchItems(hits, searcher); } return(results); }
public void CalcDistanceFromErrPct() { SpatialContext ctx = SpatialContext.Geo; double DEP = 0.5;//distErrPct //the result is the diagonal distance from the center to the closest corner, // times distErrPct IShape superwide = ctx.MakeRectangle(-180, 180, 0, 0); // LUCENENET specific: Added delta to the first 3 asserts because it is not a // valid expectation that they are exactly on the nose when dealing with floating point // types. And in .NET Core 2.0, the implementation has changed which now makes this test // fail without delta. //0 distErrPct means 0 distance always assertEquals(0, SpatialArgs.CalcDistanceFromErrPct(superwide, 0, ctx), 0.0001); assertEquals(180 * DEP, SpatialArgs.CalcDistanceFromErrPct(superwide, DEP, ctx), 0.0001); IShape supertall = ctx.MakeRectangle(0, 0, -90, 90); assertEquals(90 * DEP, SpatialArgs.CalcDistanceFromErrPct(supertall, DEP, ctx), 0.0001); IShape upperhalf = ctx.MakeRectangle(-180, 180, 0, 90); assertEquals(45 * DEP, SpatialArgs.CalcDistanceFromErrPct(upperhalf, DEP, ctx), 0.0001); IShape midCircle = ctx.MakeCircle(0, 0, 45); assertEquals(60 * DEP, SpatialArgs.CalcDistanceFromErrPct(midCircle, DEP, ctx), 0.0001); }
public void CalcDistanceFromErrPct() { SpatialContext ctx = SpatialContext.GEO; double DEP = 0.5;//distErrPct //the result is the diagonal distance from the center to the closest corner, // times distErrPct IShape superwide = ctx.MakeRectangle(-180, 180, 0, 0); //0 distErrPct means 0 distance always assertEquals(0, SpatialArgs.CalcDistanceFromErrPct(superwide, 0, ctx), 0); assertEquals(180 * DEP, SpatialArgs.CalcDistanceFromErrPct(superwide, DEP, ctx), 0); IShape supertall = ctx.MakeRectangle(0, 0, -90, 90); assertEquals(90 * DEP, SpatialArgs.CalcDistanceFromErrPct(supertall, DEP, ctx), 0); IShape upperhalf = ctx.MakeRectangle(-180, 180, 0, 90); assertEquals(45 * DEP, SpatialArgs.CalcDistanceFromErrPct(upperhalf, DEP, ctx), 0.0001); IShape midCircle = ctx.MakeCircle(0, 0, 45); assertEquals(60 * DEP, SpatialArgs.CalcDistanceFromErrPct(midCircle, DEP, ctx), 0.0001); }
private void DoSpatialSearch( SpatialContext ctx, SpatialStrategy strategy, TestIndex indexer, double searchRadius, string idToMatch, Func <SpatialArgs, Query> createQuery, int lat, int lng) { var searcher = (LuceneSearcher)indexer.GetSearcher(); var luceneSearcher = searcher.GetLuceneSearcher(); GetXYFromCoords(lat, lng, out var x, out var y); // Make a circle around the search point var args = new SpatialArgs( SpatialOperation.Intersects, ctx.MakeCircle(x, y, DistanceUtils.Dist2Degrees(searchRadius, DistanceUtils.EARTH_MEAN_RADIUS_KM))); var filter = strategy.MakeFilter(args); var query = createQuery(args); // TODO: It doesn't make a whole lot of sense to sort by score when searching on only geo-coords, // typically you would sort by closest distance // Which can be done, see https://github.com/apache/lucene-solr/blob/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java#L169 TopDocs docs = luceneSearcher.Search(query, filter, MaxResultDocs, new Sort(new SortField(null, SortField.SCORE))); AssertDocMatchedIds(luceneSearcher, docs, idToMatch); // TODO: We should make this possible and allow passing in a Lucene Filter // to the LuceneSearchQuery along with the Lucene Query, then we // don't need to manually perform the Lucene Search //var criteria = (LuceneSearchQuery)searcher.CreateQuery(); //criteria.LuceneQuery(q); //var results = criteria.Execute(); }
protected virtual Lucene.Net.Search.Query VisitWithinRadius(WithinRadiusNode node, LuceneQueryMapperState mappingState) { SpatialContext ctx = SpatialContext.GEO; var strategy = new PointVectorStrategy(ctx, Sitecore.ContentSearch.Spatial.Common.Constants.LocationFieldName); if (node.Latitude is double && node.Longitude is double && node.Radius is double) { var distance = DistanceUtils.Dist2Degrees((double)node.Radius, DistanceUtils.EARTH_MEAN_RADIUS_MI); Circle circle = ctx.MakeCircle((double)node.Longitude, (double)node.Latitude, distance); var spatialArgs = new SpatialArgs(SpatialOperation.Intersects, circle); var dq = strategy.MakeQuery(spatialArgs); DistanceReverseValueSource valueSource = new DistanceReverseValueSource(strategy, circle.GetCenter(), distance); ValueSourceFilter vsf = new ValueSourceFilter(new QueryWrapperFilter(dq), valueSource, 0, distance); var filteredSpatial = new FilteredQuery(new MatchAllDocsQuery(), vsf); Lucene.Net.Search.Query spatialRankingQuery = new FunctionQuery(valueSource); BooleanQuery bq = new BooleanQuery(); bq.Add(filteredSpatial, Occur.MUST); bq.Add(spatialRankingQuery, Occur.MUST); return(bq); } throw new NotSupportedException("Wrong parameters type, Radius, latitude and longitude must be of type double"); }
protected virtual Lucene.Net.Search.Query VisitWithinRadius(WithinRadiusNode node, LuceneQueryMapperState mappingState) { SpatialContext ctx = SpatialContext.GEO; var strategy = new PointVectorStrategy(ctx, Sitecore.ContentSearch.Spatial.Common.Constants.LocationFieldName); if (node.Latitude is double && node.Longitude is double && node.Radius is double) { var distance = DistanceUtils.Dist2Degrees((double)node.Radius, DistanceUtils.EARTH_MEAN_RADIUS_MI); Circle circle = ctx.MakeCircle((double)node.Longitude, (double)node.Latitude, distance); var spatialArgs = new SpatialArgs(SpatialOperation.IsWithin, circle); var dq = strategy.MakeQuery(spatialArgs); DistanceReverseValueSource valueSource = new DistanceReverseValueSource(strategy, circle.GetCenter(), distance); ValueSourceFilter vsf = new ValueSourceFilter(new QueryWrapperFilter(dq), valueSource, 0, distance); var filteredSpatial = new FilteredQuery(new MatchAllDocsQuery(), vsf); mappingState.FilterQuery = filteredSpatial; Lucene.Net.Search.Query spatialRankingQuery = new FunctionQuery(valueSource); Random r = new Random(DateTime.Now.Millisecond); var randomNumber = r.Next(10000101, 11000101); Lucene.Net.Search.Query dummyQuery = Lucene.Net.Search.NumericRangeQuery.NewIntRange("__smallcreateddate", randomNumber, Int32.Parse(DateTime.Now.ToString("yyyyMMdd")), true, true); BooleanQuery bq = new BooleanQuery(); bq.Add(filteredSpatial, Occur.MUST); bq.Add(spatialRankingQuery, Occur.MUST); bq.Add(dummyQuery, Occur.SHOULD); return(bq); } throw new NotSupportedException("Wrong parameters type, Radius, latitude and longitude must be of type double"); }
public void testCircle(SpatialContext ctx) { Shape s = ctx.ReadShape("Circle(1.23 4.56 distance=7.89)"); Assert.Equal(ctx.MakeCircle(1.23, 4.56, 7.89), s); Assert.Equal(s, WriteThenRead(s, ctx)); Assert.Equal(s, ctx.ReadShape("CIRCLE( 4.56,1.23 d=7.89 )")); // use lat,lon and use 'd' abbreviation Assert.True(s.HasArea()); }
public Filter ToFilter(SpatialContext spatialContext, SpatialPrefixTree tree) { var strategy = new RecursivePrefixTreeStrategy(tree, GeoFieldName); var spatialArgs = new SpatialArgs(SpatialOperation.Intersects, spatialContext.MakeCircle(X, Y, DistanceUtils.Dist2Degrees(this.Distance, DistanceUtils.EARTH_MEAN_RADIUS_KM))); return(strategy.MakeFilter(spatialArgs)); }
public void testCircleWithCriticalCulture(SpatialContext ctx) { using (new TemporaryCulture(new CultureInfo("de-DE"))) { Shape s = ctx.ReadShape("Circle(1.23 4.56 distance=7.89)"); Assert.Equal(ctx.MakeCircle(1.23, 4.56, 7.89), s); Assert.Equal(s, WriteThenRead(s, ctx)); Assert.Equal(s, ctx.ReadShape("CIRCLE( 4.56,1.23 d=7.89 )")); // use lat,lon and use 'd' abbreviation Assert.True(s.HasArea()); } }
private QueryHelper <TModel> GeoFilter(Expression <Func <TModel, object> > exp, double longitude, double latitude, double distDEG) { string name = getName(exp.Body.ToString()); //name = name.IndexOf('.') > -1 ? name.Substring(0, name.LastIndexOf('.')) : name; SpatialOperation op = SpatialOperation.Intersects; //SpatialStrategy strat = new PointVectorStrategy(ctx, name); int maxLevels = 11; SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels); var strat = new RecursivePrefixTreeStrategy(grid, name); var point = ctx.MakePoint(longitude, latitude); var shape = ctx.MakeCircle(point, distDEG); var args = new SpatialArgs(op, shape); filter = strat.MakeFilter(args); return(this); }
private SpatialArgs GetArgs(int docId, int distanceInKms) { Document doc = base.indexSearcher.IndexReader.Document(docId, null); SpatialContext ctx = _spatialStrategy.GetSpatialContext(); string[] parts = doc.Get(StrategyPrefix, null) .Split(' '); Point pt = ctx.MakePoint(double.Parse(parts[0]), double.Parse(parts[1])); Circle circle = ctx.MakeCircle(pt, DistanceUtils.Dist2Degrees(distanceInKms, DistanceUtils.EARTH_MEAN_RADIUS_KM)); var args = new SpatialArgs(SpatialOperation.Intersects, circle); return(args); }
public void testArea() { double radius = DistanceUtils.EARTH_MEAN_RADIUS_KM * DistanceUtils.KM_TO_DEG; //surface of a sphere is 4 * pi * r^2 double earthArea = 4 * Math.PI * radius * radius; Circle c = ctx.MakeCircle(random.Next(-180, 180), random.Next(-90, 90), 180); //180 means whole earth CustomAssert.EqualWithDelta(earthArea, c.GetArea(ctx), 1.0); CustomAssert.EqualWithDelta(earthArea, ctx.GetWorldBounds().GetArea(ctx), 1.0); //now check half earth Circle cHalf = ctx.MakeCircle(c.GetCenter(), 90); CustomAssert.EqualWithDelta(earthArea / 2, cHalf.GetArea(ctx), 1.0); //circle with same radius at +20 lat with one at -20 lat should have same area as well as bbox with same area Circle c2 = ctx.MakeCircle(c.GetCenter(), 30); Circle c3 = ctx.MakeCircle(c.GetCenter().GetX(), 20, 30); CustomAssert.EqualWithDelta(c2.GetArea(ctx), c3.GetArea(ctx), 0.01); Circle c3Opposite = ctx.MakeCircle(c.GetCenter().GetX(), -20, 30); CustomAssert.EqualWithDelta(c3.GetArea(ctx), c3Opposite.GetArea(ctx), 0.01); CustomAssert.EqualWithDelta(c3.GetBoundingBox().GetArea(ctx), c3Opposite.GetBoundingBox().GetArea(ctx), 0.01); //small shapes near the equator should have similar areas to euclidean rectangle Rectangle smallRect = ctx.MakeRectangle(0, 1, 0, 1); CustomAssert.EqualWithDelta(1.0, smallRect.GetArea(null), 0.0); double smallDelta = smallRect.GetArea(null) - smallRect.GetArea(ctx); Assert.True(smallDelta > 0 && smallDelta < 0.0001); Circle smallCircle = ctx.MakeCircle(0, 0, 1); smallDelta = smallCircle.GetArea(null) - smallCircle.GetArea(ctx); Assert.True(smallDelta > 0 && smallDelta < 0.0001); //bigger, but still fairly similar //c2 = ctx.makeCircle(c.getCenter(), 30); double areaRatio = c2.GetArea(null) / c2.GetArea(ctx); Assert.True(areaRatio > 1 && areaRatio < 1.1); }
static void Main(string[] args) { int maxLength = GeohashPrefixTree.GetMaxLevelsPossible(); strategy = new RecursivePrefixTreeStrategy( new GeohashPrefixTree(context, maxLength)); var dir = new RAMDirectory(); var writer = new IndexWriter(dir, new SimpleAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED); AddPoint(writer, "London", -81.233040, 42.983390); AddPoint(writer, "East New York", -73.882360, 40.666770); AddPoint(writer, "Manhattan", -73.966250, 40.783430); AddPoint(writer, "New York City", -74.005970, 40.714270); AddPoint(writer, "Oslo", 10.746090, 59.912730); AddPoint(writer, "Bergen", 5.324150, 60.392990); AddPoint(writer, "Washington, D. C.", -77.036370, 38.895110); writer.Close(); // Origin point - Oslo Spektrum const double lat = 59.9138688; const double lng = 10.752245399999993; const double radius = 600; var query = strategy.MakeQuery(new SpatialArgs(SpatialOperation.IsWithin, context.MakeCircle(lng, lat, radius)), fieldInfo); var searcher = new IndexSearcher(dir); var results = searcher.Search(query, null, 100); foreach (var topDoc in results.ScoreDocs) { var name = searcher.Doc(topDoc.doc).Get("Name"); Console.WriteLine(name); } searcher.Close(); dir.Close(); }
public virtual void TestSimplePoint(SpatialContext ctx) { base.ctx = ctx; Assert.Throws <InvalidShapeException>(() => ctx.MakePoint(2001, 0)); Assert.Throws <InvalidShapeException>(() => ctx.MakePoint(0, -301)); IPoint pt = ctx.MakePoint(0, 0); string msg = pt.ToString(); //test equals & hashcode IPoint pt2 = ctx.MakePoint(0, 0); Assert.Equal(/*msg,*/ pt, pt2); Assert.Equal(/*msg,*/ pt.GetHashCode(), pt2.GetHashCode()); Assert.False(pt.HasArea, msg); Assert.Equal(/*msg,*/ pt.Center, pt); IRectangle bbox = pt.BoundingBox; Assert.False(bbox.HasArea, msg); var center = bbox.Center; Assert.True(pt.Equals(center)); //Assert.Equal(/*msg,*/ pt, center); AssertRelation(msg, SpatialRelation.CONTAINS, pt, pt2); AssertRelation(msg, SpatialRelation.DISJOINT, pt, ctx.MakePoint(0, 1)); AssertRelation(msg, SpatialRelation.DISJOINT, pt, ctx.MakePoint(1, 0)); AssertRelation(msg, SpatialRelation.DISJOINT, pt, ctx.MakePoint(1, 1)); pt.Reset(1, 2); Assert.Equal(ctx.MakePoint(1, 2), pt); Assert.Equal(ctx.MakeCircle(pt, 3), pt.GetBuffered(3, ctx)); TestEmptiness(ctx.MakePoint(double.NaN, double.NaN)); }
public virtual ICircle ReadCircle(BinaryReader dataInput) { return(ctx.MakeCircle(ReadPoint(dataInput), ReadDim(dataInput))); }
/// <summary> /// Reads the shape specification as defined in the class javadocs. If the first character is /// a letter but it doesn't complete out "Circle" or "CIRCLE" then this method returns null, /// offering the caller the opportunity to potentially try additional parsing. /// If the first character is not a letter then it's assumed to be a point or rectangle. If that /// doesn't work out then an <see cref="InvalidShapeException"/> is thrown. /// </summary> /// <param name="str"></param> /// <param name="ctx"></param> /// <returns></returns> public static IShape ReadShapeOrNull(string str, SpatialContext ctx) { if (str == null || str.Length == 0) { throw new InvalidShapeException(str); } string[] tokens; int nextToken = 0; if (char.IsLetter(str[0])) { if (str.StartsWith("Circle(", StringComparison.Ordinal) || str.StartsWith("CIRCLE(", StringComparison.Ordinal)) { int idx = str.LastIndexOf(')'); if (idx > 0) { int circleLength = "Circle(".Length; string body = str.Substring(circleLength, idx - circleLength); tokens = body.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); nextToken = 0; string token = tokens[nextToken]; IPoint pt; if (token.IndexOf(',') != -1) { pt = ReadLatCommaLonPoint(token, ctx); } else { double x = double.Parse(token, CultureInfo.InvariantCulture); double y = double.Parse(token = tokens[++nextToken], CultureInfo.InvariantCulture); pt = ctx.MakePoint(x, y); } double?d = null; string arg = tokens[++nextToken]; idx = arg.IndexOf('='); if (idx > 0) { string k = arg.Substring(0, idx - 0); if (k.Equals("d", StringComparison.Ordinal) || k.Equals("distance", StringComparison.Ordinal)) { d = double.Parse(arg.Substring(idx + 1), CultureInfo.InvariantCulture); } else { throw new InvalidShapeException("unknown arg: " + k + " :: " + str); } } else { d = double.Parse(arg, CultureInfo.InvariantCulture); } // if we have additional tokens... if (nextToken < tokens.Length - 1) { throw new InvalidShapeException("Extra arguments: " + tokens[++nextToken] /*st.nextToken()*/ + " :: " + str); } if (d == null) { throw new InvalidShapeException("Missing Distance: " + str); } //NOTE: we are assuming the units of 'd' is the same as that of the spatial context. return(ctx.MakeCircle(pt, d.Value)); } } return(null);//caller has opportunity to try other parsing } if (str.IndexOf(',') != -1) { return(ReadLatCommaLonPoint(str, ctx)); } tokens = str.Split(' '); nextToken = 0; double p0 = double.Parse(tokens[nextToken], CultureInfo.InvariantCulture); double p1 = double.Parse(tokens[++nextToken], CultureInfo.InvariantCulture); // if we have additional tokens... if (nextToken < tokens.Length - 1) { double p2 = double.Parse(tokens[++nextToken], CultureInfo.InvariantCulture); double p3 = double.Parse(tokens[++nextToken], CultureInfo.InvariantCulture); // if we have additional tokens... if (nextToken < tokens.Length - 1) { throw new InvalidShapeException("Only 4 numbers supported (rect) but found more: " + str); } return(ctx.MakeRectangle(p0, p2, p1, p3)); } return(ctx.MakePoint(p0, p1)); }
/// <summary> /// Returns a new shape that is larger than shape by at distErr. /// </summary> protected virtual IShape BufferShape(IShape shape, double distErr) { //TODO move this generic code elsewhere? Spatial4j? if (distErr <= 0) { throw new ArgumentException("distErr must be > 0"); } SpatialContext ctx = m_grid.SpatialContext; if (shape is IPoint) { return(ctx.MakeCircle((IPoint)shape, distErr)); } else if (shape is ICircle) { var circle = (ICircle)shape; double newDist = circle.Radius + distErr; if (ctx.IsGeo && newDist > 180) { newDist = 180; } return(ctx.MakeCircle(circle.Center, newDist)); } else { IRectangle bbox = shape.BoundingBox; double newMinX = bbox.MinX - distErr; double newMaxX = bbox.MaxX + distErr; double newMinY = bbox.MinY - distErr; double newMaxY = bbox.MaxY + distErr; if (ctx.IsGeo) { if (newMinY < -90) { newMinY = -90; } if (newMaxY > 90) { newMaxY = 90; } if (newMinY == -90 || newMaxY == 90 || bbox.Width + 2 * distErr > 360) { newMinX = -180; newMaxX = 180; } else { newMinX = DistanceUtils.NormLonDEG(newMinX); newMaxX = DistanceUtils.NormLonDEG(newMaxX); } } else { //restrict to world bounds newMinX = Math.Max(newMinX, ctx.WorldBounds.MinX); newMaxX = Math.Min(newMaxX, ctx.WorldBounds.MaxX); newMinY = Math.Max(newMinY, ctx.WorldBounds.MinY); newMaxY = Math.Min(newMaxY, ctx.WorldBounds.MaxY); } return(ctx.MakeRectangle(newMinX, newMaxX, newMinY, newMaxY)); } }
public virtual IShape GetBuffered(double distance, SpatialContext ctx) { return(ctx.MakeCircle(this, distance)); }
/// <summary> /// Make a spatial query /// </summary> /// <param name="lat"></param> /// <param name="lng"></param> /// <param name="radius">Radius, in miles</param> /// <returns></returns> public static Query MakeQuery(double lat, double lng, double radius) { return(strategy.MakeQuery(new SpatialArgs(SpatialOperation.IsWithin, RavenSpatialContext.MakeCircle(lng, lat, radius)), fieldInfo)); }
public virtual void TestGeoCircle(SpatialContext ctx) { base.ctx = ctx; Assert.Equal(string.Format("Circle(Pt(x={0:0.0},y={1:0.0}), d={2:0.0}° {3:0.00}km)", 10, 20, 30, 3335.85), ctx.MakeCircle(10, 20, 30).ToString()); double v = 200 * (random.NextDouble() > 0.5 ? -1 : 1); Assert.Throws <InvalidShapeException>(() => ctx.MakeCircle(v, 0, 5)); Assert.Throws <InvalidShapeException>(() => ctx.MakeCircle(0, v, 5)); //Assert.Throws<InvalidShapeException>(() => ctx.MakeCircle(random.Next(-180, 180), random.Next(-90, 90), v)); //--Start with some static tests that once failed: //Bug: numeric edge at pole, fails to init ctx.MakeCircle(110, -12, 90 + 12); //Bug: horizXAxis not in enclosing rectangle, assertion ctx.MakeCircle(-44, 16, 106); ctx.MakeCircle(-36, -76, 14); ctx.MakeCircle(107, 82, 172); // TODO need to update this test to be valid //{ // //Bug in which distance was being confused as being in the same coordinate system as x,y. // double distDeltaToPole = 0.001;//1m // double distDeltaToPoleDEG = ctx.getDistCalc().distanceToDegrees(distDeltaToPole); // double dist = 1;//1km // double distDEG = ctx.getDistCalc().distanceToDegrees(dist); // Circle c = ctx.makeCircle(0, 90 - distDeltaToPoleDEG - distDEG, dist); // Rectangle cBBox = c.getBoundingBox(); // Rectangle r = ctx.makeRect(cBBox.getMaxX() * 0.99, cBBox.getMaxX() + 1, c.getCenter().getY(), c.getCenter().getY()); // assertEquals(INTERSECTS, c.getBoundingBox().relate(r, ctx)); // assertEquals("dist != xy space", INTERSECTS, c.relate(r, ctx));//once failed here //} AssertEquals("bad proportion logic", SpatialRelation.INTERSECTS, ctx.MakeCircle(64, -70, 18).Relate(ctx.MakeRectangle(46, 116, -86, -62))); AssertEquals("Both touch pole", SpatialRelation.INTERSECTS, ctx.MakeCircle(-90, 30, 60).Relate(ctx.MakeRectangle(-24, -16, 14, 90))); AssertEquals("Spherical cap should contain enclosed band", SpatialRelation.CONTAINS, ctx.MakeCircle(0, -90, 30).Relate(ctx.MakeRectangle(-180, 180, -90, -80))); AssertEquals("touches pole", SpatialRelation.INTERSECTS, ctx.MakeCircle(0, -88, 2).Relate(ctx.MakeRectangle(40, 60, -90, -86))); AssertEquals("wrong farthest opp corner", SpatialRelation.INTERSECTS, ctx.MakeCircle(92, 36, 46).Relate(ctx.MakeRectangle(134, 136, 32, 80))); AssertEquals("edge rounding issue 2", SpatialRelation.INTERSECTS, ctx.MakeCircle(84, -40, 136).Relate(ctx.MakeRectangle(-150, -80, 34, 84))); AssertEquals("edge rounding issue", SpatialRelation.CONTAINS, ctx.MakeCircle(0, 66, 156).Relate(ctx.MakePoint(0, -90))); AssertEquals("nudge back circle", SpatialRelation.CONTAINS, ctx.MakeCircle(-150, -90, 122).Relate(ctx.MakeRectangle(0, -132, 32, 32))); AssertEquals("wrong estimate", SpatialRelation.DISJOINT, ctx.MakeCircle(-166, 59, KmToDeg(5226.2)).Relate(ctx.MakeRectangle(36, 66, 23, 23))); AssertEquals("bad CONTAINS (dateline)", SpatialRelation.INTERSECTS, ctx.MakeCircle(56, -50, KmToDeg(12231.5)).Relate(ctx.MakeRectangle(108, 26, 39, 48))); AssertEquals("bad CONTAINS (backwrap2)", SpatialRelation.INTERSECTS, ctx.MakeCircle(112, -3, 91).Relate(ctx.MakeRectangle(-163, 29, -38, 10))); AssertEquals("bad CONTAINS (r x-wrap)", SpatialRelation.INTERSECTS, ctx.MakeCircle(-139, 47, 80).Relate(ctx.MakeRectangle(-180, 180, -3, 12))); AssertEquals("bad CONTAINS (pwrap)", SpatialRelation.INTERSECTS, ctx.MakeCircle(-139, 47, 80).Relate(ctx.MakeRectangle(-180, 179, -3, 12))); AssertEquals("no-dist 1", SpatialRelation.WITHIN, ctx.MakeCircle(135, 21, 0).Relate(ctx.MakeRectangle(-103, -154, -47, 52))); AssertEquals("bbox <= >= -90 bug", SpatialRelation.CONTAINS, ctx.MakeCircle(-64, -84, 124).Relate(ctx.MakeRectangle(-96, 96, -10, -10))); //The horizontal axis line of a geo circle doesn't necessarily pass through c's ctr. AssertEquals("c's horiz axis doesn't pass through ctr", SpatialRelation.INTERSECTS, ctx.MakeCircle(71, -44, 40).Relate(ctx.MakeRectangle(15, 27, -62, -34))); AssertEquals("pole boundary", SpatialRelation.INTERSECTS, ctx.MakeCircle(-100, -12, 102).Relate(ctx.MakeRectangle(143, 175, 4, 32))); AssertEquals("full circle assert", SpatialRelation.CONTAINS, ctx.MakeCircle(-64, 32, 180).Relate(ctx.MakeRectangle(47, 47, -14, 90))); //--Now proceed with systematic testing: AssertEquals(ctx.WorldBounds, ctx.MakeCircle(0, 0, 180).BoundingBox); //assertEquals(ctx.makeCircle(0,0,distToOpposeSide/2 - 500).getBoundingBox()); double[] theXs = new double[] { -180, -45, 90 }; foreach (double x in theXs) { double[] theYs = new double[] { -90, -45, 0, 45, 90 }; foreach (double y in theYs) { TestCircle(x, y, 0); TestCircle(x, y, KmToDeg(500)); TestCircle(x, y, 90); TestCircle(x, y, 180); } } TestCircleIntersect(); }
public virtual IShape GetBuffered(double distance, SpatialContext ctx) { return(ctx.MakeCircle(point, distance + radiusDEG)); }
/// <summary>Returns a new shape that is larger than shape by at distErr.</summary> /// <remarks>Returns a new shape that is larger than shape by at distErr.</remarks> protected internal virtual Shape BufferShape(Shape shape, double distErr) { //TODO move this generic code elsewhere? Spatial4j? if (distErr <= 0) { throw new ArgumentException("distErr must be > 0"); } SpatialContext ctx = grid.SpatialContext; if (shape is Point) { return(ctx.MakeCircle((Point)shape, distErr)); } else { if (shape is Circle) { var circle = (Circle)shape; double newDist = circle.GetRadius() + distErr; if (ctx.IsGeo() && newDist > 180) { newDist = 180; } return(ctx.MakeCircle(circle.GetCenter(), newDist)); } else { Rectangle bbox = shape.GetBoundingBox(); double newMinX = bbox.GetMinX() - distErr; double newMaxX = bbox.GetMaxX() + distErr; double newMinY = bbox.GetMinY() - distErr; double newMaxY = bbox.GetMaxY() + distErr; if (ctx.IsGeo()) { if (newMinY < -90) { newMinY = -90; } if (newMaxY > 90) { newMaxY = 90; } if (newMinY == -90 || newMaxY == 90 || bbox.GetWidth() + 2 * distErr > 360) { newMinX = -180; newMaxX = 180; } else { newMinX = DistanceUtils.NormLonDEG(newMinX); newMaxX = DistanceUtils.NormLonDEG(newMaxX); } } else { //restrict to world bounds newMinX = Math.Max(newMinX, ctx.GetWorldBounds().GetMinX()); newMaxX = Math.Min(newMaxX, ctx.GetWorldBounds().GetMaxX()); newMinY = Math.Max(newMinY, ctx.GetWorldBounds().GetMinY()); newMaxY = Math.Min(newMaxY, ctx.GetWorldBounds().GetMaxY()); } return(ctx.MakeRectangle(newMinX, newMaxX, newMinY, newMaxY)); } } }
public static void SearchSample() { Directory dir = new RAMDirectory(); Analyzer analyzer = new StandardAnalyzer(Version); var indexWriter = new IndexWriter(dir, analyzer, IndexWriter.MaxFieldLength.UNLIMITED); SpatialContext ctx = SpatialContext.GEO; var strategy = new PointVectorStrategy(ctx, SpartialFieldName); //var precision = 8; // Precision 8 means down to 19 meter - higher precision consumes more memory //SpatialPrefixTree grid = new GeohashPrefixTree(ctx, precision); //var strategy = new RecursivePrefixTreeStrategy(grid, spartialFieldName); var docs = CreateSearchDocuments(GetDeals(), strategy); foreach (var doc in docs) { indexWriter.AddDocument(doc); } indexWriter.Commit(); indexWriter.Dispose(); // "Current" position Point littleMermaid = ctx.MakePoint(12.599239, 55.692848); //var parser = new QueryParser(Version, "title", analyzer); //Query q = parser.Parse("deal"); Query q = new MatchAllDocsQuery(); // NOTE: MatchAllDocsQuery always returns score as 1.0 // Add distance from current point to the scoring q = new DistanceCustomScoreQuery(q, strategy, littleMermaid); //q = new RecursivePrefixTreeStrategyDistanceCustomScoreQuery(q, strategy, littleMermaid, spartialFieldName); // Remove everything more than 2000 km away var filter = strategy.MakeFilter(new SpatialArgs(SpatialOperation.Intersects, ctx.MakeCircle(littleMermaid, DistanceUtils.Dist2Degrees(2000, DistanceUtils.EARTH_MEAN_RADIUS_KM)))); // Ensures the most recent searcher is used without destroying the Lucene IndexReader cache (via NRT) var searcherManager = new SearcherManager(dir); var collector = new GroupTopDocsCollector(5, SupplierFieldName); var searcher = searcherManager.GetSearcher(); try { searcher.Search(q, filter, collector); } finally { searcherManager.ReleaseSearcher(searcher); } var hits = collector.GroupTopDocs(); Console.WriteLine("Found {0} document(s) that matched query '{1}':", hits.TotalHits, q); foreach (var match in hits.GroupScoreDocs) { Document doc = searcher.Doc(match.Doc); Console.WriteLine("Best match '{0}' in group '{1}' with count {2} (MaxDoc: Score {3} Location '{4}')", doc.Get(TitleFieldName), match.GroupFieldValue, match.GroupCount, match.Score, doc.Get(LocationNameFieldName)); } }