protected Rectangle makeNormRect(double minX, double maxX, double minY, double maxY) {
    if (ctx.isGeo()) {
      if (Math.abs(maxX - minX) >= 360) {
        minX = -180;
        maxX = 180;
      } else {
        minX = DistanceUtils.normLonDEG(minX);
        maxX = DistanceUtils.normLonDEG(maxX);
      }

    } else {
      if (maxX < minX) {
        double t = minX;
        minX = maxX;
        maxX = t;
      }
      minX = boundX(minX, ctx.getWorldBounds());
      maxX = boundX(maxX, ctx.getWorldBounds());
    }
    if (maxY < minY) {
      double t = minY;
      minY = maxY;
      maxY = t;
    }
    minY = boundY(minY, ctx.getWorldBounds());
    maxY = boundY(maxY, ctx.getWorldBounds());
    return ctx.makeRectangle(minX, maxX, minY, maxY);
  }
 /** Normalize x & y (put in lon-lat ranges) & ensure geohash round-trip for given precision. */
 private Point normPointXY(double x, double y) {
   // put x,y as degrees into double[] as radians
   double[] latLon = {Math.toRadians(y), Math.toRadians(x)};
   DistanceUtils.normLatRAD(latLon);
   DistanceUtils.normLatRAD(latLon);
   double x2 = Math.toDegrees(latLon[1]);
   double y2 = Math.toDegrees(latLon[0]);
   // overwrite latLon, units is now degrees
   return GeohashUtils.decode(GeohashUtils.encodeLatLon(y2, x2, PRECISION), ctx);
 }
 private Query query(GeoDistance geoDistance, SpatialStrategy spatialStrategy) {
   double kms = geoDistance.getValue(GeoDistanceUnit.KILOMETRES);
   double distance = DistanceUtils.dist2Degrees(kms, DistanceUtils.EARTH_MEAN_RADIUS_KM);
   Circle circle = spatialContext.makeCircle(longitude, latitude, distance);
   SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, circle);
   return spatialStrategy.makeQuery(args);
 }
 private double calcDist(Point p1, Point p2) {
   // TODO use ctx.calc?
   return DistanceUtils.distHaversineRAD(
           Math.toRadians(p1.getY()),
           Math.toRadians(p1.getX()),
           Math.toRadians(p2.getY()),
           Math.toRadians(p2.getX()))
       * ctx.getUnits().earthRadius();
 }
 @Override
 public String toString() {
   // Add distance in km, which may be easier to recognize.
   double distKm = DistanceUtils.degrees2Dist(radiusDEG, DistanceUtils.EARTH_MEAN_RADIUS_KM);
   // instead of String.format() so that we get consistent output no matter the locale
   String dStr =
       new Formatter(Locale.getDefault())
           .format("%.1f\u00B0 %.2fkm", radiusDEG, distKm)
           .toString();
   return "Circle(" + point + ", d=" + dStr + ')';
 }
 private void init() {
   if (radiusDEG > 90) {
     // --spans more than half the globe
     assert enclosingBox.getWidth() == 360;
     double backDistDEG = 180 - radiusDEG;
     if (backDistDEG > 0) {
       double backRadius = 180 - radiusDEG;
       double backX = DistanceUtils.normLonDEG(getCenter().getX() + 180);
       double backY = DistanceUtils.normLatDEG(getCenter().getY() + 180);
       // Shrink inverseCircle as small as possible to avoid accidental overlap.
       // Note that this is tricky business to come up with a value small enough
       // but not too small or else numerical conditioning issues become a problem.
       backRadius -=
           Math.max(
               Math.ulp(Math.abs(backY) + backRadius), Math.ulp(Math.abs(backX) + backRadius));
       if (inverseCircle != null) {
         inverseCircle.reset(backX, backY, backRadius);
       } else {
         inverseCircle = new GeoCircle(ctx.makePoint(backX, backY), backRadius, ctx);
       }
     } else {
       inverseCircle = null; // whole globe
     }
     horizAxisY = getCenter().getY(); // although probably not used
   } else {
     inverseCircle = null;
     double _horizAxisY =
         ctx.getDistCalc().calcBoxByDistFromPt_yHorizAxisDEG(getCenter(), radiusDEG, 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;
     }
     // assert enclosingBox.relate_yRange(horizAxis,horizAxis,ctx).intersects();
   }
 }
 protected double normY(double y) {
   return ctx.isGeo() ? DistanceUtils.normLatDEG(y) : y;
 }
 protected double normX(double x) {
   return ctx.isGeo() ? DistanceUtils.normLonDEG(x) : x;
 }