public MakeRectangle ( System.Point lowerLeft, System.Point upperRight ) : Rectangle | ||
lowerLeft | System.Point | |
upperRight | System.Point | |
리턴 | Rectangle |
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> /// WARNING: geoms is copied by reference. /// </summary> /// <param name="geoms"></param> /// <param name="ctx"></param> public MultiShape(IEnumerable<Shape> geoms, SpatialContext ctx) { if (!geoms.Any()) throw new ArgumentException("must be given at least 1 shape", "geoms"); this.geoms = geoms; //compute and cache bbox double minX = Double.PositiveInfinity; double minY = Double.PositiveInfinity; double maxX = Double.NegativeInfinity; double maxY = Double.NegativeInfinity; foreach (var geom in geoms) { Rectangle r = geom.GetBoundingBox(); minX = Math.Min(minX, r.GetMinX()); minY = Math.Min(minY, r.GetMinY()); maxX = Math.Max(maxX, r.GetMaxX()); maxY = Math.Max(maxY, r.GetMaxY()); } this.bbox = ctx.MakeRectangle(minX, maxX, minY, maxY); }
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(); }
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 static Rectangle CalcBoxByDistFromPtDEG(double lat, double lon, double distDEG, SpatialContext ctx, Rectangle reuse) { //See http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates Section 3.1, 3.2 and 3.3 double minX; double maxX; double minY; double maxY; if (distDEG == 0) { minX = lon; maxX = lon; minY = lat; maxY = lat; } else if (distDEG >= 180) { //distance is >= opposite side of the globe minX = -180; maxX = 180; minY = -90; maxY = 90; } else { //--calc latitude bounds maxY = lat + distDEG; minY = lat - distDEG; if (maxY >= 90 || minY <= -90) { //touches either pole //we have special logic for longitude minX = -180; maxX = 180; //world wrap: 360 deg if (maxY <= 90 && minY >= -90) { //doesn't pass either pole: 180 deg minX = NormLonDEG(lon - 90); maxX = NormLonDEG(lon + 90); } if (maxY > 90) maxY = 90; if (minY < -90) minY = -90; } else { //--calc longitude bounds double lon_delta_deg = CalcBoxByDistFromPt_deltaLonDEG(lat, lon, distDEG); minX = NormLonDEG(lon - lon_delta_deg); maxX = NormLonDEG(lon + lon_delta_deg); } } if (reuse == null) { return ctx.MakeRectangle(minX, maxX, minY, maxY); } else { reuse.Reset(minX, maxX, minY, maxY); return reuse; } }
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 void TestSimpleRectangle(SpatialContext ctx) { base.ctx = ctx; double v = 2001 * (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)); Assert.Throws<InvalidShapeException>(() => ctx.MakeRectangle(10, -10, 0, 0)); double[] minXs = new double[] { -1000, -360, -180, -20, 0, 20, 180, 1000 }; foreach (double minX in minXs) { double[] widths = new double[] { 0, 10, 180, 360, 400 }; foreach (double width in widths) { TestRectangle(minX, width, 0, 0); TestRectangle(minX, width, -10, 10); TestRectangle(minX, width, 5, 10); } } Rectangle r = ctx.MakeRectangle(0, 0, 0, 0); r.Reset(1, 2, 3, 4); Assert.Equal(ctx.MakeRectangle(1, 2, 3, 4), r); testRectIntersect(); }
/** Returns min-max lat, min-max lon. */ public static Rectangle DecodeBoundary(String geohash, SpatialContext ctx) { double minY = -90, maxY = 90, minX = -180, maxX = 180; bool isEven = true; for (int i = 0; i < geohash.Length; i++) { char c = geohash[i]; if (c >= 'A' && c <= 'Z') c = Convert.ToChar(c - Convert.ToChar('A' - 'a')); int cd = BASE_32_IDX[c - BASE_32[0]]; //TODO check successful? foreach (var mask in BITS) { if (isEven) { if ((cd & mask) != 0) { minX = (minX + maxX) / 2D; } else { maxX = (minX + maxX) / 2D; } } else { if ((cd & mask) != 0) { minY = (minY + maxY) / 2D; } else { maxY = (minY + maxY) / 2D; } } isEven = !isEven; } } return ctx.MakeRectangle(minX, maxX, minY, maxY); }