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); }
public static Rectangle CalcBoxByDistFromPtDEG(double lat, double lon, double distance, SpatialContext ctx) { //See http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates Section 3.1, 3.2 and 3.3 double radius = ctx.GetUnits().EarthRadius(); double dist_deg = Dist2Degrees(distance, radius); if (dist_deg == 0) return ctx.MakeRect(lon, lon, lat, lat);//essentially a point if (dist_deg >= 180)//distance is >= opposite side of the globe return ctx.GetWorldBounds(); //--calc latitude bounds double latN_deg = lat + dist_deg; double latS_deg = lat - dist_deg; if (latN_deg >= 90 || latS_deg <= -90) {//touches either pole //we have special logic for longitude double lonW_deg = -180, lonE_deg = 180;//world wrap: 360 deg if (latN_deg <= 90 && latS_deg >= -90) {//doesn't pass either pole: 180 deg lonW_deg = lon - 90; lonE_deg = lon + 90; } if (latN_deg > 90) latN_deg = 90; if (latS_deg < -90) latS_deg = -90; return ctx.MakeRect(lonW_deg, lonE_deg, latS_deg, latN_deg); } else { //--calc longitude bounds double lon_delta_deg = CalcBoxByDistFromPt_deltaLonDEG(lat, lon, distance, radius); double lonW_deg = lon - lon_delta_deg; double lonE_deg = lon + lon_delta_deg; return ctx.MakeRect(lonW_deg, lonE_deg, latS_deg, latN_deg);//ctx will normalize longitude } }
public override Point PointOnBearing(Point @from, double dist, double bearingDEG, SpatialContext ctx) { //TODO avoid unnecessary double[] intermediate object if (dist == 0) return from; double[] latLon = DistanceUtils.PointOnBearingRAD( DistanceUtils.ToRadians(from.GetY()), DistanceUtils.ToRadians(from.GetX()), DistanceUtils.Dist2Radians(dist, ctx.GetUnits().EarthRadius()), DistanceUtils.ToRadians(bearingDEG), null); return ctx.MakePoint(DistanceUtils.ToDegrees(latLon[1]), DistanceUtils.ToDegrees(latLon[0])); }
public void TestGeoCircle(SpatialContext ctx) { base.ctx = ctx; //--Start with some static tests that once failed: //Bug: numeric edge at pole, fails to init ctx.MakeCircle(110, -12, ctx.GetDistCalc().DegreesToDistance(90 + 12)); //Bug: horizXAxis not in enclosing rectangle, assertion ctx.MakeCircle(-44, 16, DegToDist(106)); ctx.MakeCircle(-36, -76, DegToDist(14)); ctx.MakeCircle(107, 82, DegToDist(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 //} Assert.Equal(/*"nudge back circle", */ SpatialRelation.CONTAINS, ctx.MakeCircle(-150, -90, DegToDist(122)).Relate(ctx.MakeRect(0, -132, 32, 32), ctx)); Assert.Equal(/* "wrong estimate", */ SpatialRelation.DISJOINT, ctx.MakeCircle(-166, 59, 5226.2).Relate(ctx.MakeRect(36, 66, 23, 23), ctx)); Assert.Equal(/*"bad CONTAINS (dateline)",*/ SpatialRelation.INTERSECTS, ctx.MakeCircle(56, -50, 12231.5).Relate(ctx.MakeRect(108, 26, 39, 48), ctx)); Assert.Equal(/*"bad CONTAINS (backwrap2)",*/ SpatialRelation.INTERSECTS, ctx.MakeCircle(112, -3, DegToDist(91)).Relate(ctx.MakeRect(-163, 29, -38, 10), ctx)); Assert.Equal(/*"bad CONTAINS (r x-wrap)",*/ SpatialRelation.INTERSECTS, ctx.MakeCircle(-139, 47, DegToDist(80)).Relate(ctx.MakeRect(-180, 180, -3, 12), ctx)); Assert.Equal(/*"bad CONTAINS (pwrap)",*/ SpatialRelation.INTERSECTS, ctx.MakeCircle(-139, 47, DegToDist(80)).Relate(ctx.MakeRect(-180, 179, -3, 12), ctx)); Assert.Equal(/*"no-dist 1",*/ SpatialRelation.WITHIN, ctx.MakeCircle(135, 21, 0).Relate(ctx.MakeRect(-103, -154, -47, 52), ctx)); Assert.Equal(/*"bbox <= >= -90 bug",*/ SpatialRelation.CONTAINS, ctx.MakeCircle(-64, -84, DegToDist(124)).Relate(ctx.MakeRect(-96, 96, -10, -10), ctx)); //The horizontal axis line of a geo circle doesn't necessarily pass through c's ctr. Assert.Equal(/*"c's horiz axis doesn't pass through ctr",*/ SpatialRelation.INTERSECTS, ctx.MakeCircle(71, -44, DegToDist(40)).Relate(ctx.MakeRect(15, 27, -62, -34), ctx)); Assert.Equal(/*"pole boundary",*/ SpatialRelation.INTERSECTS, ctx.MakeCircle(-100, -12, DegToDist(102)).Relate(ctx.MakeRect(143, 175, 4, 32), ctx)); Assert.Equal(/*"full circle assert",*/ SpatialRelation.CONTAINS, ctx.MakeCircle(-64, 32, DegToDist(180)).Relate(ctx.MakeRect(47, 47, -14, 90), ctx)); //--Now proceed with systematic testing: double distToOpposeSide = ctx.GetUnits().EarthRadius() * Math.PI; Assert.Equal(ctx.GetWorldBounds(), ctx.MakeCircle(0, 0, distToOpposeSide).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, 500); TestCircle(x, y, DegToDist(90)); TestCircle(x, y, ctx.GetUnits().EarthRadius() * 6); } } TestCircleIntersect(); }