public void TestDefault()
        {
            SpatialContext s = SpatialContext.GEO;
            SpatialContext t = Call();//default

            Assert.Equal(s.GetType(), t.GetType());
            Assert.Equal(s.IsGeo(), t.IsGeo());
            Assert.Equal(s.GetDistCalc(), t.GetDistCalc());
            Assert.Equal(s.GetWorldBounds(), t.GetWorldBounds());
        }
        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);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Given a cell having the specified level, returns the distance from opposite
        /// corners.
        /// </summary>
        /// <remarks>
        /// Given a cell having the specified level, returns the distance from opposite
        /// corners. Since this might very depending on where the cell is, this method
        /// may over-estimate.
        /// </remarks>
        /// <param name="level">[1 to maxLevels]</param>
        /// <returns>&gt; 0</returns>
        public virtual double GetDistanceForLevel(int level)
        {
            if (level < 1 || level > MaxLevels)
            {
                throw new ArgumentException("Level must be in 1 to maxLevels range");
            }
            //TODO cache for each level
            Cell      cell   = GetCell(ctx.GetWorldBounds().GetCenter(), level);
            Rectangle bbox   = cell.GetShape().GetBoundingBox();
            double    width  = bbox.GetWidth();
            double    height = bbox.GetHeight();

            //Use standard cartesian hypotenuse. For geospatial, this answer is larger
            // than the correct one but it's okay to over-estimate.
            return(Math.Sqrt(width * width + height * height));
        }
Exemplo n.º 4
0
        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);
        }
Exemplo n.º 5
0
        public void TestGeoRectangle(SpatialContext ctx)
        {
            base.ctx = ctx;

            double v = 200 * (random.NextDouble() > 0.5 ? -1 : 1);

            Assert.Throws <InvalidShapeException>(() => ctx.MakeRectangle(v, 0, 0, 0));
            Assert.Throws <InvalidShapeException>(() => ctx.MakeRectangle(0, v, 0, 0));
            Assert.Throws <InvalidShapeException>(() => ctx.MakeRectangle(0, 0, v, 0));
            Assert.Throws <InvalidShapeException>(() => ctx.MakeRectangle(0, 0, 0, v));
            Assert.Throws <InvalidShapeException>(() => ctx.MakeRectangle(0, 0, 10, -10));

            //test some relateXRange
            //    opposite +/- 180
            Assert.Equal(SpatialRelation.INTERSECTS, ctx.MakeRectangle(170, 180, 0, 0).RelateXRange(-180, -170));
            Assert.Equal(SpatialRelation.INTERSECTS, ctx.MakeRectangle(-90, -45, 0, 0).RelateXRange(-45, -135));
            Assert.Equal(SpatialRelation.CONTAINS, ctx.GetWorldBounds().RelateXRange(-90, -135));
            //point on edge at dateline using opposite +/- 180
            Assert.Equal(SpatialRelation.CONTAINS, ctx.MakeRectangle(170, 180, 0, 0).Relate(ctx.MakePoint(-180, 0)));

            //test 180 becomes -180 for non-zero width rectangle
            Assert.Equal(ctx.MakeRectangle(-180, -170, 0, 0), ctx.MakeRectangle(180, -170, 0, 0));
            Assert.Equal(ctx.MakeRectangle(170, 180, 0, 0), ctx.MakeRectangle(170, -180, 0, 0));

            double[] lons = new double[] { 0, 45, 160, 180, -45, -175, -180 }; //minX
            foreach (double lon in lons)
            {
                double[] lonWs = new double[] { 0, 20, 180, 200, 355, 360 }; //width
                foreach (double lonW in lonWs)
                {
                    if (lonW == 360 && lon != -180)
                    {
                        continue;
                    }
                    TestRectangle(lon, lonW, 0, 0);
                    TestRectangle(lon, lonW, -10, 10);
                    TestRectangle(lon, lonW, 80, 10);   //polar cap
                    TestRectangle(lon, lonW, -90, 180); //full lat range
                }
            }

            TestShapes2D.testCircleReset(ctx);

            //Test geo rectangle intersections
            testRectIntersect();
        }
        public void TestCustom()
        {
            SpatialContext sc = Call("geo", "false");

            Assert.True(!sc.IsGeo());
            Assert.Equal(new CartesianDistCalc(), sc.GetDistCalc());

            sc = Call("geo", "false",
                      "distCalculator", "cartesian^2",
                      "worldBounds", "-100 0 75 200");//West South East North
            Assert.Equal(new CartesianDistCalc(true), sc.GetDistCalc());
            Assert.Equal(new RectangleImpl(-100, 75, 0, 200, sc), sc.GetWorldBounds());

            sc = Call("geo", "true",
                      "distCalculator", "lawOfCosines");
            Assert.True(sc.IsGeo());
            var test = new GeodesicSphereDistCalc.LawOfCosines();

            Assert.Equal(test, sc.GetDistCalc());
        }
Exemplo n.º 7
0
        public void testNodeTraverse()
        {
            Node prevN = null;
            Node n     = trie.GetWorldNode();

            Assert.AreEqual(0, n.GetLevel());
            Assert.AreEqual(ctx.GetWorldBounds(), n.GetShape());
            while (n.GetLevel() < trie.GetMaxLevels())
            {
                prevN = n;
                var it = n.GetSubCells().GetEnumerator();
                it.MoveNext();
                n = it.Current;                 //TODO random which one?

                Assert.AreEqual(prevN.GetLevel() + 1, n.GetLevel());
                Rectangle prevNShape = (Rectangle)prevN.GetShape();
                Shape     s          = n.GetShape();
                Rectangle sbox       = s.GetBoundingBox();
                Assert.IsTrue(prevNShape.GetWidth() > sbox.GetWidth());
                Assert.IsTrue(prevNShape.GetHeight() > sbox.GetHeight());
            }
        }
 public QuadPrefixTree(SpatialContext ctx, int maxLevels)
     : base(ctx, maxLevels)
 {
     Init(ctx, ctx.GetWorldBounds(), maxLevels);
 }
 public QuadPrefixTree(SpatialContext ctx)
     : base(ctx, DEFAULT_MAX_LEVELS)
 {
     Init(ctx, ctx.GetWorldBounds(), DEFAULT_MAX_LEVELS);
 }
Exemplo n.º 10
0
        /// <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));
                }
            }
        }
Exemplo n.º 11
0
 public QuadPrefixTree(SpatialContext ctx, int maxLevels)
     : this(ctx, ctx.GetWorldBounds(), maxLevels)
 {
 }
Exemplo n.º 12
0
        public void TestGeoCircle(SpatialContext ctx)
        {
            base.ctx = ctx;

            Assert.Equal("Circle(Pt(x=10.0,y=20.0), d=30.0° 3335.85km)", 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("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.GetWorldBounds(), ctx.MakeCircle(0, 0, 180).GetBoundingBox());
            //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();
        }