Return-Path: X-Original-To: apmail-lucene-commits-archive@www.apache.org Delivered-To: apmail-lucene-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A046418C23 for ; Tue, 22 Mar 2016 15:53:04 +0000 (UTC) Received: (qmail 48410 invoked by uid 500); 22 Mar 2016 15:53:04 -0000 Mailing-List: contact commits-help@lucene.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@lucene.apache.org Delivered-To: mailing list commits@lucene.apache.org Received: (qmail 48393 invoked by uid 99); 22 Mar 2016 15:53:04 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 22 Mar 2016 15:53:04 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 210BEDFC75; Tue, 22 Mar 2016 15:53:04 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: mikemccand@apache.org To: commits@lucene.apache.org Date: Tue, 22 Mar 2016 15:53:05 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [2/3] lucene-solr:branch_6x: LUCENE-7128: clean up new geo APIs to consistently take lat before lon, make methods private when possible, use lat/lon instead of y/x naming, remove unused code http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c5da271b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoProjectionUtils.java ---------------------------------------------------------------------- diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoProjectionUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoProjectionUtils.java index 12d1350..61aa09f 100644 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoProjectionUtils.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoProjectionUtils.java @@ -69,83 +69,14 @@ public class GeoProjectionUtils { } /** - * Converts from geocentric earth-centered earth-fixed to geodesic lat/lon/alt - * @param x Cartesian x coordinate - * @param y Cartesian y coordinate - * @param z Cartesian z coordinate - * @param lla 0: longitude 1: latitude: 2: altitude - * @return double array as 0: longitude 1: latitude 2: altitude - */ - public static final double[] ecfToLLA(final double x, final double y, final double z, double[] lla) { - boolean atPole = false; - final double ad_c = 1.0026000D; - final double cos67P5 = 0.38268343236508977D; - - if (lla == null) { - lla = new double[3]; - } - - if (x != 0.0) { - lla[0] = StrictMath.atan2(y,x); - } else { - if (y > 0) { - lla[0] = PIO2; - } else if (y < 0) { - lla[0] = -PIO2; - } else { - atPole = true; - lla[0] = 0.0D; - if (z > 0.0) { - lla[1] = PIO2; - } else if (z < 0.0) { - lla[1] = -PIO2; - } else { - lla[1] = PIO2; - lla[2] = -SEMIMINOR_AXIS; - return lla; - } - } - } - - final double w2 = x*x + y*y; - final double w = StrictMath.sqrt(w2); - final double t0 = z * ad_c; - final double s0 = StrictMath.sqrt(t0 * t0 + w2); - final double sinB0 = t0 / s0; - final double cosB0 = w / s0; - final double sin3B0 = sinB0 * sinB0 * sinB0; - final double t1 = z + SEMIMINOR_AXIS * EP2 * sin3B0; - final double sum = w - SEMIMAJOR_AXIS * E2 * cosB0 * cosB0 * cosB0; - final double s1 = StrictMath.sqrt(t1 * t1 + sum * sum); - final double sinP1 = t1 / s1; - final double cosP1 = sum / s1; - final double rn = SEMIMAJOR_AXIS / StrictMath.sqrt(1.0D - E2 * sinP1 * sinP1); - - if (cosP1 >= cos67P5) { - lla[2] = w / cosP1 - rn; - } else if (cosP1 <= -cos67P5) { - lla[2] = w / -cosP1 - rn; - } else { - lla[2] = z / sinP1 + rn * (E2 - 1.0); - } - if (!atPole) { - lla[1] = StrictMath.atan(sinP1/cosP1); - } - lla[0] = TO_DEGREES * lla[0]; - lla[1] = TO_DEGREES * lla[1]; - - return lla; - } - - /** - * Converts from geodesic lon lat alt to geocentric earth-centered earth-fixed - * @param lon geodesic longitude + * Converts from geodesic lat lon alt to geocentric earth-centered earth-fixed * @param lat geodesic latitude + * @param lon geodesic longitude * @param alt geodesic altitude * @param ecf reusable earth-centered earth-fixed result * @return either a new ecef array or the reusable ecf parameter */ - public static final double[] llaToECF(double lon, double lat, double alt, double[] ecf) { + public static final double[] llaToECF(double lat, double lon, double alt, double[] ecf) { lon = TO_RADIANS * lon; lat = TO_RADIANS * lat; @@ -177,261 +108,23 @@ public class GeoProjectionUtils { } /** - * Converts from lat lon alt (in degrees) to East North Up right-hand coordinate system - * @param lon longitude in degrees - * @param lat latitude in degrees - * @param alt altitude in meters - * @param centerLon reference point longitude in degrees - * @param centerLat reference point latitude in degrees - * @param centerAlt reference point altitude in meters - * @param enu result east, north, up coordinate - * @return east, north, up coordinate - */ - public static double[] llaToENU(final double lon, final double lat, final double alt, double centerLon, - double centerLat, final double centerAlt, double[] enu) { - if (enu == null) { - enu = new double[3]; - } - - // convert point to ecf coordinates - final double[] ecf = llaToECF(lon, lat, alt, null); - - // convert from ecf to enu - return ecfToENU(ecf[0], ecf[1], ecf[2], centerLon, centerLat, centerAlt, enu); - } - - /** - * Converts from East North Up right-hand rule to lat lon alt in degrees - * @param x easting (in meters) - * @param y northing (in meters) - * @param z up (in meters) - * @param centerLon reference point longitude (in degrees) - * @param centerLat reference point latitude (in degrees) - * @param centerAlt reference point altitude (in meters) - * @param lla resulting lat, lon, alt point (in degrees) - * @return lat, lon, alt point (in degrees) - */ - public static double[] enuToLLA(final double x, final double y, final double z, final double centerLon, - final double centerLat, final double centerAlt, double[] lla) { - // convert enuToECF - if (lla == null) { - lla = new double[3]; - } - - // convert enuToECF, storing intermediate result in lla - lla = enuToECF(x, y, z, centerLon, centerLat, centerAlt, lla); - - // convert ecf to LLA - return ecfToLLA(lla[0], lla[1], lla[2], lla); - } - - /** - * Convert from Earth-Centered-Fixed to Easting, Northing, Up Right Hand System - * @param x ECF X coordinate (in meters) - * @param y ECF Y coordinate (in meters) - * @param z ECF Z coordinate (in meters) - * @param centerLon ENU origin longitude (in degrees) - * @param centerLat ENU origin latitude (in degrees) - * @param centerAlt ENU altitude (in meters) - * @param enu reusable enu result - * @return Easting, Northing, Up coordinate - */ - public static double[] ecfToENU(double x, double y, double z, final double centerLon, - final double centerLat, final double centerAlt, double[] enu) { - if (enu == null) { - enu = new double[3]; - } - - // create rotation matrix and rotate to enu orientation - final double[][] phi = createPhiTransform(centerLon, centerLat, null); - - // convert origin to ENU - final double[] originECF = llaToECF(centerLon, centerLat, centerAlt, null); - final double[] originENU = new double[3]; - originENU[0] = ((phi[0][0] * originECF[0]) + (phi[0][1] * originECF[1]) + (phi[0][2] * originECF[2])); - originENU[1] = ((phi[1][0] * originECF[0]) + (phi[1][1] * originECF[1]) + (phi[1][2] * originECF[2])); - originENU[2] = ((phi[2][0] * originECF[0]) + (phi[2][1] * originECF[1]) + (phi[2][2] * originECF[2])); - - // rotate then translate - enu[0] = ((phi[0][0] * x) + (phi[0][1] * y) + (phi[0][2] * z)) - originENU[0]; - enu[1] = ((phi[1][0] * x) + (phi[1][1] * y) + (phi[1][2] * z)) - originENU[1]; - enu[2] = ((phi[2][0] * x) + (phi[2][1] * y) + (phi[2][2] * z)) - originENU[2]; - - return enu; - } - - /** - * Convert from Easting, Northing, Up Right-Handed system to Earth Centered Fixed system - * @param x ENU x coordinate (in meters) - * @param y ENU y coordinate (in meters) - * @param z ENU z coordinate (in meters) - * @param centerLon ENU origin longitude (in degrees) - * @param centerLat ENU origin latitude (in degrees) - * @param centerAlt ENU origin altitude (in meters) - * @param ecf reusable ecf result - * @return ecf result coordinate - */ - public static double[] enuToECF(final double x, final double y, final double z, double centerLon, - double centerLat, final double centerAlt, double[] ecf) { - if (ecf == null) { - ecf = new double[3]; - } - - double[][] phi = createTransposedPhiTransform(centerLon, centerLat, null); - double[] ecfOrigin = llaToECF(centerLon, centerLat, centerAlt, null); - - // rotate and translate - ecf[0] = (phi[0][0]*x + phi[0][1]*y + phi[0][2]*z) + ecfOrigin[0]; - ecf[1] = (phi[1][0]*x + phi[1][1]*y + phi[1][2]*z) + ecfOrigin[1]; - ecf[2] = (phi[2][0]*x + phi[2][1]*y + phi[2][2]*z) + ecfOrigin[2]; - - return ecf; - } - - /** - * Create the rotation matrix for converting Earth Centered Fixed to Easting Northing Up - * @param originLon ENU origin longitude (in degrees) - * @param originLat ENU origin latitude (in degrees) - * @param phiMatrix reusable phi matrix result - * @return phi rotation matrix - */ - private static double[][] createPhiTransform(double originLon, double originLat, double[][] phiMatrix) { - - if (phiMatrix == null) { - phiMatrix = new double[3][3]; - } - - originLon = TO_RADIANS * originLon; - originLat = TO_RADIANS * originLat; - - final double sLon = sloppySin(originLon); - final double cLon = cos(originLon); - final double sLat = sloppySin(originLat); - final double cLat = cos(originLat); - - phiMatrix[0][0] = -sLon; - phiMatrix[0][1] = cLon; - phiMatrix[0][2] = 0.0D; - phiMatrix[1][0] = -sLat * cLon; - phiMatrix[1][1] = -sLat * sLon; - phiMatrix[1][2] = cLat; - phiMatrix[2][0] = cLat * cLon; - phiMatrix[2][1] = cLat * sLon; - phiMatrix[2][2] = sLat; - - return phiMatrix; - } - - /** - * Create the transposed rotation matrix for converting Easting Northing Up coordinates to Earth Centered Fixed - * @param originLon ENU origin longitude (in degrees) - * @param originLat ENU origin latitude (in degrees) - * @param phiMatrix reusable phi rotation matrix result - * @return transposed phi rotation matrix - */ - private static double[][] createTransposedPhiTransform(double originLon, double originLat, double[][] phiMatrix) { - - if (phiMatrix == null) { - phiMatrix = new double[3][3]; - } - - originLon = TO_RADIANS * originLon; - originLat = TO_RADIANS * originLat; - - final double sLat = sloppySin(originLat); - final double cLat = cos(originLat); - final double sLon = sloppySin(originLon); - final double cLon = cos(originLon); - - phiMatrix[0][0] = -sLon; - phiMatrix[1][0] = cLon; - phiMatrix[2][0] = 0.0D; - phiMatrix[0][1] = -sLat * cLon; - phiMatrix[1][1] = -sLat * sLon; - phiMatrix[2][1] = cLat; - phiMatrix[0][2] = cLat * cLon; - phiMatrix[1][2] = cLat * sLon; - phiMatrix[2][2] = sLat; - - return phiMatrix; - } - - /** - * Finds a point along a bearing from a given lon,lat geolocation using vincenty's distance formula + * Finds a point along a bearing from a given lat,lon geolocation using great circle arc * - * @param lon origin longitude in degrees * @param lat origin latitude in degrees - * @param bearing azimuthal bearing in degrees - * @param dist distance in meters - * @param pt resulting point - * @return the point along a bearing at a given distance in meters - */ - public static final double[] pointFromLonLatBearingVincenty(double lon, double lat, double bearing, double dist, double[] pt) { - - if (pt == null) { - pt = new double[2]; - } - - final double alpha1 = TO_RADIANS * bearing; - final double cosA1 = cos(alpha1); - final double sinA1 = sloppySin(alpha1); - final double tanU1 = (1-FLATTENING) * sloppyTan(TO_RADIANS * lat); - final double cosU1 = 1 / StrictMath.sqrt((1+tanU1*tanU1)); - final double sinU1 = tanU1*cosU1; - final double sig1 = StrictMath.atan2(tanU1, cosA1); - final double sinAlpha = cosU1 * sinA1; - final double cosSqAlpha = 1 - sinAlpha*sinAlpha; - final double uSq = cosSqAlpha * EP2; - final double A = 1 + uSq/16384D*(4096D + uSq * (-768D + uSq * (320D - 175D*uSq))); - final double B = uSq/1024D * (256D + uSq * (-128D + uSq * (74D - 47D * uSq))); - - double sigma = dist / (SEMIMINOR_AXIS*A); - double sigmaP; - double sinSigma, cosSigma, cos2SigmaM, deltaSigma; - - do { - cos2SigmaM = cos(2*sig1 + sigma); - sinSigma = sloppySin(sigma); - cosSigma = cos(sigma); - - deltaSigma = B * sinSigma * (cos2SigmaM + (B/4D) * (cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- - (B/6) * cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); - sigmaP = sigma; - sigma = dist / (SEMIMINOR_AXIS*A) + deltaSigma; - } while (StrictMath.abs(sigma-sigmaP) > 1E-12); - - final double tmp = sinU1*sinSigma - cosU1*cosSigma*cosA1; - final double lat2 = StrictMath.atan2(sinU1*cosSigma + cosU1*sinSigma*cosA1, - (1-FLATTENING) * StrictMath.sqrt(sinAlpha*sinAlpha + tmp*tmp)); - final double lambda = StrictMath.atan2(sinSigma*sinA1, cosU1*cosSigma - sinU1*sinSigma*cosA1); - final double c = FLATTENING/16 * cosSqAlpha * (4 + FLATTENING * (4 - 3 * cosSqAlpha)); - - final double lam = lambda - (1-c) * FLATTENING * sinAlpha * - (sigma + c * sinSigma * (cos2SigmaM + c * cosSigma * (-1 + 2* cos2SigmaM*cos2SigmaM))); - pt[0] = normalizeLon(lon + TO_DEGREES * lam); - pt[1] = normalizeLat(TO_DEGREES * lat2); - - return pt; - } - - /** - * Finds a point along a bearing from a given lon,lat geolocation using great circle arc - * * @param lon origin longitude in degrees - * @param lat origin latitude in degrees * @param bearing azimuthal bearing in degrees * @param dist distance in meters * @param pt resulting point * @return the point along a bearing at a given distance in meters */ - public static final double[] pointFromLonLatBearingGreatCircle(double lon, double lat, double bearing, double dist, double[] pt) { + public static final double[] pointFromLonLatBearingGreatCircle(double lat, double lon, double bearing, double dist, double[] pt) { if (pt == null) { pt = new double[2]; } - lon *= TO_RADIANS; lat *= TO_RADIANS; + lon *= TO_RADIANS; bearing *= TO_RADIANS; final double cLat = cos(lat); @@ -447,14 +140,14 @@ public class GeoProjectionUtils { } /** - * Finds the bearing (in degrees) between 2 geo points (lon, lat) using great circle arc - * @param lon1 first point longitude in degrees + * Finds the bearing (in degrees) between 2 geo points (lat, lon) using great circle arc * @param lat1 first point latitude in degrees - * @param lon2 second point longitude in degrees + * @param lon1 first point longitude in degrees * @param lat2 second point latitude in degrees + * @param lon2 second point longitude in degrees * @return the bearing (in degrees) between the two provided points */ - public static double bearingGreatCircle(double lon1, double lat1, double lon2, double lat2) { + public static double bearingGreatCircle(double lat1, double lon1, double lat2, double lon2) { double dLon = (lon2 - lon1) * TO_RADIANS; lat2 *= TO_RADIANS; lat1 *= TO_RADIANS; http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c5da271b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRect.java ---------------------------------------------------------------------- diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRect.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRect.java index e147351..8d947b4 100644 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRect.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRect.java @@ -18,19 +18,19 @@ package org.apache.lucene.spatial.util; /** Represents a lat/lon rectangle. */ public class GeoRect { - /** minimum longitude value (in degrees) */ - public final double minLon; - /** minimum latitude value (in degrees) */ - public final double maxLon; /** maximum longitude value (in degrees) */ public final double minLat; + /** minimum longitude value (in degrees) */ + public final double minLon; /** maximum latitude value (in degrees) */ public final double maxLat; + /** minimum latitude value (in degrees) */ + public final double maxLon; /** * Constructs a bounding box by first validating the provided latitude and longitude coordinates */ - public GeoRect(double minLon, double maxLon, double minLat, double maxLat) { + public GeoRect(double minLat, double maxLat, double minLon, double maxLon) { if (GeoUtils.isValidLon(minLon) == false) { throw new IllegalArgumentException("invalid minLon " + minLon); } http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c5da271b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java ---------------------------------------------------------------------- diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java index e40b91a..4a31202 100644 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java @@ -28,13 +28,14 @@ public class GeoRelationUtils { } /** - * Determine if a bbox (defined by minLon, minLat, maxLon, maxLat) contains the provided point (defined by lon, lat) + * Determine if a bbox (defined by minLat, maxLat, minLon, maxLon) contains the provided point (defined by lat, lon) * NOTE: this is a basic method that does not handle dateline or pole crossing. Unwrapping must be done before * calling this method. */ - public static boolean pointInRectPrecise(final double lon, final double lat, final double minLon, - final double minLat, final double maxLon, final double maxLat) { - return lon >= minLon && lon <= maxLon && lat >= minLat && lat <= maxLat; + public static boolean pointInRectPrecise(final double lat, final double lon, + final double minLat, final double maxLat, + final double minLon, final double maxLon) { + return lat >= minLat && lat <= maxLat && lon >= minLon && lon <= maxLon; } /** @@ -46,17 +47,17 @@ public class GeoRelationUtils { * * NOTE: Requires polygon point (x,y) order either clockwise or counter-clockwise */ - public static boolean pointInPolygon(double[] x, double[] y, double lat, double lon) { - assert x.length == y.length; + public static boolean pointInPolygon(double[] polyLats, double[] polyLons, double lat, double lon) { + assert polyLats.length == polyLons.length; boolean inPoly = false; /** * Note: This is using a euclidean coordinate system which could result in * upwards of 110KM error at the equator. * TODO convert coordinates to cylindrical projection (e.g. mercator) */ - for (int i = 1; i < x.length; i++) { - if (x[i] <= lon && x[i-1] >= lon || x[i-1] <= lon && x[i] >= lon) { - if (y[i] + (lon - x[i]) / (x[i-1] - x[i]) * (y[i-1] - y[i]) <= lat) { + for (int i = 1; i < polyLats.length; i++) { + if (polyLons[i] <= lon && polyLons[i-1] >= lon || polyLons[i-1] <= lon && polyLons[i] >= lon) { + if (polyLats[i] + (lon - polyLons[i]) / (polyLons[i-1] - polyLons[i]) * (polyLats[i-1] - polyLats[i]) <= lat) { inPoly = !inPoly; } } @@ -71,42 +72,34 @@ public class GeoRelationUtils { /** * Computes whether two rectangles are disjoint */ - public static boolean rectDisjoint(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY, - final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) { - return (aMaxX < bMinX || aMinX > bMaxX || aMaxY < bMinY || aMinY > bMaxY); + private static boolean rectDisjoint(final double aMinLat, final double aMaxLat, final double aMinLon, final double aMaxLon, + final double bMinLat, final double bMaxLat, final double bMinLon, final double bMaxLon) { + return (aMaxLon < bMinLon || aMinLon > bMaxLon || aMaxLat < bMinLat || aMinLat > bMaxLat); } /** * Computes whether the first (a) rectangle is wholly within another (b) rectangle (shared boundaries allowed) */ - public static boolean rectWithin(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY, - final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) { - return !(aMinX < bMinX || aMinY < bMinY || aMaxX > bMaxX || aMaxY > bMaxY); + public static boolean rectWithin(final double aMinLat, final double aMaxLat, final double aMinLon, final double aMaxLon, + final double bMinLat, final double bMaxLat, final double bMinLon, final double bMaxLon) { + return !(aMinLon < bMinLon || aMinLat < bMinLat || aMaxLon > bMaxLon || aMaxLat > bMaxLat); } /** * Computes whether two rectangles cross */ - public static boolean rectCrosses(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY, - final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) { - return !(rectDisjoint(aMinX, aMinY, aMaxX, aMaxY, bMinX, bMinY, bMaxX, bMaxY) || - rectWithin(aMinX, aMinY, aMaxX, aMaxY, bMinX, bMinY, bMaxX, bMaxY)); - } - - /** - * Computes whether rectangle a contains rectangle b (touching allowed) - */ - public static boolean rectContains(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY, - final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) { - return !(bMinX < aMinX || bMinY < aMinY || bMaxX > aMaxX || bMaxY > aMaxY); + public static boolean rectCrosses(final double aMinLat, final double aMaxLat, final double aMinLon, final double aMaxLon, + final double bMinLat, final double bMaxLat, final double bMinLon, final double bMaxLon) { + return !(rectDisjoint(aMinLat, aMaxLat, aMinLon, aMaxLon, bMinLat, bMaxLat, bMinLon, bMaxLon) || + rectWithin(aMinLat, aMaxLat, aMinLon, aMaxLon, bMinLat, bMaxLat, bMinLon, bMaxLon)); } /** * Computes whether a rectangle intersects another rectangle (crosses, within, touching, etc) */ - public static boolean rectIntersects(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY, - final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) { - return !((aMaxX < bMinX || aMinX > bMaxX || aMaxY < bMinY || aMinY > bMaxY) ); + public static boolean rectIntersects(final double aMinLat, final double aMaxLat, final double aMinLon, final double aMaxLon, + final double bMinLat, final double bMaxLat, final double bMinLon, final double bMaxLon) { + return !((aMaxLon < bMinLon || aMinLon > bMaxLon || aMaxLat < bMinLat || aMinLat > bMaxLat)); } ///////////////////////// @@ -116,33 +109,35 @@ public class GeoRelationUtils { /** * Convenience method for accurately computing whether a rectangle crosses a poly */ - public static boolean rectCrossesPolyPrecise(final double rMinX, final double rMinY, final double rMaxX, - final double rMaxY, final double[] shapeX, final double[] shapeY, - final double sMinX, final double sMinY, final double sMaxX, - final double sMaxY) { + public static boolean rectCrossesPolyPrecise(final double rMinLat, final double rMaxLat, + final double rMinLon, final double rMaxLon, + final double[] shapeLat, final double[] shapeLon, + final double sMinLat, final double sMaxLat, + final double sMinLon, final double sMaxLon) { // short-circuit: if the bounding boxes are disjoint then the shape does not cross - if (rectDisjoint(rMinX, rMinY, rMaxX, rMaxY, sMinX, sMinY, sMaxX, sMaxY)) { + if (rectDisjoint(rMinLat, rMaxLat, rMinLon, rMaxLon, sMinLat, sMaxLat, sMinLon, sMaxLon)) { return false; } - return rectCrossesPoly(rMinX, rMinY, rMaxX, rMaxY, shapeX, shapeY); + return rectCrossesPoly(rMinLat, rMaxLat, rMinLon, rMaxLon, shapeLat, shapeLon); } /** * Compute whether a rectangle crosses a shape. (touching not allowed) Includes a flag for approximating the * relation. */ - public static boolean rectCrossesPolyApprox(final double rMinX, final double rMinY, final double rMaxX, - final double rMaxY, final double[] shapeX, final double[] shapeY, - final double sMinX, final double sMinY, final double sMaxX, - final double sMaxY) { + public static boolean rectCrossesPolyApprox(final double rMinLat, final double rMaxLat, + final double rMinLon, final double rMaxLon, + final double[] shapeLat, final double[] shapeLon, + final double sMinLat, final double sMaxLat, + final double sMinLon, final double sMaxLon) { // short-circuit: if the bounding boxes are disjoint then the shape does not cross - if (rectDisjoint(rMinX, rMinY, rMaxX, rMaxY, sMinX, sMinY, sMaxX, sMaxY)) { + if (rectDisjoint(rMinLat, rMaxLat, rMinLon, rMaxLon, sMinLat, sMaxLat, sMinLon, sMaxLon)) { return false; } - final int polyLength = shapeX.length-1; + final int polyLength = shapeLon.length-1; for (short p=0; p= maxAy || maxBy <= minAy); } // horizontally collinear - final double minAx = Math.min(aX1, aX2); - final double maxAx = Math.max(aX1, aX2); - final double minBx = Math.min(bX1, bX2); - final double maxBx = Math.max(bX1, bX2); + final double minAx = Math.min(aLon1, aLon2); + final double maxAx = Math.max(aLon1, aLon2); + final double minBx = Math.min(bLon1, bLon2); + final double maxBx = Math.max(bLon1, bLon2); return !(minBx >= maxAx || maxBx <= minAx); } @@ -249,107 +250,113 @@ public class GeoRelationUtils { * Computes whether a rectangle is within a polygon (shared boundaries not allowed) with more rigor than the * {@link GeoRelationUtils#rectWithinPolyApprox} counterpart */ - public static boolean rectWithinPolyPrecise(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, - final double[] shapeX, final double[] shapeY, final double sMinX, - final double sMinY, final double sMaxX, final double sMaxY) { + public static boolean rectWithinPolyPrecise(final double rMinLat, final double rMaxLat, final double rMinLon, final double rMaxLon, + final double[] shapeLats, final double[] shapeLons, final double sMinLat, + final double sMaxLat, final double sMinLon, final double sMaxLon) { // check if rectangle crosses poly (to handle concave/pacman polys), then check that all 4 corners // are contained - return !(rectCrossesPolyPrecise(rMinX, rMinY, rMaxX, rMaxY, shapeX, shapeY, sMinX, sMinY, sMaxX, sMaxY) || - !pointInPolygon(shapeX, shapeY, rMinY, rMinX) || !pointInPolygon(shapeX, shapeY, rMinY, rMaxX) || - !pointInPolygon(shapeX, shapeY, rMaxY, rMaxX) || !pointInPolygon(shapeX, shapeY, rMaxY, rMinX)); + return !(rectCrossesPolyPrecise(rMinLat, rMaxLat, rMinLon, rMaxLon, shapeLats, shapeLons, sMinLat, sMaxLat, sMinLon, sMaxLon) || + !pointInPolygon(shapeLats, shapeLons, rMinLat, rMinLon) || !pointInPolygon(shapeLats, shapeLons, rMinLat, rMaxLon) || + !pointInPolygon(shapeLats, shapeLons, rMaxLat, rMaxLon) || !pointInPolygon(shapeLats, shapeLons, rMaxLat, rMinLon)); } /** * Computes whether a rectangle is within a given polygon (shared boundaries allowed) */ - public static boolean rectWithinPolyApprox(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, - final double[] shapeX, final double[] shapeY, final double sMinX, - final double sMinY, final double sMaxX, final double sMaxY) { + public static boolean rectWithinPolyApprox(final double rMinLat, final double rMaxLat, final double rMinLon, final double rMaxLon, + final double[] shapeLats, final double[] shapeLons, final double sMinLat, + final double sMaxLat, final double sMinLon, final double sMaxLon) { // approximation: check if rectangle crosses poly (to handle concave/pacman polys), then check one of the corners // are contained // short-cut: if bounding boxes cross, rect is not within - if (rectCrosses(rMinX, rMinY, rMaxX, rMaxY, sMinX, sMinY, sMaxX, sMaxY) == true) { + if (rectCrosses(rMinLat, rMaxLat, rMinLon, rMaxLon, sMinLat, sMaxLat, sMinLon, sMaxLon) == true) { return false; } - return !(rectCrossesPolyApprox(rMinX, rMinY, rMaxX, rMaxY, shapeX, shapeY, sMinX, sMinY, sMaxX, sMaxY) - || !pointInPolygon(shapeX, shapeY, rMinY, rMinX)); + return !(rectCrossesPolyApprox(rMinLat, rMaxLat, rMinLon, rMaxLon, shapeLats, shapeLons, sMinLat, sMaxLat, sMinLon, sMaxLon) + || !pointInPolygon(shapeLats, shapeLons, rMinLat, rMinLon)); } ///////////////////////// // Circle relations ///////////////////////// - private static boolean rectAnyCornersInCircle(final double rMinX, final double rMinY, final double rMaxX, - final double rMaxY, final double centerLon, final double centerLat, + private static boolean rectAnyCornersInCircle(final double rMinLat, final double rMaxLat, final double rMinLon, + final double rMaxLon, final double centerLat, final double centerLon, final double radiusMeters, final boolean approx) { if (approx == true) { - return rectAnyCornersInCircleSloppy(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters); + return rectAnyCornersInCircleSloppy(rMinLat, rMaxLat, rMinLon, rMaxLon, centerLat, centerLon, radiusMeters); } - double w = Math.abs(rMaxX - rMinX); + double w = Math.abs(rMaxLon - rMinLon); if (w <= 90.0) { - return SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMinX) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMinX) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMaxX) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMaxX) <= radiusMeters; + return SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMinLon) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMinLon) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMaxLon) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMaxLon) <= radiusMeters; } // partition w /= 4; - final double p1 = rMinX + w; + final double p1 = rMinLon + w; final double p2 = p1 + w; final double p3 = p2 + w; - return SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMinX) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMinX) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, p1) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMinY, p1) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMinY, p2) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, p2) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, p3) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMinY, p3) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMaxX) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMaxX) <= radiusMeters; + return SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMinLon) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMinLon) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, p1) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, p1) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, p2) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, p2) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, p3) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, p3) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMaxLon) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMaxLon) <= radiusMeters; } - private static boolean rectAnyCornersInCircleSloppy(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, - final double centerLon, final double centerLat, final double radiusMeters) { - return SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMinX) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMinX) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMaxX) <= radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMaxX) <= radiusMeters; + private static boolean rectAnyCornersInCircleSloppy(final double rMinLat, final double rMaxLat, final double rMinLon, final double rMaxLon, + final double centerLat, final double centerLon, final double radiusMeters) { + return SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMinLon) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMinLon) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMaxLon) <= radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMaxLon) <= radiusMeters; } /** * Compute whether any of the 4 corners of the rectangle (defined by min/max X/Y) are outside the circle (defined * by centerLon, centerLat, radiusMeters) * - * Note: exotic rectangles at the poles (e.g., those whose lon/lat distance ratios greatly deviate from 1) can not + * Note: exotic rectangles at the poles (e.g., those whose lat/lon distance ratios greatly deviate from 1) can not * be determined by using distance alone. For this reason the approx flag may be set to false, in which case the * space will be further divided to more accurately compute whether the rectangle crosses the circle */ - private static boolean rectAnyCornersOutsideCircle(final double rMinX, final double rMinY, final double rMaxX, - final double rMaxY, final double centerLon, final double centerLat, + private static boolean rectAnyCornersOutsideCircle(final double rMinLat, final double rMaxLat, final double rMinLon, + final double rMaxLon, final double centerLat, final double centerLon, final double radiusMeters, final boolean approx) { if (approx == true) { - return rectAnyCornersOutsideCircleSloppy(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters); + return rectAnyCornersOutsideCircleSloppy(rMinLat, rMaxLat, rMinLon, rMaxLon, centerLat, centerLon, radiusMeters); } // if span is less than 70 degrees we can approximate using distance alone - if (Math.abs(rMaxX - rMinX) <= 70.0) { - return SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMinX) > radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMinX) > radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMaxX) > radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMaxX) > radiusMeters; + if (Math.abs(rMaxLon - rMinLon) <= 70.0) { + return SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMinLon) > radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMinLon) > radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMaxLon) > radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMaxLon) > radiusMeters; } - return rectCrossesOblateCircle(centerLon, centerLat, radiusMeters, rMinX, rMinY, rMaxX, rMaxY); + return rectCrossesOblateCircle(centerLat, centerLon, + radiusMeters, + rMinLat, rMaxLat, + rMinLon, rMaxLon); } /** - * Compute whether the rectangle (defined by min/max Lon/Lat) crosses a potentially oblate circle + * Compute whether the rectangle (defined by min/max Lat/Lon) crosses a potentially oblate circle * * TODO benchmark for replacing existing rectCrossesCircle. */ - public static boolean rectCrossesOblateCircle(double centerLon, double centerLat, double radiusMeters, double rMinLon, double rMinLat, double rMaxLon, double rMaxLat) { + private static boolean rectCrossesOblateCircle(double centerLat, double centerLon, + double radiusMeters, + double rMinLat, double rMaxLat, + double rMinLon, double rMaxLon) { double w = Math.abs(rMaxLon - rMinLon); final int segs = (int)Math.ceil(w / 45.0); w /= segs; @@ -373,14 +380,14 @@ public class GeoRelationUtils { // else we treat as an oblate circle by slicing the longitude space and checking the azimuthal range // OPTIMIZATION: this is only executed for latitude values "closeTo" the poles (e.g., 88.0 > lat < -88.0) if ( (rMaxLat > 88.0 || rMinLat < -88.0) - && (pt = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(p1, rMinLat, - GeoProjectionUtils.bearingGreatCircle(p1, rMinLat, p1, rMaxLat), radiusMeters - d1, pt))[1] < rMinLat || pt[1] < rMaxLat - || (pt = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(maxLon, rMinLat, - GeoProjectionUtils.bearingGreatCircle(maxLon, rMinLat, maxLon, rMaxLat), radiusMeters - d2, pt))[1] < rMinLat || pt[1] < rMaxLat - || (pt = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(maxLon, rMinLat, - GeoProjectionUtils.bearingGreatCircle(maxLon, rMinLat, (midLon = p1 + 0.5*(maxLon - p1)), rMaxLat), - radiusMeters - SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, midLon), pt))[1] < rMinLat - || pt[1] < rMaxLat == false ) { + && (pt = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(rMinLat, p1, + GeoProjectionUtils.bearingGreatCircle(rMinLat, p1, rMaxLat, p1), radiusMeters - d1, pt))[1] < rMinLat || pt[1] < rMaxLat + || (pt = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(rMinLat, maxLon, + GeoProjectionUtils.bearingGreatCircle(rMinLat, maxLon, rMaxLat, maxLon), radiusMeters - d2, pt))[1] < rMinLat || pt[1] < rMaxLat + || (pt = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(rMinLat, maxLon, + GeoProjectionUtils.bearingGreatCircle(rMinLat, maxLon, rMaxLat, (midLon = p1 + 0.5*(maxLon - p1))), + radiusMeters - SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, midLon), pt))[1] < rMinLat + || pt[1] < rMaxLat == false ) { return true; } p1 += w; @@ -388,81 +395,77 @@ public class GeoRelationUtils { return false; } - private static boolean rectAnyCornersOutsideCircleSloppy(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, - final double centerLon, final double centerLat, final double radiusMeters) { - return SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMinX) > radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMinX) > radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMaxY, rMaxX) > radiusMeters - || SloppyMath.haversinMeters(centerLat, centerLon, rMinY, rMaxX) > radiusMeters; - } - - /** - * Convenience method for computing whether a rectangle is within a circle using additional precision checks - */ - public static boolean rectWithinCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, - final double centerLon, final double centerLat, final double radiusMeters) { - return rectWithinCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, false); + private static boolean rectAnyCornersOutsideCircleSloppy(final double rMinLat, final double rMaxLat, final double rMinLon, final double rMaxLon, + final double centerLat, final double centerLon, final double radiusMeters) { + return SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMinLon) > radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMinLon) > radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMaxLat, rMaxLon) > radiusMeters + || SloppyMath.haversinMeters(centerLat, centerLon, rMinLat, rMaxLon) > radiusMeters; } /** * Computes whether a rectangle is within a circle. Note: approx == true will be faster but less precise and may * fail on large rectangles */ - public static boolean rectWithinCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, - final double centerLon, final double centerLat, final double radiusMeters, + public static boolean rectWithinCircle(final double rMinLat, final double rMaxLat, final double rMinLon, final double rMaxLon, + final double centerLat, final double centerLon, final double radiusMeters, final boolean approx) { - return rectAnyCornersOutsideCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx) == false; - } - - /** - * Determine if a bbox (defined by minLon, minLat, maxLon, maxLat) contains the provided point (defined by lon, lat) - * NOTE: this is basic method that does not handle dateline or pole crossing. Unwrapping must be done before - * calling this method. - */ - public static boolean rectCrossesCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, - final double centerLon, final double centerLat, final double radiusMeters) { - return rectCrossesCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, false); + return rectAnyCornersOutsideCircle(rMinLat, rMaxLat, rMinLon, rMaxLon, centerLat, centerLon, radiusMeters, approx) == false; } /** * Computes whether a rectangle crosses a circle. Note: approx == true will be faster but less precise and may * fail on large rectangles + * + *

NOTE: this is basic method that does not handle dateline or pole crossing. Unwrapping must be done before + * calling this method. */ - public static boolean rectCrossesCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, - final double centerLon, final double centerLat, final double radiusMeters, + public static boolean rectCrossesCircle(final double rMinLat, final double rMaxLat, final double rMinLon, final double rMaxLon, + final double centerLat, final double centerLon, final double radiusMeters, final boolean approx) { if (approx == true) { - return rectAnyCornersInCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx) - || isClosestPointOnRectWithinRange(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx); + if (rectAnyCornersInCircle(rMinLat, rMaxLat, rMinLon, rMaxLon, centerLat, centerLon, radiusMeters, approx)) { + return true; + } + } else { + if (rectAnyCornersInCircle(rMinLat, rMaxLat, rMinLon, rMaxLon, centerLat, centerLon, radiusMeters, approx) && + rectAnyCornersOutsideCircle(rMinLat, rMaxLat, rMinLon, rMaxLon, centerLat, centerLon, radiusMeters, approx)) { + return true; + } } - - return (rectAnyCornersInCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx) && - rectAnyCornersOutsideCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx)) - || isClosestPointOnRectWithinRange(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx); + if (isClosestPointOnRectWithinRange(rMinLat, rMaxLat, rMinLon, rMaxLon, centerLat, centerLon, radiusMeters, approx)) { + return true; + } + return false; } - private static boolean isClosestPointOnRectWithinRange(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, - final double centerLon, final double centerLat, final double radiusMeters, + private static boolean isClosestPointOnRectWithinRange(final double rMinLat, final double rMaxLat, + final double rMinLon, final double rMaxLon, + final double centerLat, final double centerLon, + final double radiusMeters, final boolean approx) { double[] closestPt = {0, 0}; - GeoDistanceUtils.closestPointOnBBox(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, closestPt); - boolean haverShortCut = SloppyMath.haversinMeters(centerLat, centerLon, closestPt[1], closestPt[0]) <= radiusMeters; + GeoDistanceUtils.closestPointOnBBox(rMinLat, rMaxLat, rMinLon, rMaxLon, centerLat, centerLon, closestPt); + boolean haverShortCut = SloppyMath.haversinMeters(centerLat, centerLon, closestPt[0], closestPt[1]) <= radiusMeters; if (approx == true || haverShortCut == true) { return haverShortCut; } - double lon1 = rMinX; - double lon2 = rMaxX; - double lat1 = rMinY; - double lat2 = rMaxY; - if (closestPt[0] == rMinX || closestPt[0] == rMaxX) { - lon1 = closestPt[0]; + double lon1 = rMinLon; + double lon2 = rMaxLon; + double lat1 = rMinLat; + double lat2 = rMaxLat; + if (closestPt[1] == rMinLon || closestPt[1] == rMaxLon) { + lon1 = closestPt[1]; lon2 = lon1; - } else if (closestPt[1] == rMinY || closestPt[1] == rMaxY) { - lat1 = closestPt[1]; + } else if (closestPt[0] == rMinLat || closestPt[0] == rMaxLat) { + lat1 = closestPt[0]; lat2 = lat1; } - return lineCrossesSphere(lon1, lat1, 0, lon2, lat2, 0, centerLon, centerLat, 0, radiusMeters); + return lineCrossesSphere(lat1, lon1, 0, + lat2, lon2, 0, + centerLat, centerLon, 0, + radiusMeters); } /** @@ -480,17 +483,18 @@ public class GeoRelationUtils { * @param radiusMeters search sphere radius (in meters) * @return whether the provided line segment is a secant of the */ - private static boolean lineCrossesSphere(double lon1, double lat1, double alt1, double lon2, - double lat2, double alt2, double centerLon, double centerLat, - double centerAlt, double radiusMeters) { + private static boolean lineCrossesSphere(double lat1, double lon1, double alt1, + double lat2, double lon2, double alt2, + double centerLat, double centerLon, double centerAlt, + double radiusMeters) { // convert to cartesian 3d (in meters) - double[] ecf1 = GeoProjectionUtils.llaToECF(lon1, lat1, alt1, null); - double[] ecf2 = GeoProjectionUtils.llaToECF(lon2, lat2, alt2, null); - double[] cntr = GeoProjectionUtils.llaToECF(centerLon, centerLat, centerAlt, null); + double[] ecf1 = GeoProjectionUtils.llaToECF(lat1, lon1, alt1, null); + double[] ecf2 = GeoProjectionUtils.llaToECF(lat2, lon2, alt2, null); + double[] cntr = GeoProjectionUtils.llaToECF(centerLat, centerLon, centerAlt, null); // convert radius from arc radius to cartesian radius - double[] oneEighty = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(centerLon, centerLat, 180.0d, radiusMeters, new double[3]); - GeoProjectionUtils.llaToECF(oneEighty[0], oneEighty[1], 0, oneEighty); + double[] oneEighty = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(centerLat, centerLon, 180.0d, radiusMeters, new double[3]); + GeoProjectionUtils.llaToECF(oneEighty[1], oneEighty[0], 0, oneEighty); radiusMeters = GeoDistanceUtils.linearDistance(oneEighty, cntr);// Math.sqrt(oneEighty[0]*cntr[0] + oneEighty[1]*cntr[1] + oneEighty[2]*cntr[2]); http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c5da271b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java ---------------------------------------------------------------------- diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java index 6d755ce..935da60 100644 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java @@ -34,7 +34,6 @@ import static org.apache.lucene.spatial.util.GeoProjectionUtils.MAX_LAT_RADIANS; import static org.apache.lucene.spatial.util.GeoProjectionUtils.MAX_LON_RADIANS; import static org.apache.lucene.spatial.util.GeoProjectionUtils.MIN_LAT_RADIANS; import static org.apache.lucene.spatial.util.GeoProjectionUtils.MIN_LON_RADIANS; -import static org.apache.lucene.spatial.util.GeoProjectionUtils.pointFromLonLatBearingGreatCircle; import static org.apache.lucene.spatial.util.GeoProjectionUtils.SEMIMAJOR_AXIS; /** @@ -93,42 +92,8 @@ public final class GeoUtils { return (off <= 180 ? off : 360-off) - 90; } - /** - * Converts a given circle (defined as a point/radius) to an approximated line-segment polygon - * - * @param lon longitudinal center of circle (in degrees) - * @param lat latitudinal center of circle (in degrees) - * @param radiusMeters distance radius of circle (in meters) - * @return a list of lon/lat points representing the circle - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public static ArrayList circleToPoly(final double lon, final double lat, final double radiusMeters) { - double angle; - // a little under-sampling (to limit the number of polygonal points): using archimedes estimation of pi - final int sides = 25; - ArrayList geometry = new ArrayList(); - double[] lons = new double[sides]; - double[] lats = new double[sides]; - - double[] pt = new double[2]; - final int sidesLen = sides - 1; - for (int i = 0; i < sidesLen; ++i) { - angle = (i * 360 / sides); - pt = pointFromLonLatBearingGreatCircle(lon, lat, angle, radiusMeters, pt); - lons[i] = pt[0]; - lats[i] = pt[1]; - } - // close the poly - lons[sidesLen] = lons[0]; - lats[sidesLen] = lats[0]; - geometry.add(lons); - geometry.add(lats); - - return geometry; - } - /** Compute Bounding Box for a circle using WGS-84 parameters */ - public static GeoRect circleToBBox(final double centerLon, final double centerLat, final double radiusMeters) { + public static GeoRect circleToBBox(final double centerLat, final double centerLon, final double radiusMeters) { final double radLat = TO_RADIANS * centerLat; final double radLon = TO_RADIANS * centerLon; double radDistance = radiusMeters / SEMIMAJOR_AXIS; @@ -155,11 +120,11 @@ public final class GeoUtils { maxLon = MAX_LON_RADIANS; } - return new GeoRect(TO_DEGREES * minLon, TO_DEGREES * maxLon, TO_DEGREES * minLat, TO_DEGREES * maxLat); + return new GeoRect(TO_DEGREES * minLat, TO_DEGREES * maxLat, TO_DEGREES * minLon, TO_DEGREES * maxLon); } /** Compute Bounding Box for a polygon using WGS-84 parameters */ - public static GeoRect polyToBBox(double[] polyLons, double[] polyLats) { + public static GeoRect polyToBBox(double[] polyLats, double[] polyLons) { if (polyLons.length != polyLats.length) { throw new IllegalArgumentException("polyLons and polyLats must be equal length"); } @@ -182,14 +147,14 @@ public final class GeoUtils { maxLat = max(polyLats[i], maxLat); } // expand bounding box by TOLERANCE factor to handle round-off error - return new GeoRect(max(minLon - TOLERANCE, MIN_LON_INCL), min(maxLon + TOLERANCE, MAX_LON_INCL), - max(minLat - TOLERANCE, MIN_LAT_INCL), min(maxLat + TOLERANCE, MAX_LAT_INCL)); + return new GeoRect(max(minLat - TOLERANCE, MIN_LAT_INCL), min(maxLat + TOLERANCE, MAX_LAT_INCL), + max(minLon - TOLERANCE, MIN_LON_INCL), min(maxLon + TOLERANCE, MAX_LON_INCL)); } - // some sloppyish stuff, do we really need this to be done in a sloppy way? // unless it is performance sensitive, we should try to remove. static final double PIO2 = Math.PI / 2D; + /** * Returns the trigonometric sine of an angle converted as a cos operation. *

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c5da271b/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointField.java ---------------------------------------------------------------------- diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointField.java b/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointField.java index fbbf643..41136b9 100644 --- a/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointField.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointField.java @@ -53,22 +53,22 @@ public class TestGeoPointField extends LuceneTestCase { // this is a simple systematic test GeoPointField[] pts = new GeoPointField[] { - new GeoPointField(FIELD_NAME, -96.774, 32.763420, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -96.7759895324707, 32.7559529921407, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -96.77701950073242, 32.77866942010977, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -96.7706036567688, 32.7756745755423, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -139.73458170890808, 27.703618681345585, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -96.4538113027811, 32.94823588839368, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -96.65084838867188, 33.06047141970814, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -96.7772, 32.778650, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -177.23537676036358, -88.56029371730983, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -26.779373834241003, 33.541429799076354, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -77.35379276106497, 26.774024500421728, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -14.796283808944777, -90.0, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -178.8538113027811, 32.94823588839368, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, 178.8538113027811, 32.94823588839368, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -73.998776, 40.720611, GeoPointField.PREFIX_TYPE_NOT_STORED), - new GeoPointField(FIELD_NAME, -179.5, -44.5, GeoPointField.PREFIX_TYPE_NOT_STORED)}; + new GeoPointField(FIELD_NAME, 32.763420, -96.774, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 32.7559529921407, -96.7759895324707, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 32.77866942010977, -96.77701950073242, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 32.7756745755423, -96.7706036567688, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 27.703618681345585, -139.73458170890808, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 32.94823588839368, -96.4538113027811, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 33.06047141970814, -96.65084838867188, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 32.778650, -96.7772, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, -88.56029371730983, -177.23537676036358, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 33.541429799076354, -26.779373834241003, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 26.774024500421728, -77.35379276106497, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, -90.0, -14.796283808944777, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 32.94823588839368, -178.8538113027811, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 32.94823588839368, 178.8538113027811, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, 40.720611, -73.998776, GeoPointField.PREFIX_TYPE_NOT_STORED), + new GeoPointField(FIELD_NAME, -44.5, -179.5, GeoPointField.PREFIX_TYPE_NOT_STORED)}; for (GeoPointField p : pts) { Document doc = new Document(); @@ -105,37 +105,39 @@ public class TestGeoPointField extends LuceneTestCase { directory = null; } - private TopDocs bboxQuery(double minLon, double minLat, double maxLon, double maxLat, int limit) throws Exception { - GeoPointInBBoxQuery q = new GeoPointInBBoxQuery(FIELD_NAME, TermEncoding.PREFIX, minLon, minLat, maxLon, maxLat); + private TopDocs bboxQuery(double minLat, double maxLat, double minLon, double maxLon, int limit) throws Exception { + GeoPointInBBoxQuery q = new GeoPointInBBoxQuery(FIELD_NAME, TermEncoding.PREFIX, minLat, maxLat, minLon, maxLon); return searcher.search(q, limit); } - private TopDocs polygonQuery(double[] lon, double[] lat, int limit) throws Exception { - GeoPointInPolygonQuery q = new GeoPointInPolygonQuery(FIELD_NAME, TermEncoding.PREFIX, lon, lat); + private TopDocs polygonQuery(double[] polyLats, double[] polyLons, int limit) throws Exception { + GeoPointInPolygonQuery q = new GeoPointInPolygonQuery(FIELD_NAME, TermEncoding.PREFIX, polyLats, polyLons); return searcher.search(q, limit); } - private TopDocs geoDistanceQuery(double lon, double lat, double radius, int limit) throws Exception { - GeoPointDistanceQuery q = new GeoPointDistanceQuery(FIELD_NAME, TermEncoding.PREFIX, lon, lat, radius); + private TopDocs geoDistanceQuery(double lat, double lon, double radius, int limit) throws Exception { + GeoPointDistanceQuery q = new GeoPointDistanceQuery(FIELD_NAME, TermEncoding.PREFIX, lat, lon, radius); return searcher.search(q, limit); } - private TopDocs geoDistanceRangeQuery(double lon, double lat, double minRadius, double maxRadius, int limit) + private TopDocs geoDistanceRangeQuery(double lat, double lon, double minRadius, double maxRadius, int limit) throws Exception { - GeoPointDistanceRangeQuery q = new GeoPointDistanceRangeQuery(FIELD_NAME, TermEncoding.PREFIX, lon, lat, minRadius, maxRadius); + GeoPointDistanceRangeQuery q = new GeoPointDistanceRangeQuery(FIELD_NAME, TermEncoding.PREFIX, lat, lon, minRadius, maxRadius); return searcher.search(q, limit); } public void testBBoxQuery() throws Exception { - TopDocs td = bboxQuery(-96.7772, 32.778650, -96.77690000, 32.778950, 5); + TopDocs td = bboxQuery(32.778650, 32.778950, -96.7772, -96.77690000, 5); assertEquals("GeoBoundingBoxQuery failed", 4, td.totalHits); } public void testPolyQuery() throws Exception { - TopDocs td = polygonQuery(new double[]{-96.7682647, -96.8280029, -96.6288757, -96.4929199, - -96.6041564, -96.7449188, -96.76826477, -96.7682647}, - new double[]{33.073130, 32.9942669, 32.938386, 33.0374494, - 33.1369762, 33.1162747, 33.073130, 33.073130}, 5); + TopDocs td = polygonQuery( + new double[]{33.073130, 32.9942669, 32.938386, 33.0374494, + 33.1369762, 33.1162747, 33.073130, 33.073130}, + new double[]{-96.7682647, -96.8280029, -96.6288757, -96.4929199, + -96.6041564, -96.7449188, -96.76826477, -96.7682647}, + 5); assertEquals("GeoPolygonQuery failed", 2, td.totalHits); } @@ -157,56 +159,56 @@ public class TestGeoPointField extends LuceneTestCase { double yMax = 1;//5; // test cell crossing poly - assertTrue(GeoRelationUtils.rectCrossesPolyApprox(xMin, yMin, xMax, yMax, px, py, xMinA, yMinA, xMaxA, yMaxA)); - assertFalse(GeoRelationUtils.rectCrossesPolyApprox(-5, 0, 0.000001, 5, px, py, xMin, yMin, xMax, yMax)); - assertTrue(GeoRelationUtils.rectWithinPolyApprox(-5, 0, -2, 5, px, py, xMin, yMin, xMax, yMax)); + assertTrue(GeoRelationUtils.rectCrossesPolyApprox(yMin, yMax, xMin, yMax, py, px, yMinA, yMaxA, xMinA, xMaxA)); + assertFalse(GeoRelationUtils.rectCrossesPolyApprox(0, 5, -5, 0.000001, py, px, yMin, yMax, xMin, xMax)); + assertTrue(GeoRelationUtils.rectWithinPolyApprox(0, 5, -5, -2, py, px, yMin, yMax, xMin, xMax)); } public void testBBoxCrossDateline() throws Exception { - TopDocs td = bboxQuery(179.0, -45.0, -179.0, -44.0, 20); + TopDocs td = bboxQuery(-45.0, -44.0, 179.0, -179.0, 20); assertEquals("BBoxCrossDateline query failed", 2, td.totalHits); } public void testWholeMap() throws Exception { - TopDocs td = bboxQuery(GeoUtils.MIN_LON_INCL, GeoUtils.MIN_LAT_INCL, GeoUtils.MAX_LON_INCL, GeoUtils.MAX_LAT_INCL, 20); - assertEquals("testWholeMap failed", 24, td.totalHits); - td = polygonQuery(new double[] {GeoUtils.MIN_LON_INCL, GeoUtils.MIN_LON_INCL, GeoUtils.MAX_LON_INCL, GeoUtils.MAX_LON_INCL, GeoUtils.MIN_LON_INCL}, - new double[] {GeoUtils.MIN_LAT_INCL, GeoUtils.MAX_LAT_INCL, GeoUtils.MAX_LAT_INCL, GeoUtils.MIN_LAT_INCL, GeoUtils.MIN_LAT_INCL}, 20); + TopDocs td = bboxQuery(GeoUtils.MIN_LAT_INCL, GeoUtils.MAX_LAT_INCL, GeoUtils.MIN_LON_INCL, GeoUtils.MAX_LON_INCL, 20); assertEquals("testWholeMap failed", 24, td.totalHits); + td = polygonQuery(new double[] {GeoUtils.MIN_LAT_INCL, GeoUtils.MAX_LAT_INCL, GeoUtils.MAX_LAT_INCL, GeoUtils.MIN_LAT_INCL, GeoUtils.MIN_LAT_INCL}, + new double[] {GeoUtils.MIN_LON_INCL, GeoUtils.MIN_LON_INCL, GeoUtils.MAX_LON_INCL, GeoUtils.MAX_LON_INCL, GeoUtils.MIN_LON_INCL}, + 20); assertEquals("testWholeMap failed", 24, td.totalHits); } public void smallTest() throws Exception { - TopDocs td = geoDistanceQuery(-73.998776, 40.720611, 1, 20); + TopDocs td = geoDistanceQuery(40.720611, -73.998776, 1, 20); assertEquals("smallTest failed", 2, td.totalHits); } // GeoBoundingBox should not accept invalid lat/lon public void testInvalidBBox() throws Exception { expectThrows(Exception.class, () -> { - bboxQuery(179.0, -92.0, 181.0, -91.0, 20); + bboxQuery(-92.0, -91.0, 179.0, 181.0, 20); }); } public void testGeoDistanceQuery() throws Exception { - TopDocs td = geoDistanceQuery(-96.4538113027811, 32.94823588839368, 6000, 20); + TopDocs td = geoDistanceQuery(32.94823588839368, -96.4538113027811, 6000, 20); assertEquals("GeoDistanceQuery failed", 2, td.totalHits); } /** see https://issues.apache.org/jira/browse/LUCENE-6905 */ public void testNonEmptyTermsEnum() throws Exception { - TopDocs td = geoDistanceQuery(-177.23537676036358, -88.56029371730983, 7757.999232959935, 20); + TopDocs td = geoDistanceQuery(-88.56029371730983, -177.23537676036358, 7757.999232959935, 20); assertEquals("GeoDistanceQuery failed", 2, td.totalHits); } public void testMultiValuedQuery() throws Exception { - TopDocs td = bboxQuery(-96.4538113027811, 32.7559529921407, -96.7706036567688, 32.7756745755423, 20); + TopDocs td = bboxQuery(32.7559529921407, 32.7756745755423, -96.4538113027811, -96.7706036567688, 20); // 3 single valued docs + 2 multi-valued docs assertEquals("testMultiValuedQuery failed", 5, td.totalHits); } public void testTooBigRadius() throws Exception { IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> { - geoDistanceQuery(0.0, 85.0, 4000000, 20); + geoDistanceQuery(85.0, 0.0, 4000000, 20); }); assertTrue(expected.getMessage().contains("exceeds maxRadius")); } @@ -215,19 +217,19 @@ public class TestGeoPointField extends LuceneTestCase { * Explicitly large */ public void testGeoDistanceQueryHuge() throws Exception { - TopDocs td = geoDistanceQuery(-96.4538113027811, 32.94823588839368, 6000000, 20); + TopDocs td = geoDistanceQuery(32.94823588839368, -96.4538113027811, 6000000, 20); assertEquals("GeoDistanceQuery failed", 16, td.totalHits); } public void testGeoDistanceQueryCrossDateline() throws Exception { - TopDocs td = geoDistanceQuery(-179.9538113027811, 32.94823588839368, 120000, 20); + TopDocs td = geoDistanceQuery(32.94823588839368, -179.9538113027811, 120000, 20); assertEquals("GeoDistanceQuery failed", 3, td.totalHits); } // GeoDistanceQuery should not accept invalid lat/lon as origin public void testInvalidGeoDistanceQuery() throws Exception { expectThrows(Exception.class, () -> { - geoDistanceQuery(181.0, 92.0, 120000, 20); + geoDistanceQuery(92.0, 181.0, 120000, 20); }); } http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c5da271b/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointQuery.java ---------------------------------------------------------------------- diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointQuery.java b/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointQuery.java index 3bf22d3..53ff25c 100644 --- a/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointQuery.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/geopoint/search/TestGeoPointQuery.java @@ -43,27 +43,27 @@ public class TestGeoPointQuery extends BaseGeoPointTestCase { @Override protected void addPointToDoc(String field, Document doc, double lat, double lon) { - doc.add(new GeoPointField(field, lon, lat, GeoPointField.PREFIX_TYPE_NOT_STORED)); + doc.add(new GeoPointField(field, lat, lon, GeoPointField.PREFIX_TYPE_NOT_STORED)); } @Override protected Query newRectQuery(String field, GeoRect rect) { - return new GeoPointInBBoxQuery(field, TermEncoding.PREFIX, rect.minLon, rect.minLat, rect.maxLon, rect.maxLat); + return new GeoPointInBBoxQuery(field, TermEncoding.PREFIX, rect.minLat, rect.maxLat, rect.minLon, rect.maxLon); } @Override protected Query newDistanceQuery(String field, double centerLat, double centerLon, double radiusMeters) { - return new GeoPointDistanceQuery(field, TermEncoding.PREFIX, centerLon, centerLat, radiusMeters); + return new GeoPointDistanceQuery(field, TermEncoding.PREFIX, centerLat, centerLon, radiusMeters); } @Override protected Query newDistanceRangeQuery(String field, double centerLat, double centerLon, double minRadiusMeters, double radiusMeters) { - return new GeoPointDistanceRangeQuery(field, TermEncoding.PREFIX, centerLon, centerLat, minRadiusMeters, radiusMeters); + return new GeoPointDistanceRangeQuery(field, TermEncoding.PREFIX, centerLat, centerLon, minRadiusMeters, radiusMeters); } @Override protected Query newPolygonQuery(String field, double[] lats, double[] lons) { - return new GeoPointInPolygonQuery(field, TermEncoding.PREFIX, lons, lats); + return new GeoPointInPolygonQuery(field, TermEncoding.PREFIX, lats, lons); } @Override @@ -77,11 +77,11 @@ public class TestGeoPointQuery extends BaseGeoPointTestCase { } if (rect.minLon < rect.maxLon) { - return GeoRelationUtils.pointInRectPrecise(pointLon, pointLat, rect.minLon, rect.minLat, rect.maxLon, rect.maxLat); + return GeoRelationUtils.pointInRectPrecise(pointLat, pointLon, rect.minLat, rect.maxLat, rect.minLon, rect.maxLon); } else { // Rect crosses dateline: - return GeoRelationUtils.pointInRectPrecise(pointLon, pointLat, -180.0, rect.minLat, rect.maxLon, rect.maxLat) - || GeoRelationUtils.pointInRectPrecise(pointLon, pointLat, rect.minLon, rect.minLat, 180.0, rect.maxLat); + return GeoRelationUtils.pointInRectPrecise(pointLat, pointLon, rect.minLat, rect.maxLat, -180.0, rect.maxLon) + || GeoRelationUtils.pointInRectPrecise(pointLat, pointLon, rect.minLat, rect.maxLat, rect.minLon, 180.0); } } @@ -112,10 +112,10 @@ public class TestGeoPointQuery extends BaseGeoPointTestCase { private static boolean radiusQueryCanBeWrong(double centerLat, double centerLon, double ptLon, double ptLat, final double radius) { - final long hashedCntr = GeoEncodingUtils.mortonHash(centerLon, centerLat); + final long hashedCntr = GeoEncodingUtils.mortonHash(centerLat, centerLon); centerLon = GeoEncodingUtils.mortonUnhashLon(hashedCntr); centerLat = GeoEncodingUtils.mortonUnhashLat(hashedCntr); - final long hashedPt = GeoEncodingUtils.mortonHash(ptLon, ptLat); + final long hashedPt = GeoEncodingUtils.mortonHash(ptLat, ptLon); ptLon = GeoEncodingUtils.mortonUnhashLon(hashedPt); ptLat = GeoEncodingUtils.mortonUnhashLat(hashedPt);