From 8b732099c7bcbb19cf30f3945ef2f5126d9f9112 Mon Sep 17 00:00:00 2001 From: Karl Wright Date: Wed, 13 Dec 2017 07:09:46 -0500 Subject: [PATCH] LUCENE-8095: Improve javadocs for circle constructors, and rename some variables. --- .../spatial3d/geom/GeoCircleFactory.java | 29 +++++++--- .../lucene/spatial3d/geom/GeoExactCircle.java | 55 ++++++++++--------- .../spatial3d/geom/GeoStandardCircle.java | 4 +- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java index 8feecced9c5..f32f366e62e 100644 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java @@ -26,27 +26,40 @@ public class GeoCircleFactory { } /** - * Create a GeoCircle of the right kind given the specified bounds. + * Create a GeoCircle from a center and a cutoff angle. The resulting shape is a circle in spherical + * planets, otherwise is an ellipse. It is the most efficient shape to represent a circle on a sphere. + * * @param planetModel is the planet model. * @param latitude is the center latitude. * @param longitude is the center longitude. - * @param radius is the radius angle. + * @param cutoffAngle is the cutoff angle. * @return a GeoCircle corresponding to what was specified. */ - public static GeoCircle makeGeoCircle(final PlanetModel planetModel, final double latitude, final double longitude, final double radius) { - if (radius < Vector.MINIMUM_ANGULAR_RESOLUTION) { + public static GeoCircle makeGeoCircle(final PlanetModel planetModel, final double latitude, final double longitude, final double cutoffAngle) { + if (cutoffAngle < Vector.MINIMUM_ANGULAR_RESOLUTION) { return new GeoDegeneratePoint(planetModel, latitude, longitude); } - return new GeoStandardCircle(planetModel, latitude, longitude, radius); + return new GeoStandardCircle(planetModel, latitude, longitude, cutoffAngle); } - /** Create an exact GeoCircle given specified bounds and desired accuracy. + /** + * Create an GeoCircle from a center, a radius and a desired accuracy. It is the most accurate shape to represent + * a circle in non-spherical planets. + *

+ * The accuracy of the circle is defined as the maximum linear distance between any point on the + * surface circle and planes that describe the circle. Therefore, with planet model WSG84, since the + * radius of earth is 6,371,000 meters, an accuracy of 1e-6 corresponds to 6.3 meters. + * For an accuracy of 1.0 meters, the accuracy value would be 1.6e-7. The maximum accuracy possible is 1e-12. + *

+ * Note that this method may thrown an IllegalArgumentException if the circle being specified cannot be + * represented by plane approximation given the planet model provided. + * * @param planetModel is the planet model. * @param latitude is the center latitude. * @param longitude is the center longitude. * @param radius is the radius surface distance. - * @param accuracy is the maximum linear distance between the circle approximation and the real circle, as computed using - * the Vincenty formula. + * @param accuracy is the maximum linear distance between the circle approximation and the real circle, + * as computed using the Vincenty formula. * @return a GeoCircle corresponding to what was specified. */ public static GeoCircle makeExactGeoCircle(final PlanetModel planetModel, final double latitude, final double longitude, final double radius, final double accuracy) { diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoExactCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoExactCircle.java index 876b24f4a41..845dd6a4d6c 100644 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoExactCircle.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoExactCircle.java @@ -24,44 +24,47 @@ import java.io.InputStream; import java.io.OutputStream; /** - * Circular area with a center and radius. + * Circular area with a center and a radius that represents the surface distance to the center. + * The circle is divided in sectors where the circle edge is approximated using Vincenty formulae. + * The higher is the precision the more sectors are needed to describe the shape and therefore a penalty + * in performance. * * @lucene.experimental */ class GeoExactCircle extends GeoBaseCircle { /** Center of circle */ protected final GeoPoint center; - /** Cutoff angle of circle (not quite the same thing as radius) */ - protected final double cutoffAngle; + /** Radius of circle */ + protected final double radius; /** Actual accuracy */ protected final double actualAccuracy; - /** A point that is on the world and on the circle plane */ + /** A point that is on the edge of the circle */ protected final GeoPoint[] edgePoints; - /** Slices of the circle. */ + /** Slices of the circle */ protected final List circleSlices; /** Constructor. *@param planetModel is the planet model. *@param lat is the center latitude. *@param lon is the center longitude. - *@param cutoffAngle is the surface radius for the circle. - *@param accuracy is the allowed error value (linear distance). + *@param radius is the surface radius for the circle. + *@param accuracy is the allowed error value (linear distance). Maximum accuracy is 1e-12. */ - public GeoExactCircle(final PlanetModel planetModel, final double lat, final double lon, final double cutoffAngle, final double accuracy) { + public GeoExactCircle(final PlanetModel planetModel, final double lat, final double lon, final double radius, final double accuracy) { super(planetModel); if (lat < -Math.PI * 0.5 || lat > Math.PI * 0.5) throw new IllegalArgumentException("Latitude out of bounds"); if (lon < -Math.PI || lon > Math.PI) throw new IllegalArgumentException("Longitude out of bounds"); - if (cutoffAngle < 0.0) - throw new IllegalArgumentException("Cutoff angle out of bounds"); - if (cutoffAngle < Vector.MINIMUM_RESOLUTION) - throw new IllegalArgumentException("Cutoff angle cannot be effectively zero"); - if (planetModel.minimumPoleDistance - cutoffAngle < Vector.MINIMUM_RESOLUTION) - throw new IllegalArgumentException("Cutoff angle out of bounds. It cannot be bigger than " + planetModel.minimumPoleDistance + " for this planet model"); + if (radius < 0.0) + throw new IllegalArgumentException("Radius out of bounds"); + if (radius < Vector.MINIMUM_RESOLUTION) + throw new IllegalArgumentException("Radius cannot be effectively zero"); + if (planetModel.minimumPoleDistance - radius < Vector.MINIMUM_RESOLUTION) + throw new IllegalArgumentException("Radius out of bounds. It cannot be bigger than " + planetModel.minimumPoleDistance + " for this planet model"); this.center = new GeoPoint(planetModel, lat, lon); - this.cutoffAngle = cutoffAngle; + this.radius = radius; if (accuracy < Vector.MINIMUM_RESOLUTION) { actualAccuracy = Vector.MINIMUM_RESOLUTION; @@ -72,10 +75,10 @@ class GeoExactCircle extends GeoBaseCircle { // We construct approximation planes until we have a low enough error estimate final List slices = new ArrayList<>(100); // Construct four cardinal points, and then we'll build the first two planes - final GeoPoint northPoint = planetModel.surfacePointOnBearing(center, cutoffAngle, 0.0); - final GeoPoint southPoint = planetModel.surfacePointOnBearing(center, cutoffAngle, Math.PI); - final GeoPoint eastPoint = planetModel.surfacePointOnBearing(center, cutoffAngle, Math.PI * 0.5); - final GeoPoint westPoint = planetModel.surfacePointOnBearing(center, cutoffAngle, Math.PI * 1.5); + final GeoPoint northPoint = planetModel.surfacePointOnBearing(center, radius, 0.0); + final GeoPoint southPoint = planetModel.surfacePointOnBearing(center, radius, Math.PI); + final GeoPoint eastPoint = planetModel.surfacePointOnBearing(center, radius, Math.PI * 0.5); + final GeoPoint westPoint = planetModel.surfacePointOnBearing(center, radius, Math.PI * 1.5); final GeoPoint edgePoint; if (planetModel.c > planetModel.ab) { @@ -101,9 +104,9 @@ class GeoExactCircle extends GeoBaseCircle { // To do this, we need to look at the part of the circle that will have the greatest error. // We will need to compute bearing points for these. final double interpPoint1Bearing = (thisSlice.point1Bearing + thisSlice.middlePointBearing) * 0.5; - final GeoPoint interpPoint1 = planetModel.surfacePointOnBearing(center, cutoffAngle, interpPoint1Bearing); + final GeoPoint interpPoint1 = planetModel.surfacePointOnBearing(center, radius, interpPoint1Bearing); final double interpPoint2Bearing = (thisSlice.point2Bearing + thisSlice.middlePointBearing) * 0.5; - final GeoPoint interpPoint2 = planetModel.surfacePointOnBearing(center, cutoffAngle, interpPoint2Bearing); + final GeoPoint interpPoint2 = planetModel.surfacePointOnBearing(center, radius, interpPoint2Bearing); // Is this point on the plane? (that is, is the approximation good enough?) if (!thisSlice.mustSplit && Math.abs(thisSlice.plane.evaluate(interpPoint1)) < actualAccuracy && Math.abs(thisSlice.plane.evaluate(interpPoint2)) < actualAccuracy) { @@ -145,13 +148,13 @@ class GeoExactCircle extends GeoBaseCircle { public void write(final OutputStream outputStream) throws IOException { SerializableObject.writeDouble(outputStream, center.getLatitude()); SerializableObject.writeDouble(outputStream, center.getLongitude()); - SerializableObject.writeDouble(outputStream, cutoffAngle); + SerializableObject.writeDouble(outputStream, radius); SerializableObject.writeDouble(outputStream, actualAccuracy); } @Override public double getRadius() { - return cutoffAngle; + return radius; } @Override @@ -235,14 +238,14 @@ class GeoExactCircle extends GeoBaseCircle { if (!(o instanceof GeoExactCircle)) return false; GeoExactCircle other = (GeoExactCircle) o; - return super.equals(other) && other.center.equals(center) && other.cutoffAngle == cutoffAngle && other.actualAccuracy == actualAccuracy; + return super.equals(other) && other.center.equals(center) && other.radius == radius && other.actualAccuracy == actualAccuracy; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + center.hashCode(); - long temp = Double.doubleToLongBits(cutoffAngle); + long temp = Double.doubleToLongBits(radius); result = 31 * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(actualAccuracy); result = 31 * result + (int) (temp ^ (temp >>> 32)); @@ -251,7 +254,7 @@ class GeoExactCircle extends GeoBaseCircle { @Override public String toString() { - return "GeoExactCircle: {planetmodel=" + planetModel+", center=" + center + ", radius=" + cutoffAngle + "(" + cutoffAngle * 180.0 / Math.PI + "), accuracy=" + actualAccuracy + "}"; + return "GeoExactCircle: {planetmodel=" + planetModel+", center=" + center + ", radius=" + radius + "(" + radius * 180.0 / Math.PI + "), accuracy=" + actualAccuracy + "}"; } /** A temporary description of a section of circle. diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java index acba9f50053..7ac45932c0d 100755 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java @@ -21,7 +21,9 @@ import java.io.OutputStream; import java.io.IOException; /** - * Circular area with a center and radius. + * Circular area with a center and cutoff angle that represents the latitude and longitude distance + * from the center where the planet will be cut. The resulting area is a circle for spherical + * planets and an ellipse otherwise. * * @lucene.experimental */