예제 #1
0
        public virtual void TestLineStringDateline()
        {
            //works because we use NTS (NtsGeometry); BufferedLineString doesn't yet do DL wrap.
            IShape s = ctx.ReadShapeFromWkt("LINESTRING(160 10, -170 15)");

            CustomAssert.EqualWithDelta(30, s.BoundingBox.Width, 0.0);
        }
예제 #2
0
        public void TestNtsContextFactory()
        {
            NtsSpatialContext ctx = (NtsSpatialContext)Call(
                "spatialContextFactory", typeof(NtsSpatialContextFactory).AssemblyQualifiedName,
                "geo", "true",
                "normWrapLongitude", "true",
                "precisionScale", "2.0",
                "wktShapeParserClass", typeof(CustomWktShapeParser).AssemblyQualifiedName,
                "datelineRule", "ccwRect",
                "validationRule", "repairConvexHull",
                "autoIndex", "true");

            Assert.True(ctx.IsNormWrapLongitude);
            CustomAssert.EqualWithDelta(2.0, ctx.GeometryFactory.PrecisionModel.Scale, 0.0);
            Assert.True(CustomWktShapeParser.once);//cheap way to test it was created
            Assert.Equal(DatelineRule.CcwRect,
                         ((NtsWktShapeParser)ctx.WktShapeParser).DatelineRule);
            Assert.Equal(ValidationRule.RepairConvexHull,
                         ((NtsWktShapeParser)ctx.WktShapeParser).ValidationRule);

            //ensure geo=false with worldbounds works -- fixes #72
            ctx = (NtsSpatialContext)Call(
                "spatialContextFactory", typeof(NtsSpatialContextFactory).AssemblyQualifiedName,
                "geo", "false",//set to false
                "worldBounds", "ENVELOPE(-500,500,300,-300)",
                "normWrapLongitude", "true",
                "precisionScale", "2.0",
                "wktShapeParserClass", typeof(CustomWktShapeParser).AssemblyQualifiedName,
                "datelineRule", "ccwRect",
                "validationRule", "repairConvexHull",
                "autoIndex", "true");
            CustomAssert.EqualWithDelta(300, ctx.WorldBounds.MaxY, 0.0);
        }
예제 #3
0
        public void TestNormLon()
        {
            var lons = new double[][]
            {
                new double[] { 1.23, 1.23 },
                //1.23 might become 1.2299999 after some math and we want to ensure that doesn't happen
                new double[] { -180, -180 },
                new double[] { 180, +180 },
                new double[] { 0, 0 },
                new double[] { -190, 170 },
                new double[] { 181, -179 },
                new double[] { -180 - 360, -180 },
                new double[] { -180 - 720, -180 },
                new double[] { 180 + 360, +180 },
                new double[] { 180 + 720, +180 }
            };

            foreach (var pair in lons)
            {
                CustomAssert.EqualWithDelta( /*"input "+pair[0],*/
                    pair[1], DistanceUtils.NormLonDEG(pair[0]), Double.Epsilon);
            }

            var random = new Random(RandomSeed.Seed());

            for (int i = -1000; i < 1000; i += random.Next(9) * 10)
            {
                double d = DistanceUtils.NormLonDEG(i);
                Assert.True(d >= -180 && d <= 180, i + " " + d);
            }
        }
예제 #4
0
        public void TestNormLat()
        {
            var lats = new double[][]
            {
                new double[] { 1.23, 1.23 },
                //1.23 might become 1.2299999 after some math and we want to ensure that doesn't happen
                new double[] { -90, -90 },
                new double[] { 90, 90 },
                new double[] { 0, 0 },
                new double[] { -100, -80 },
                new double[] { -90 - 180, 90 },
                new double[] { -90 - 360, -90 },
                new double[] { 90 + 180, -90 },
                new double[] { 90 + 360, 90 },
                new double[] { -12 + 180, 12 }
            };

            foreach (var pair in lats)
            {
                CustomAssert.EqualWithDelta( /* "input "+pair[0],*/
                    pair[1], DistanceUtils.NormLatDEG(pair[0]), Double.Epsilon);
            }
            var random = new Random(RandomSeed.Seed());

            for (int i = -1000; i < 1000; i += random.Next(9) * 10)
            {
                double d = DistanceUtils.NormLatDEG(i);
                Assert.True(/*i + " " + d,*/ d >= -90 && d <= 90);
            }
        }
