/** * Called after bounding box is intersected. * * @param bboxSect INTERSECTS or CONTAINS from enclosingBox's intersection * @return DISJOINT, CONTAINS, or INTERSECTS (not WITHIN) */ @Override protected SpatialRelation relateRectanglePhase2(Rectangle r, SpatialRelation bboxSect) { // Rectangle wraps around the world longitudinally creating a solid band; there are no corners // to test intersection if (r.getWidth() == 360) { return SpatialRelation.INTERSECTS; } if (inverseCircle != null) { return inverseCircle.relate(r).inverse(); } // if a pole is wrapped, we have a separate algorithm if (enclosingBox.getWidth() == 360) { return relateRectangleCircleWrapsPole(r, ctx); } // This is an optimization path for when there are no dateline or pole issues. if (!enclosingBox.getCrossesDateLine() && !r.getCrossesDateLine()) { return super.relateRectanglePhase2(r, bboxSect); } // do quick check to see if all corners are within this circle for CONTAINS int cornersIntersect = numCornersIntersect(r); if (cornersIntersect == 4) { // ensure r's x axis is within c's. If it doesn't, r sneaks around the globe to touch the // other side (intersect). SpatialRelation xIntersect = r.relateXRange(enclosingBox.getMinX(), enclosingBox.getMaxX()); if (xIntersect == SpatialRelation.WITHIN) return SpatialRelation.CONTAINS; return SpatialRelation.INTERSECTS; } // INTERSECT or DISJOINT ? if (cornersIntersect > 0) return SpatialRelation.INTERSECTS; // Now we check if one of the axis of the circle intersect with r. If so we have // intersection. /* x axis intersects */ if (r.relateYRange(getYAxis(), getYAxis()).intersects() // at y vertical && r.relateXRange(enclosingBox.getMinX(), enclosingBox.getMaxX()).intersects()) return SpatialRelation.INTERSECTS; /* y axis intersects */ if (r.relateXRange(getXAxis(), getXAxis()).intersects()) { // at x horizontal double yTop = getCenter().getY() + radiusDEG; assert yTop <= 90; double yBot = getCenter().getY() - radiusDEG; assert yBot >= -90; if (r.relateYRange(yBot, yTop).intersects()) // back bottom return SpatialRelation.INTERSECTS; } return SpatialRelation.DISJOINT; }
private SpatialRelation relateRectangleCircleWrapsPole(Rectangle r, SpatialContext ctx) { // This method handles the case where the circle wraps ONE pole, but not both. For both, // there is the inverseCircle case handled before now. The only exception is for the case where // the circle covers the entire globe, and we'll check that first. if (radiusDEG == 180) // whole globe return SpatialRelation.CONTAINS; // Check if r is within the pole wrap region: double yTop = getCenter().getY() + radiusDEG; if (yTop > 90) { double yTopOverlap = yTop - 90; assert yTopOverlap <= 90; if (r.getMinY() >= 90 - yTopOverlap) return SpatialRelation.CONTAINS; } else { double yBot = point.getY() - radiusDEG; if (yBot < -90) { double yBotOverlap = -90 - yBot; assert yBotOverlap <= 90; if (r.getMaxY() <= -90 + yBotOverlap) return SpatialRelation.CONTAINS; } else { // This point is probably not reachable ?? assert yTop == 90 || yBot == -90; // we simply touch a pole // continue } } // If there are no corners to check intersection because r wraps completely... if (r.getWidth() == 360) return SpatialRelation.INTERSECTS; // Check corners: int cornersIntersect = numCornersIntersect(r); // (It might be possible to reduce contains() calls within nCI() to exactly two, but this // intersection // code is complicated enough as it is.) double frontX = getCenter().getX(); if (cornersIntersect == 4) { // all double backX = frontX <= 0 ? frontX + 180 : frontX - 180; if (r.relateXRange(backX, backX).intersects()) return SpatialRelation.INTERSECTS; else return SpatialRelation.CONTAINS; } else if (cornersIntersect == 0) { // none if (r.relateXRange(frontX, frontX).intersects()) return SpatialRelation.INTERSECTS; else return SpatialRelation.DISJOINT; } else // partial return SpatialRelation.INTERSECTS; }