From 0a00734a60938f5705e2fad1605c291ecb592bf2 Mon Sep 17 00:00:00 2001 From: David Wayne Smiley Date: Wed, 27 May 2015 13:34:52 +0000 Subject: [PATCH] LUCENE-6487: Geo3D with WGS84 patch from Karl: GeoPoint.getLat & getLon. git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene6487@1682021 13f79535-47bb-0310-9956-ffa450edef68 --- .../spatial/spatial4j/geo3d/GeoPoint.java | 51 ++++++++++++++++++- .../lucene/spatial/spatial4j/geo3d/Plane.java | 2 +- .../spatial/spatial4j/geo3d/Vector.java | 20 +++++--- .../Geo3dShapeRectRelationTestCase.java | 4 +- 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java index 67844371359..335c6db877c 100755 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java @@ -24,30 +24,79 @@ package org.apache.lucene.spatial.spatial4j.geo3d; */ public class GeoPoint extends Vector { + /** This is the lazily-evaluated magnitude. Some constructors include it, but others don't, and + * we try not to create extra computation by always computing it. */ protected double magnitude = Double.NEGATIVE_INFINITY; + /** Construct a GeoPoint from the trig functions of a lat and lon pair. + * @param planetModel is the planetModel to put the point on. + * @param sinLat is the sin of the latitude. + * @param sinLon is the sin of the longitude. + * @param cosLat is the cos of the latitude. + * @param cosLon is the cos of the longitude. + */ public GeoPoint(final PlanetModel planetModel, final double sinLat, final double sinLon, final double cosLat, final double cosLon) { - this(computeMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat), + this(computeDesiredEllipsoidMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat), cosLat * cosLon, cosLat * sinLon, sinLat); } + /** Construct a GeoPoint from a latitude/longitude pair. + * @param planetModel is the planetModel to put the point on. + * @param lat is the latitude. + * @param lon is the longitude. + */ public GeoPoint(final PlanetModel planetModel, final double lat, final double lon) { this(planetModel, Math.sin(lat), Math.sin(lon), Math.cos(lat), Math.cos(lon)); } + /** Construct a GeoPoint from a unit (x,y,z) vector and a magnitude. + * @param magnitude is the desired magnitude, provided to put the point on the ellipsoid. + * @param x is the unit x value. + * @param y is the unit y value. + * @param z is the unit z value. + */ public GeoPoint(final double magnitude, final double x, final double y, final double z) { super(x * magnitude, y * magnitude, z * magnitude); this.magnitude = magnitude; } + /** Construct a GeoPoint from an (x,y,z) value. + * The (x,y,z) tuple must be on the desired ellipsoid. + * @param x is the ellipsoid point x value. + * @param y is the ellipsoid point y value. + * @param z is the ellipsoid point z value. + */ public GeoPoint(final double x, final double y, final double z) { super(x, y, z); } + /** Compute an arc distance between two points. + * @param v is the second point. + * @return the angle, in radians, between the two points. + */ public double arcDistance(final GeoPoint v) { return Tools.safeAcos(dotProduct(v)/(magnitude() * v.magnitude())); } + /** Compute the latitude for the point. + *@return the latitude. + */ + public double getLatitude() { + return Math.asin(z / magnitude() ); + } + + /** Compute the longitude for the point. + * @return the longitude value. Uses 0.0 if there is no computable longitude. + */ + public double getLongitude() { + if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(y) < MINIMUM_RESOLUTION) + return 0.0; + return Math.atan2(y,z); + } + + /** Compute the linear magnitude of the point. + * @return the magnitude. + */ @Override public double magnitude() { if (this.magnitude == Double.NEGATIVE_INFINITY) { diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Plane.java b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Plane.java index 95f19a9c15f..b5f79dfdc17 100755 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Plane.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Plane.java @@ -56,7 +56,7 @@ public class Plane extends Vector { */ public Plane(final PlanetModel planetModel, final double sinLat) { super(0.0, 0.0, 1.0); - D = -sinLat * computeMagnitude(planetModel, sinLat); + D = -sinLat * computeDesiredEllipsoidMagnitude(planetModel, sinLat); } /** diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Vector.java b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Vector.java index fe84c05611f..a29249f4c72 100755 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Vector.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Vector.java @@ -307,20 +307,28 @@ public class Vector { return Math.sqrt(x * x + y * y + z * z); } - /** Compute the magnitude of a vector projected to a given + /** Compute the desired magnitude of a unit vector projected to a given * planet model. + * @param planetModel is the planet model. + * @param x is the unit vector x value. + * @param y is the unit vector y value. + * @param z is the unit vector z value. + * @return a magnitude value for that (x,y,z) that projects the vector onto the specified ellipsoid. */ - protected static double computeMagnitude(final PlanetModel planetModel, final double x, final double y, final double z) { + protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double x, final double y, final double z) { return 1.0 / Math.sqrt(x*x*planetModel.inverseAbSquared + y*y*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared); } - /** Compute the magnitude of a vector projected to a given - * planet model. + /** Compute the desired magnitude of a unit vector projected to a given + * planet model. The unit vector is specified only by a z value. + * @param planetModel is the planet model. + * @param z is the unit vector z value. + * @return a magnitude value for that z value that projects the vector onto the specified ellipsoid. */ - protected static double computeMagnitude(final PlanetModel planetModel, final double z) { + protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double z) { return 1.0 / Math.sqrt((1.0-z*z)*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared); } - + @Override public boolean equals(Object o) { if (!(o instanceof Vector)) diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java index 2755d848667..14b117288c3 100644 --- a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java @@ -237,7 +237,7 @@ public abstract class Geo3dShapeRectRelationTestCase extends RandomizedShapeTest } private Point geoPointToSpatial4jPoint(GeoPoint geoPoint) { - return ctx.makePoint(geoPoint.x * DistanceUtils.RADIANS_TO_DEGREES, - geoPoint.y * DistanceUtils.RADIANS_TO_DEGREES); + return ctx.makePoint(geoPoint.getLongitude() * DistanceUtils.RADIANS_TO_DEGREES, + geoPoint.getLongitude() * DistanceUtils.RADIANS_TO_DEGREES); } }