예제 #5
0
        protected virtual void AssertEqualsRatio(string msg, double expected, double actual)
        {
            double delta      = Math.Abs(actual - expected);
            double @base      = Math.Min(actual, expected);
            double deltaRatio = @base == 0 ? delta : Math.Min(delta, delta / @base);

            CustomAssert.EqualWithDelta(/*msg,*/ 0, deltaRatio, EPS);
        }
예제 #6
0
        private static void AssertEqualsRatio(double expected, double actual, double EPS)
        {
            double delta      = Math.Abs(actual - expected);
            double baseValue  = Math.Min(actual, expected);
            double deltaRatio = baseValue == 0 ? delta : Math.Min(delta, delta / baseValue);

            CustomAssert.EqualWithDelta(0, deltaRatio, EPS);
        }
예제 #7
0
        private void AssertEqualsRatio(String msg, double expected, double actual)
        {
            double delta      = Math.Abs(actual - expected);
            double baseValue  = Math.Min(actual, expected);
            double deltaRatio = (baseValue == 0) ? delta : Math.Min(delta, delta / baseValue);

            CustomAssert.EqualWithDelta(/*msg,*/ 0, deltaRatio, EPS);
        }
예제 #8
0
        public virtual void TestDecodePreciseLongitudeLatitude()
        {
            string hash = GeohashUtils.EncodeLatLon(52.3738007, 4.8909347);

            IPoint point = GeohashUtils.Decode(hash, ctx);

            CustomAssert.EqualWithDelta(52.3738007, point.Y, 0.00001D);
            CustomAssert.EqualWithDelta(4.8909347, point.X, 0.00001D);
        }
예제 #9
0
        public void TestDecodeImpreciseLongitudeLatitude()
        {
            String hash = GeohashUtils.EncodeLatLon(84.6, 10.5);

            Point point = GeohashUtils.Decode(hash, ctx);

            CustomAssert.EqualWithDelta(84.6, point.GetY(), 0.00001D);
            CustomAssert.EqualWithDelta(10.5, point.GetX(), 0.00001D);
        }
예제 #10
0
        public virtual void TestDecodeImpreciseLongitudeLatitude()
        {
            string hash = GeohashUtils.EncodeLatLon(84.6, 10.5);

            IPoint point = GeohashUtils.Decode(hash, ctx);

            CustomAssert.EqualWithDelta(84.6, point.Y, 0.00001D);
            CustomAssert.EqualWithDelta(10.5, point.X, 0.00001D);
        }
예제 #11
0
 public virtual void TestHashLenToWidth()
 {
     //test odd & even len
     double[] boxOdd = GeohashUtils.LookupDegreesSizeForHashLen(3);
     CustomAssert.EqualWithDelta(1.40625, boxOdd[0], 0.0001);
     CustomAssert.EqualWithDelta(1.40625, boxOdd[1], 0.0001);
     double[] boxEven = GeohashUtils.LookupDegreesSizeForHashLen(4);
     CustomAssert.EqualWithDelta(0.1757, boxEven[0], 0.0001);
     CustomAssert.EqualWithDelta(0.3515, boxEven[1], 0.0001);
 }
예제 #12
0
        public virtual void TestWidthGreaterThan180()
        {
            //does NOT cross the dateline but is a wide shape >180
            NtsGeometry ntsGeo = (NtsGeometry)ctx.ReadShapeFromWkt("POLYGON((-161 49, 0 49, 20 49, 20 89.1, 0 89.1, -161 89.2, -161 49))");

            CustomAssert.EqualWithDelta(161 + 20, ntsGeo.BoundingBox.Width, 0.001);

            //shift it to cross the dateline and check that it's still good
            ntsGeo = ShiftPoly(ntsGeo, 180);
            CustomAssert.EqualWithDelta(161 + 20, ntsGeo.BoundingBox.Width, 0.001);
        }
예제 #13
0
        public void testSomeDistances()
        {
            //See to verify: from http://www.movable-type.co.uk/scripts/latlong.html
            Point ctr = pLL(0, 100);

            CustomAssert.EqualWithDelta(11100, dc().Distance(ctr, pLL(10, 0)) * DistanceUtils.DEG_TO_KM, 3);
            double deg = dc().Distance(ctr, pLL(10, -160));

            CustomAssert.EqualWithDelta(11100, deg * DistanceUtils.DEG_TO_KM, 3);

            CustomAssert.EqualWithDelta(314.40338, dc().Distance(pLL(1, 2), pLL(3, 4)) * DistanceUtils.DEG_TO_KM, EPS);
        }
