/** Reads the stream, consuming a format that is a tab-separated values of 3 columns: * an "id", a "name" and the "shape". Empty lines and lines starting with a '#' are skipped. * The stream is closed. */ public static IEnumerator<SpatialTestData> GetTestData(Stream @in, SpatialContext ctx) { List<SpatialTestData> results = new List<SpatialTestData>(); TextReader bufInput = new StreamReader(@in, Encoding.UTF8); try { String line; while ((line = bufInput.ReadLine()) != null) { if (line.Length == 0 || line[0] == '#') continue; SpatialTestData data = new SpatialTestData(); String[] vals = line.Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries); if (vals.Length != 3) throw new ArgumentException("bad format; expecting 3 tab-separated values for line: " + line); data.id = vals[0]; data.name = vals[1]; try { data.shape = ctx.ReadShapeFromWkt(vals[2]); } catch (ParseException e) { throw new ApplicationException(e.Message, e); } results.Add(data); } } finally { bufInput.Dispose(); } return results.GetEnumerator(); }
/// <summary> /// Gets the error distance that specifies how precise the query shape is. This /// looks at <see cref="DistErr"/>, <see cref="DistErrPct"/>, and /// <paramref name="defaultDistErrPct"/>. /// </summary> /// <param name="ctx"></param> /// <param name="defaultDistErrPct">0 to 0.5</param> /// <returns>>= 0</returns> public virtual double ResolveDistErr(SpatialContext ctx, double defaultDistErrPct) { if (DistErr != null) return DistErr.Value; double distErrPct = (this.distErrPct ?? defaultDistErrPct); return CalcDistanceFromErrPct(Shape, distErrPct, ctx); }
//1m /// <summary>The factory is looked up via "prefixTree" in args, expecting "geohash" or "quad". /// </summary> /// <remarks> /// The factory is looked up via "prefixTree" in args, expecting "geohash" or "quad". /// If its neither of these, then "geohash" is chosen for a geo context, otherwise "quad" is chosen. /// </remarks> public static SpatialPrefixTree MakeSPT(IDictionary<string, string> args, SpatialContext ctx) { SpatialPrefixTreeFactory instance; string cname = args[PrefixTree]; if (cname == null) { cname = ctx.IsGeo() ? "geohash" : "quad"; } if ("geohash".Equals(cname, StringComparison.OrdinalIgnoreCase)) { instance = new GeohashPrefixTree.Factory(); } else { if ("quad".Equals(cname, StringComparison.OrdinalIgnoreCase)) { instance = new QuadPrefixTree.Factory(); } else { try { Type c = Type.GetType(cname); instance = (SpatialPrefixTreeFactory)System.Activator.CreateInstance(c); } catch (Exception e) { throw new Exception(string.Empty, e); } } } instance.Init(args, ctx); return instance.NewSPT(); }
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 QuadPrefixTree(SpatialContext ctx, Rectangle bounds, int maxLevels) : base(ctx, maxLevels) { //not really sure how big this should be // side // number xmin = bounds.GetMinX(); xmax = bounds.GetMaxX(); ymin = bounds.GetMinY(); ymax = bounds.GetMaxY(); levelW = new double[maxLevels]; levelH = new double[maxLevels]; levelS = new int[maxLevels]; levelN = new int[maxLevels]; gridW = xmax - xmin; gridH = ymax - ymin; xmid = xmin + gridW / 2.0; ymid = ymin + gridH / 2.0; levelW[0] = gridW / 2.0; levelH[0] = gridH / 2.0; levelS[0] = 2; levelN[0] = 4; for (int i = 1; i < levelW.Length; i++) { levelW[i] = levelW[i - 1] / 2.0; levelH[i] = levelH[i - 1] / 2.0; levelS[i] = levelS[i - 1] * 2; levelN[i] = levelN[i - 1] * 4; } }
internal readonly int[] levelN; // number public QuadPrefixTree(SpatialContext ctx, IRectangle bounds, int maxLevels) : base(ctx, maxLevels) { xmin = bounds.MinX; xmax = bounds.MaxX; ymin = bounds.MinY; ymax = bounds.MaxY; levelW = new double[maxLevels]; levelH = new double[maxLevels]; levelS = new int[maxLevels]; levelN = new int[maxLevels]; gridW = xmax - xmin; gridH = ymax - ymin; this.xmid = xmin + gridW / 2.0; this.ymid = ymin + gridH / 2.0; levelW[0] = gridW / 2.0; levelH[0] = gridH / 2.0; levelS[0] = 2; levelN[0] = 4; for (int i = 1; i < levelW.Length; i++) { levelW[i] = levelW[i - 1] / 2.0; levelH[i] = levelH[i - 1] / 2.0; levelS[i] = levelS[i - 1] * 2; levelN[i] = levelN[i - 1] * 4; } }
public void testMultiShape(SpatialContext ctx) { this.ctx = ctx; if(ctx.IsGeo()) return;//TODO not yet supported! //come up with some random shapes int NUM_SHAPES = random.Next(1, 5); var shapes = new List<Rectangle>(NUM_SHAPES); while (shapes.Count < NUM_SHAPES) { shapes.Add(RandomRectangle(20)); } var multiShape = new MultiShape(shapes.Cast<Shape>(), ctx); //test multiShape.getBoundingBox(); Rectangle msBbox = multiShape.GetBoundingBox(); if (shapes.Count == 1) { Assert.Equal(shapes[0], msBbox.GetBoundingBox()); } else { foreach (Rectangle shape in shapes) { AssertRelation("bbox contains shape", SpatialRelation.CONTAINS, msBbox, shape); } } //TODO test multiShape.relate() }
public override void TearDown() { base.TearDown(); ctx = null; strategy = null; storeShape = true; }
/// <summary>The factory is looked up via "prefixTree" in args, expecting "geohash" or "quad".</summary> /// <remarks> /// The factory is looked up via "prefixTree" in args, expecting "geohash" or "quad". /// If its neither of these, then "geohash" is chosen for a geo context, otherwise "quad" is chosen. /// </remarks> public static SpatialPrefixTree MakeSPT(IDictionary<string, string> args, SpatialContext ctx) { SpatialPrefixTreeFactory instance; string cname; if (!args.TryGetValue(PREFIX_TREE, out cname)) { cname = ctx.IsGeo ? "geohash" : "quad"; } if ("geohash".Equals(cname, StringComparison.OrdinalIgnoreCase)) { instance = new GeohashPrefixTree.Factory(); } else if ("quad".Equals(cname, StringComparison.OrdinalIgnoreCase)) { instance = new QuadPrefixTree.Factory(); } else { try { Type c = Type.GetType(cname); instance = (SpatialPrefixTreeFactory)Activator.CreateInstance(c); } catch (Exception e) { throw new ApplicationException(string.Empty, e); } } instance.Init(args, ctx); return instance.NewSPT(); }
protected void Init(SpatialContext ctx, Rectangle bounds, int maxLevels) { this.xmin = bounds.GetMinX(); this.xmax = bounds.GetMaxX(); this.ymin = bounds.GetMinY(); this.ymax = bounds.GetMaxY(); levelW = new double[maxLevels]; levelH = new double[maxLevels]; levelS = new int[maxLevels]; levelN = new int[maxLevels]; gridW = xmax - xmin; gridH = ymax - ymin; xmid = xmin + gridW / 2.0; ymid = ymin + gridH / 2.0; levelW[0] = gridW / 2.0; levelH[0] = gridH / 2.0; levelS[0] = 2; levelN[0] = 4; for (int i = 1; i < levelW.Length; i++) { levelW[i] = levelW[i - 1] / 2.0; levelH[i] = levelH[i - 1] / 2.0; levelS[i] = levelS[i - 1] * 2; levelN[i] = levelN[i - 1] * 4; } }
public override Rectangle CalcBoxByDistFromPt(Point @from, double distance, SpatialContext ctx) { Debug.Assert(radius == ctx.GetUnits().EarthRadius()); if (distance == 0) return from.GetBoundingBox(); return DistanceUtils.CalcBoxByDistFromPtDEG(from.GetY(), from.GetX(), distance, ctx); }
//we don't have a line shape so we use a rectangle for these axis public CircleImpl(Point p, double dist, SpatialContext ctx) { //We assume any normalization / validation of params already occurred (including bounding dist) this.point = p; this.distRadius = dist; this.ctx = ctx; this.enclosingBox = ctx.GetDistCalc().CalcBoxByDistFromPt(point, distRadius, ctx); }
//we don't have a line shape so we use a rectangle for these axis public CircleImpl(Point p, double radiusDEG, SpatialContext ctx) { //We assume any validation of params already occurred (including bounding dist) this.ctx = ctx; this.point = p; this.radiusDEG = radiusDEG; this.enclosingBox = ctx.GetDistCalc().CalcBoxByDistFromPt(point, this.radiusDEG, ctx, null); }
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 ShapeFieldCacheDistanceValueSource(SpatialContext ctx, ShapeFieldCacheProvider<IPoint> provider, IPoint from, double multiplier) { this.ctx = ctx; this.from = from; this.provider = provider; this.multiplier = multiplier; }
/// <summary> /// Constructs the spatial strategy with its mandatory arguments. /// </summary> /// <param name="ctx"></param> /// <param name="fieldName"> </param> protected SpatialStrategy(SpatialContext ctx, string fieldName) { if (ctx == null) throw new ArgumentException("ctx is required", "ctx"); this.ctx = ctx; if (string.IsNullOrEmpty(fieldName)) throw new ArgumentException("fieldName is required", "fieldName"); this.fieldName = fieldName; }
private readonly double nullValue;//computed public DistanceToShapeValueSource(ValueSource shapeValueSource, IPoint queryPoint, double multiplier, SpatialContext ctx) { this.shapeValueSource = shapeValueSource; this.queryPoint = queryPoint; this.multiplier = multiplier; this.distCalc = ctx.DistCalc; this.nullValue = (ctx.IsGeo ? 180 * multiplier : double.MaxValue); }
public int precisionStep = 8; // same as solr default #endregion Fields #region Constructors public BBoxStrategy(SpatialContext ctx, String fieldNamePrefix) : base(ctx, fieldNamePrefix) { field_bbox = fieldNamePrefix; field_minX = fieldNamePrefix + SUFFIX_MINX; field_maxX = fieldNamePrefix + SUFFIX_MAXX; field_minY = fieldNamePrefix + SUFFIX_MINY; field_maxY = fieldNamePrefix + SUFFIX_MAXY; field_xdl = fieldNamePrefix + SUFFIX_XDL; }
public void TestDefault() { SpatialContext ctx = SpatialContext.GEO; SpatialContext ctx2 = Call();//default Assert.Equal(ctx.GetType(), ctx2.GetType()); Assert.Equal(ctx.IsGeo, ctx2.IsGeo); Assert.Equal(ctx.DistCalc, ctx2.DistCalc); Assert.Equal(ctx.WorldBounds, ctx2.WorldBounds); }
public GeohashPrefixTree(SpatialContext ctx, int maxLevels) : base(ctx, maxLevels) { Rectangle bounds = ctx.GetWorldBounds(); if (bounds.GetMinX() != -180) throw new ArgumentException("Geohash only supports lat-lon world bounds. Got " + bounds); int MAXP = GetMaxLevelsPossible(); if (maxLevels <= 0 || maxLevels > MAXP) throw new ArgumentException("maxLen must be [1-" + MAXP + "] but got " + maxLevels); }
public void testMakeRect(SpatialContext ctx) { this.ctx = ctx; //test rectangle constructor Assert.Equal(new RectangleImpl(1, 3, 2, 4), new RectangleImpl(new PointImpl(1, 2), new PointImpl(3, 4))); //test ctx.makeRect Assert.Equal(ctx.MakeRect(1, 3, 2, 4), ctx.MakeRect(ctx.MakePoint(1, 2), ctx.MakePoint(3, 4))); }
/** * Get Test Queries. The InputStream is closed. */ public static IEnumerator<SpatialTestQuery> GetTestQueries( SpatialArgsParser parser, SpatialContext ctx, string name, Stream @in) { List<SpatialTestQuery> results = new List<SpatialTestQuery>(); TextReader bufInput = new StreamReader(@in, Encoding.UTF8); try { String line; for (int lineNumber = 1; (line = bufInput.ReadLine()) != null; lineNumber++) { SpatialTestQuery test = new SpatialTestQuery(); test.line = line; test.lineNumber = lineNumber; try { // skip a comment if (line.StartsWith("[", StringComparison.Ordinal)) { int idx2 = line.IndexOf(']'); if (idx2 > 0) { line = line.Substring(idx2 + 1); } } int idx = line.IndexOf('@'); StringTokenizer st = new StringTokenizer(line.Substring(0, idx - 0)); while (st.HasMoreTokens()) { test.ids.Add(st.NextToken().Trim()); } test.args = parser.Parse(line.Substring(idx + 1).Trim(), ctx); results.Add(test); } catch (Exception ex) { throw new ApplicationException("invalid query line: " + test.line, ex); } } } finally { bufInput.Dispose(); } return results.GetEnumerator(); }
protected void InitWorldBounds() { String worldBoundsStr; if (!Args.TryGetValue("worldBounds", out worldBoundsStr) || worldBoundsStr == null) { return; } //kinda ugly we do this just to read a rectangle. TODO refactor var simpleCtx = new SpatialContext(geo, Calculator, null); WorldBounds = (Rectangle)simpleCtx.ReadShape(worldBoundsStr); }
public GeohashPrefixTree(SpatialContext ctx, int maxLevels) : base(ctx, maxLevels) { IRectangle bounds = ctx.WorldBounds; if (bounds.MinX != -180) { throw new ArgumentException("Geohash only supports lat-lon world bounds. Got " + bounds); } int Maxp = MaxLevelsPossible; if (maxLevels <= 0 || maxLevels > Maxp) { throw new ArgumentException("maxLen must be [1-" + Maxp + "] but got " + maxLevels); } }
protected void Init() { //Typical geospatial context // These can also be constructed from SpatialContextFactory this.ctx = SpatialContext.GEO; int maxLevels = 11;//results in sub-meter precision for geohash //TODO demo lookup by detail distance // This can also be constructed from SpatialPrefixTreeFactory SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels); this.strategy = new RecursivePrefixTreeStrategy(grid, "myGeoField"); this.directory = new RAMDirectory(); }
public override Point PointOnBearing(Point @from, double distDEG, double bearingDEG, SpatialContext ctx, Point reuse) { if (distDEG == 0) { if (reuse == null) return from; reuse.Reset(from.GetX(), from.GetY()); return reuse; } Point result = DistanceUtils.PointOnBearingRAD( DistanceUtils.ToRadians(from.GetY()), DistanceUtils.ToRadians(from.GetX()), DistanceUtils.ToRadians(distDEG), DistanceUtils.ToRadians(bearingDEG), ctx, reuse);//output result is in radians result.Reset(DistanceUtils.ToDegrees(result.GetX()), DistanceUtils.ToDegrees(result.GetY())); return result; }
public AreaSimilarity(SpatialContext ctx, Rectangle queryExtent, double queryPower, double targetPower) { this.ctx = ctx; this.queryExtent = queryExtent; this.queryArea = queryExtent.GetArea(ctx); this.queryPower = queryPower; this.targetPower = targetPower; // if (this.qryMinX > queryExtent.getMaxX()) { // this.qryCrossedDateline = true; // this.qryArea = Math.abs(qryMaxX + 360.0 - qryMinX) * Math.abs(qryMaxY - qryMinY); // } else { // this.qryArea = Math.abs(qryMaxX - qryMinX) * Math.abs(qryMaxY - qryMinY); // } }
public override Rectangle CalcBoxByDistFromPt(Point from, double distDEG, SpatialContext ctx, Rectangle reuse) { double minX = from.GetX() - distDEG; double maxX = from.GetX() + distDEG; double minY = from.GetY() - distDEG; double maxY = from.GetY() + distDEG; if (reuse == null) { return ctx.MakeRectangle(minX, maxX, minY, maxY); } else { reuse.Reset(minX, maxX, minY, maxY); return reuse; } }
/// <summary> /// Computes the distance given a shape and the {@code distErrPct}. The /// algorithm is the fraction of the distance from the center of the query /// shape to its furthest bounding box corner. /// </summary> /// <param name="shape">Mandatory.</param> /// <param name="distErrPct">0 to 0.5</param> /// <param name="ctx">Mandatory</param> /// <returns>A distance (in degrees).</returns> public static double CalcDistanceFromErrPct(Shape shape, double distErrPct, SpatialContext ctx) { if (distErrPct < 0 || distErrPct > 0.5) { throw new ArgumentException("distErrPct " + distErrPct + " must be between [0 to 0.5]", "distErrPct"); } if (distErrPct == 0 || shape is Point) { return 0; } Rectangle bbox = shape.GetBoundingBox(); //The diagonal distance should be the same computed from any opposite corner, // and this is the longest distance that might be occurring within the shape. double diagonalDist = ctx.GetDistCalc().Distance( ctx.MakePoint(bbox.GetMinX(), bbox.GetMinY()), bbox.GetMaxX(), bbox.GetMaxY()); return diagonalDist*0.5*distErrPct; }
public SampleDataWriter(string filePath, SpatialContext ctx, bool bbox, int maxLength) { this.ctx = ctx; this.bbox = bbox; this.maxLength = maxLength; @out = new StringWriter(/*new FileStream(filePath, FileMode.Create)*/); @out.Write("#id"); @out.Write('\t'); @out.Write("name"); @out.Write('\t'); @out.Write("shape"); @out.Write('\t'); @out.WriteLine(); @out.Flush(); }
private readonly GeoCircle inverseCircle; //when distance reaches > 1/2 way around the world, cache the inverse. #endregion Fields #region Constructors public GeoCircle(Point p, double dist, SpatialContext ctx) : base(p, dist, ctx) { Debug.Assert(ctx.IsGeo()); //In the direction of latitude (N,S), distance is the same number of degrees. distDEG = ctx.GetDistCalc().DistanceToDegrees(distRadius); if (distDEG > 90) { //--spans more than half the globe Debug.Assert(enclosingBox.GetWidth() == 360); double backDistDEG = 180 - distDEG; if (backDistDEG > 0) { double backDistance = ctx.GetDistCalc().DegreesToDistance(backDistDEG); //shrink inverseCircle as small as possible to avoid accidental overlap backDistance -= Ulp(backDistance); Point backPoint = ctx.MakePoint(GetCenter().GetX() + 180, GetCenter().GetY() + 180); inverseCircle = new GeoCircle(backPoint, backDistance, ctx); } else inverseCircle = null;//whole globe horizAxisY = GetCenter().GetY();//although probably not used } else { inverseCircle = null; double _horizAxisY = ctx.GetDistCalc().CalcBoxByDistFromPt_yHorizAxisDEG(GetCenter(), dist, ctx); //some rare numeric conditioning cases can cause this to be barely beyond the box if (_horizAxisY > enclosingBox.GetMaxY()) { horizAxisY = enclosingBox.GetMaxY(); } else if (_horizAxisY < enclosingBox.GetMinY()) { horizAxisY = enclosingBox.GetMinY(); } else { horizAxisY = _horizAxisY; } //Debug.Assert(enclosingBox.Relate_yRange(horizAxis, horizAxis, ctx).Intersects()); } }
/// <summary> /// The factory is looked up via "prefixTree" in args, expecting "geohash" or "quad". /// If its neither of these, then "geohash" is chosen for a geo context, otherwise "quad" is chosen. /// </summary> /// <param name="args"></param> /// <param name="ctx"></param> /// <returns></returns> public static SpatialPrefixTree MakeSPT(Dictionary<String, String> args, SpatialContext ctx) { SpatialPrefixTreeFactory instance; String cname; if (!args.TryGetValue(PREFIX_TREE, out cname) || cname == null) cname = ctx.IsGeo() ? "geohash" : "quad"; if ("geohash".Equals(cname, StringComparison.InvariantCultureIgnoreCase)) instance = new GeohashPrefixTree.Factory(); else if ("quad".Equals(cname, StringComparison.InvariantCultureIgnoreCase)) instance = new QuadPrefixTree.Factory(); else { Type t = Type.GetType(cname); instance = (SpatialPrefixTreeFactory)Activator.CreateInstance(t); } instance.Init(args, ctx); return instance.NewSPT(); }
public void TestCustom() { SpatialContext ctx = Call("geo", "false"); Assert.True(!ctx.IsGeo); Assert.Equal(new CartesianDistCalc(), ctx.DistCalc); ctx = Call("geo", "false", "distCalculator", "cartesian^2", "worldBounds", "ENVELOPE(-100, 75, 200, 0)");//xMin, xMax, yMax, yMin Assert.Equal(new CartesianDistCalc(true), ctx.DistCalc); Assert.Equal(new Rectangle(-100, 75, 0, 200, ctx), ctx.WorldBounds); ctx = Call("geo", "true", "distCalculator", "lawOfCosines"); Assert.True(ctx.IsGeo); var test = new GeodesicSphereDistCalc.LawOfCosines(); Assert.Equal(test, ctx.DistCalc); }
public virtual BinaryCodec MakeBinaryCodec(SpatialContext ctx) { return(MakeClassInstance <BinaryCodec>(binaryCodecClass, ctx, this)); }
public virtual WktShapeParser MakeWktShapeParser(SpatialContext ctx) { return(MakeClassInstance <WktShapeParser>(wktShapeParserClass, ctx, this)); }