//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); }
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> /// 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 double GetArea(SpatialContext ctx) { if (ctx == null) { return GetWidth()*GetHeight(); } else { return ctx.GetDistCalc().Area(this); } }
public DistanceSimilarity(SpatialContext ctx, Point queryPoint) { this.queryPoint = queryPoint; this.distCalc = ctx.GetDistCalc(); this.nullValue = (ctx.IsGeo() ? 180 : double.MaxValue); }
public SpatialRelation Relate(Circle circle, SpatialContext ctx) { double crossDist = ctx.GetDistCalc().Distance(point, circle.GetCenter()); double aDist = distRadius, bDist = circle.GetRadius(); if (crossDist > aDist + bDist) return SpatialRelation.DISJOINT; if (crossDist < aDist && crossDist + bDist <= aDist) return SpatialRelation.CONTAINS; if (crossDist < bDist && crossDist + aDist <= bDist) return SpatialRelation.WITHIN; return SpatialRelation.INTERSECTS; }
public double GetArea(SpatialContext ctx) { if (ctx == null) { return Math.PI*distRadius*distRadius; } else { return ctx.GetDistCalc().Area(this); } }
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(); }