예제 #14
0
        protected virtual void TestRectangle(double minX, double width, double minY, double height)
        {
            double maxX = minX + width;
            double maxY = minY + height;

            minX = NormX(minX);
            maxX = NormX(maxX);

            IRectangle r = ctx.MakeRectangle(minX, maxX, minY, maxY);

            //test equals & hashcode of duplicate
            IRectangle r2 = ctx.MakeRectangle(minX, maxX, minY, maxY);

            Assert.Equal(r, r2);
            Assert.Equal(r.GetHashCode(), r2.GetHashCode());

            string msg = r.ToString();

            Assert.Equal(/*msg,*/ width != 0 && height != 0, r.HasArea);
            Assert.Equal(/*msg,*/ width != 0 && height != 0, r.GetArea(ctx) > 0);
            if (ctx.IsGeo && r.Width == 360 && r.Height == 180)
            {
                //whole globe
                double earthRadius = DistanceUtils.ToDegrees(1);
                CustomAssert.EqualWithDelta(4 * Math.PI * earthRadius * earthRadius, r.GetArea(ctx), 1.0);//1km err
            }

            AssertEqualsRatio(msg, height, r.Height);
            AssertEqualsRatio(msg, width, r.Width);
            IPoint center = r.Center;

            msg += " ctr:" + center;
            //System.out.println(msg);
            AssertRelation(msg, SpatialRelation.CONTAINS, r, center);

            IDistanceCalculator dc = ctx.DistCalc;
            double dUR             = dc.Distance(center, r.MaxX, r.MaxY);
            double dLR             = dc.Distance(center, r.MaxX, r.MinY);
            double dUL             = dc.Distance(center, r.MinX, r.MaxY);
            double dLL             = dc.Distance(center, r.MinX, r.MinY);

            Assert.Equal(/*msg,*/ width != 0 || height != 0, dUR != 0);
            if (dUR != 0)
            {
                Assert.True(dUR > 0 && dLL > 0);
            }
            AssertEqualsRatio(msg, dUR, dUL);
            AssertEqualsRatio(msg, dLR, dLL);
            if (!ctx.IsGeo || center.Y == 0)
            {
                AssertEqualsRatio(msg, dUR, dLL);
            }
        }
예제 #15
0
        private void checkBBox(Point ctr, double distKm)
        {
            String msg  = "ctr: " + ctr + " distKm: " + distKm;
            double dist = distKm * DistanceUtils.KM_TO_DEG;

            Rectangle r            = dc().CalcBoxByDistFromPt(ctr, dist, ctx, null);
            double    horizAxisLat = dc().CalcBoxByDistFromPt_yHorizAxisDEG(ctr, dist, ctx);

            if (!Double.IsNaN(horizAxisLat))
            {
                Assert.True(r.RelateYRange(horizAxisLat, horizAxisLat).Intersects());
            }

            //horizontal
            if (r.GetWidth() >= 180)
            {
                double deg        = dc().Distance(ctr, r.GetMinX(), r.GetMaxY() == 90 ? 90 : -90);
                double calcDistKm = deg * DistanceUtils.DEG_TO_KM;
                Assert.True(/*msg,*/ calcDistKm <= distKm + EPS);
                //horizAxisLat is meaningless in this context
            }
            else
            {
                Point  tPt        = FindClosestPointOnVertToPoint(r.GetMinX(), r.GetMinY(), r.GetMaxY(), ctr);
                double calcDistKm = dc().Distance(ctr, tPt) * DistanceUtils.DEG_TO_KM;
                CustomAssert.EqualWithDelta(/*msg,*/ distKm, calcDistKm, EPS);
                CustomAssert.EqualWithDelta(/*msg,*/ tPt.GetY(), horizAxisLat, EPS);
            }

            //vertical
            double topDistKm = dc().Distance(ctr, ctr.GetX(), r.GetMaxY()) * DistanceUtils.DEG_TO_KM;

            if (r.GetMaxY() == 90)
            {
                Assert.True(/*msg,*/ topDistKm <= distKm + EPS);
            }
            else
            {
                CustomAssert.EqualWithDelta(msg, distKm, topDistKm, EPS);
            }
            double botDistKm = dc().Distance(ctr, ctr.GetX(), r.GetMinY()) * DistanceUtils.DEG_TO_KM;

            if (r.GetMinY() == -90)
            {
                Assert.True(/*msg,*/ botDistKm <= distKm + EPS);
            }
            else
            {
                CustomAssert.EqualWithDelta(/*msg,*/ distKm, botDistKm, EPS);
            }
        }
예제 #16
0
        public void testArea()
        {
            //simple bbox
            Rectangle r      = RandomRectangle(20);
            var       ctxJts = (NtsSpatialContext)ctx;
            var       rPoly  = new NtsGeometry(ctxJts.GetGeometryFrom(r), ctxJts, false);

            CustomAssert.EqualWithDelta(r.GetArea(null), rPoly.GetArea(null), 0.0);
            CustomAssert.EqualWithDelta(r.GetArea(ctx), rPoly.GetArea(ctx), 0.000001);             //same since fills 100%

            CustomAssert.EqualWithDelta(1300, POLY_SHAPE.GetArea(null), 0.0);

            //fills 27%
            CustomAssert.EqualWithDelta(0.27, POLY_SHAPE.GetArea(ctx) / POLY_SHAPE.GetBoundingBox().GetArea(ctx), 0.009);
            Assert.True(POLY_SHAPE.GetBoundingBox().GetArea(ctx) > POLY_SHAPE.GetArea(ctx));
        }
예제 #17
0
        public virtual void TestArea()
        {
            //simple bbox
            IRectangle        r      = RandomRectangle(20);
            NtsSpatialContext ctxNts = (NtsSpatialContext)ctx;
            NtsGeometry       rPoly  = ctxNts.MakeShape(ctxNts.GetGeometryFrom(r), false, false);

            CustomAssert.EqualWithDelta(r.GetArea(null), rPoly.GetArea(null), 0.0);
            CustomAssert.EqualWithDelta(r.GetArea(ctx), rPoly.GetArea(ctx), 0.000001);//same since fills 100%

            CustomAssert.EqualWithDelta(1300, POLY_SHAPE.GetArea(null), 0.0);

            //fills 27%
            CustomAssert.EqualWithDelta(0.27, POLY_SHAPE.GetArea(ctx) / POLY_SHAPE.BoundingBox.GetArea(ctx), 0.009);
            Assert.True(POLY_SHAPE.BoundingBox.GetArea(ctx) > POLY_SHAPE.GetArea(ctx));
        }
예제 #18
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);
        }
예제 #19
0
        private void assertDistanceConversion(double dist)
        {
            double radius = DistanceUtils.EARTH_MEAN_RADIUS_KM;
            //test back & forth conversion for both
            double distRAD = DistanceUtils.Dist2Radians(dist, radius);

            CustomAssert.EqualWithDelta(dist, DistanceUtils.Radians2Dist(distRAD, radius), EPS);
            double distDEG = DistanceUtils.Dist2Degrees(dist, radius);

            CustomAssert.EqualWithDelta(dist, DistanceUtils.Degrees2Dist(distDEG, radius), EPS);
            //test across rad & deg
            CustomAssert.EqualWithDelta(distDEG, DistanceUtils.ToDegrees(distRAD), EPS);
            //test point on bearing
            CustomAssert.EqualWithDelta(
                DistanceUtils.PointOnBearingRAD(0, 0, DistanceUtils.Dist2Radians(dist, radius),
                                                DistanceUtils.DEG_90_AS_RADS, ctx, new PointImpl(0, 0, ctx)).GetX(),
                distRAD, 10e-5);
        }
예제 #20
0
        public void TestDecodeEncode()
        {
            String geoHash = "u173zq37x014";

            Assert.Equal(geoHash, GeohashUtils.EncodeLatLon(52.3738007, 4.8909347));
            Point point = GeohashUtils.Decode(geoHash, ctx);

            CustomAssert.EqualWithDelta(52.37380061d, point.GetY(), 0.000001d);
            CustomAssert.EqualWithDelta(4.8909343d, point.GetX(), 0.000001d);

            Assert.Equal(geoHash, GeohashUtils.EncodeLatLon(point.GetY(), point.GetX()));

            geoHash = "u173";
            point   = GeohashUtils.Decode("u173", ctx);
            geoHash = GeohashUtils.EncodeLatLon(point.GetY(), point.GetX());
            Point point2 = GeohashUtils.Decode(geoHash, ctx);

            CustomAssert.EqualWithDelta(point.GetY(), point2.GetY(), 0.000001d);
            CustomAssert.EqualWithDelta(point.GetX(), point2.GetX(), 0.000001d);
        }
예제 #21
0
        public virtual void TestDecodeEncode()
        {
            string geoHash = "u173zq37x014";

            Assert.Equal(geoHash, GeohashUtils.EncodeLatLon(52.3738007, 4.8909347));
            IPoint point = GeohashUtils.Decode(geoHash, ctx);

            CustomAssert.EqualWithDelta(52.37380061d, point.Y, 0.000001d);
            CustomAssert.EqualWithDelta(4.8909343d, point.X, 0.000001d);

            Assert.Equal(geoHash, GeohashUtils.EncodeLatLon(point.Y, point.X));

            geoHash = "u173";
            point   = GeohashUtils.Decode("u173", ctx);
            geoHash = GeohashUtils.EncodeLatLon(point.Y, point.X);
            IPoint point2 = GeohashUtils.Decode(geoHash, ctx);

            CustomAssert.EqualWithDelta(point.Y, point2.Y, 0.000001d);
            CustomAssert.EqualWithDelta(point.X, point2.X, 0.000001d);
        }
예제 #22
0
        public virtual void TestCalcBoxByDistFromPt()
        {
            //first test regression
            {
                double d    = 6894.1 * DistanceUtils.KM_TO_DEG;
                IPoint pCtr = PLL(-20, 84);
                IPoint pTgt = PLL(-42, 15);
                Assert.True(Dc().Distance(pCtr, pTgt) < d);
                //since the pairwise distance is less than d, a bounding box from ctr with d should contain pTgt.
                IRectangle r = Dc().CalcBoxByDistFromPt(pCtr, d, ctx, null);
                Assert.Equal(SpatialRelation.CONTAINS, r.Relate(pTgt));
                CheckBBox(pCtr, d);
            }

            CustomAssert.EqualWithDelta(/*"0 dist, horiz line",*/
                -45, Dc().CalcBoxByDistFromPt_yHorizAxisDEG(ctx.MakePoint(-180, -45), 0, ctx), 0);

            double MAXDIST = (double)180 * DistanceUtils.DEG_TO_KM;

            CheckBBox(ctx.MakePoint(0, 0), MAXDIST);
            CheckBBox(ctx.MakePoint(0, 0), MAXDIST * 0.999999);
            CheckBBox(ctx.MakePoint(0, 0), 0);
            CheckBBox(ctx.MakePoint(0, 0), 0.000001);
            CheckBBox(ctx.MakePoint(0, 90), 0.000001);
            CheckBBox(ctx.MakePoint(-32.7, -5.42), 9829);
            CheckBBox(ctx.MakePoint(0, 90 - 20), (double)20 * DistanceUtils.DEG_TO_KM);
            {
                double d = 0.010;//10m
                CheckBBox(ctx.MakePoint(0, 90 - (d + 0.001) * DistanceUtils.KM_TO_DEG), d);
            }

            for (int T = 0; T < 100; T++)
            {
                double lat  = -90 + random.NextDouble() * 180;
                double lon  = -180 + random.NextDouble() * 360;
                IPoint ctr  = ctx.MakePoint(lon, lat);
                double dist = MAXDIST * random.NextDouble();
                CheckBBox(ctr, dist);
            }
        }
예제 #23
0
        public virtual 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.WorldBounds.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();

            //Test buffer
            AssertEquals(ctx.MakeRectangle(-10, 10, -10, 10), ctx.MakeRectangle(0, 0, 0, 0).GetBuffered(10, ctx));
            for (int i = 0; i < AtLeast(100); i++)
            {
                IRectangle r   = RandomRectangle(1);
                int        buf = random.Next(0, 90 + 1);
                IRectangle br  = (IRectangle)r.GetBuffered(buf, ctx);
                AssertRelation(null, SpatialRelation.CONTAINS, br, r);
                if (r.Width + 2 * buf >= 360)
                {
                    CustomAssert.EqualWithDelta(360, br.Width, 0.0);
                }
                else
                {
                    Assert.True(br.Width - r.Width >= 2 * buf);
                }
                //TODO test more thoroughly; we don't check that we over-buf
            }
            Assert.True(ctx.MakeRectangle(0, 10, 0, 89).GetBuffered(0.5, ctx).BoundingBox.Width
                        > 11);
        }