You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ds...@apache.org on 2017/12/13 21:55:19 UTC
lucene-solr:branch_7x: LUCENE-8086: spatial-extras Geo3dFactory: Use
GeoExactCircle with configurable precision for non-spherical planet models.
Some internal refactorings as well.
Repository: lucene-solr
Updated Branches:
refs/heads/branch_7x 4b4532815 -> caf401c43
LUCENE-8086: spatial-extras Geo3dFactory: Use GeoExactCircle with configurable precision for non-spherical planet models.
Some internal refactorings as well.
(cherry picked from commit d66d954)
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/caf401c4
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/caf401c4
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/caf401c4
Branch: refs/heads/branch_7x
Commit: caf401c43bbe40771ae633c1a62732823930f35f
Parents: 4b45328
Author: David Smiley <ds...@apache.org>
Authored: Wed Dec 13 16:32:48 2017 -0500
Committer: David Smiley <ds...@apache.org>
Committed: Wed Dec 13 16:55:08 2017 -0500
----------------------------------------------------------------------
lucene/CHANGES.txt | 4 +
.../spatial/spatial4j/Geo3dCircleShape.java | 15 --
.../spatial4j/Geo3dDistanceCalculator.java | 60 +----
.../lucene/spatial/spatial4j/Geo3dShape.java | 6 +-
.../spatial/spatial4j/Geo3dShapeFactory.java | 43 ++-
.../Geo3dShapeRectRelationTestCase.java | 264 -------------------
.../Geo3dShapeSphereModelRectRelationTest.java | 8 +-
.../Geo3dShapeWGS84ModelRectRelationTest.java | 10 +-
.../spatial4j/ShapeRectRelationTestCase.java | 201 ++++++++++++++
9 files changed, 261 insertions(+), 350 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/caf401c4/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index e57ed8f..e075448 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -17,6 +17,10 @@ Improvements
disk. This change adds an expert setting to opt ouf of this behavior unless
flusing is falling behind. (Simon Willnauer)
+* LUCENE-8086: spatial-extras Geo3dFactory: Use GeoExactCircle with
+ configurable precision for non-spherical planet models.
+ (Ignacio Vera via David Smiley)
+
======================= Lucene 7.2.0 =======================
API Changes
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/caf401c4/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dCircleShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dCircleShape.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dCircleShape.java
index ccef92a..d01e2b8 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dCircleShape.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dCircleShape.java
@@ -20,13 +20,10 @@ package org.apache.lucene.spatial.spatial4j;
import org.apache.lucene.spatial3d.geom.GeoCircle;
import org.apache.lucene.spatial3d.geom.GeoCircleFactory;
import org.apache.lucene.spatial3d.geom.GeoPointShapeFactory;
-import org.apache.lucene.spatial3d.geom.PlanetModel;
import org.locationtech.spatial4j.context.SpatialContext;
import org.locationtech.spatial4j.distance.DistanceUtils;
import org.locationtech.spatial4j.shape.Circle;
import org.locationtech.spatial4j.shape.Point;
-import org.locationtech.spatial4j.shape.Shape;
-import org.locationtech.spatial4j.shape.SpatialRelation;
/**
* Specialization of a {@link Geo3dShape} which represents a {@link Circle}.
@@ -67,16 +64,4 @@ public class Geo3dCircleShape extends Geo3dShape<GeoCircle> implements Circle {
}
return center;
}
-
- //TODO Improve GeoCircle to properly relate a point with WGS84 model -- LUCENE-7970
- @Override
- public SpatialRelation relate(Shape other) {
- if (shape.getPlanetModel() != PlanetModel.SPHERE && other instanceof Point) {
- if (spatialcontext.getDistCalc().distance((Point) other, getCenter()) <= getRadius()) {
- return SpatialRelation.CONTAINS;
- }
- return SpatialRelation.DISJOINT;
- }
- return super.relate(other);
- }
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/caf401c4/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dDistanceCalculator.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dDistanceCalculator.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dDistanceCalculator.java
index 5154de4..8fdb481 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dDistanceCalculator.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dDistanceCalculator.java
@@ -73,62 +73,20 @@ public class Geo3dDistanceCalculator implements DistanceCalculator {
@Override
public Point pointOnBearing(Point from, double distDEG, double bearingDEG, SpatialContext ctx, Point reuse) {
- // Algorithm using Vincenty's formulae (https://en.wikipedia.org/wiki/Vincenty%27s_formulae)
- // which takes into account that planets may not be spherical.
- //Code adaptation from http://www.movable-type.co.uk/scripts/latlong-vincenty.html
Geo3dPointShape geoFrom = (Geo3dPointShape) from;
GeoPoint point = (GeoPoint) geoFrom.shape;
- double lat = point.getLatitude();
- double lon = point.getLongitude();
double dist = DistanceUtils.DEGREES_TO_RADIANS * distDEG;
double bearing = DistanceUtils.DEGREES_TO_RADIANS * bearingDEG;
-
- double sinα1 = Math.sin(bearing);
- double cosα1 = Math.cos(bearing);
-
- double tanU1 = (1 - planetModel.flattening) * Math.tan(lat);
- double cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1));
- double sinU1 = tanU1 * cosU1;
-
- double σ1 = Math.atan2(tanU1, cosα1);
- double sinα = cosU1 * sinα1;
- double cosSqα = 1 - sinα * sinα;
- double uSq = cosSqα * planetModel.squareRatio;// (planetModel.ab* planetModel.ab - planetModel.c*planetModel.c) / (planetModel.c*planetModel.c);
- double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
- double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
-
- double cos2σM;
- double sinσ;
- double cosσ;
- double Δσ;
-
- double σ = dist / (planetModel.c * A);
- double σʹ;
- double iterations = 0;
- do {
- cos2σM = Math.cos(2 * σ1 + σ);
- sinσ = Math.sin(σ);
- cosσ = Math.cos(σ);
- Δσ = B * sinσ * (cos2σM + B / 4 * (cosσ * (-1 + 2 * cos2σM * cos2σM) -
- B / 6 * cos2σM * (-3 + 4 * sinσ * sinσ) * (-3 + 4 * cos2σM * cos2σM)));
- σʹ = σ;
- σ = dist / (planetModel.c * A) + Δσ;
- } while (Math.abs(σ - σʹ) > 1e-12 && ++iterations < 200);
-
- if (iterations >= 200) {
- throw new RuntimeException("Formula failed to converge");
+ GeoPoint newPoint = planetModel.surfacePointOnBearing(point, dist, bearing);
+ double newLat = newPoint.getLatitude() * DistanceUtils.RADIANS_TO_DEGREES;
+ double newLon = newPoint.getLongitude() * DistanceUtils.RADIANS_TO_DEGREES;
+ if (reuse != null) {
+ reuse.reset(newLon, newLat);
+ return reuse;
+ }
+ else {
+ return ctx.getShapeFactory().pointXY(newLon, newLat);
}
-
- double x = sinU1 * sinσ - cosU1 * cosσ * cosα1;
- double φ2 = Math.atan2(sinU1 * cosσ + cosU1 * sinσ * cosα1, (1 - planetModel.flattening) * Math.sqrt(sinα * sinα + x * x));
- double λ = Math.atan2(sinσ * sinα1, cosU1 * cosσ - sinU1 * sinσ * cosα1);
- double C = planetModel.flattening / 16 * cosSqα * (4 + planetModel.flattening * (4 - 3 * cosSqα));
- double L = λ - (1 - C) * planetModel.flattening * sinα *
- (σ + C * sinσ * (cos2σM + C * cosσ * (-1 + 2 * cos2σM * cos2σM)));
- double λ2 = (lon + L + 3 * Math.PI) % (2 * Math.PI) - Math.PI; // normalise to -180..+180
-
- return ctx.getShapeFactory().pointXY(λ2 * DistanceUtils.RADIANS_TO_DEGREES,
- φ2 * DistanceUtils.RADIANS_TO_DEGREES);
}
@Override
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/caf401c4/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
index eedf7d6..327ac8f 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
@@ -112,11 +112,7 @@ public class Geo3dShape<T extends GeoAreaShape> implements Shape {
if (bbox == null) {
LatLonBounds bounds = new LatLonBounds();
shape.getBounds(bounds);
- double leftLon = bounds.checkNoLongitudeBound() ? -Math.PI : bounds.getLeftLongitude();
- double rightLon = bounds.checkNoLongitudeBound() ? Math.PI : bounds.getRightLongitude();
- double minLat = bounds.checkNoBottomLatitudeBound() ? -Math.PI * 0.5 : bounds.getMinLatitude();
- double maxLat = bounds.checkNoTopLatitudeBound() ? Math.PI * 0.5 : bounds.getMaxLatitude();
- GeoBBox geoBBox = GeoBBoxFactory.makeGeoBBox(shape.getPlanetModel(), maxLat, minLat, leftLon, rightLon);
+ GeoBBox geoBBox = GeoBBoxFactory.makeGeoBBox(shape.getPlanetModel(), bounds);
bbox = new Geo3dRectangleShape(geoBBox, spatialcontext);
this.boundingBox = bbox;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/caf401c4/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShapeFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShapeFactory.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShapeFactory.java
index a80a043..282d93b 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShapeFactory.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShapeFactory.java
@@ -55,6 +55,13 @@ public class Geo3dShapeFactory implements ShapeFactory {
private SpatialContext context;
private PlanetModel planetModel;
+ /**
+ * Default accuracy for circles when not using the unit sphere.
+ * It is equivalent to ~10m on the surface of the earth.
+ */
+ private static final double DEFAULT_CIRCLE_ACCURACY = 1e-4;
+ private double circleAccuracy = DEFAULT_CIRCLE_ACCURACY;
+
@SuppressWarnings("unchecked")
public Geo3dShapeFactory(SpatialContext context, SpatialContextFactory factory) {
this.context = context;
@@ -67,6 +74,16 @@ public class Geo3dShapeFactory implements ShapeFactory {
return context;
}
+ /**
+ * Set the accuracy for circles in decimal degrees. Note that accuracy has no effect
+ * when the planet model is a sphere. In that case, circles are always fully precise.
+ *
+ * @param circleAccuracy the provided accuracy in decimal degrees.
+ */
+ public void setCircleAccuracy(double circleAccuracy) {
+ this.circleAccuracy = circleAccuracy;
+ }
+
@Override
public boolean isNormWrapLongitude() {
return normWrapLongitude;
@@ -150,10 +167,23 @@ public class Geo3dShapeFactory implements ShapeFactory {
@Override
public Circle circle(double x, double y, double distance) {
- GeoCircle circle = GeoCircleFactory.makeGeoCircle(planetModel,
- y * DistanceUtils.DEGREES_TO_RADIANS,
- x * DistanceUtils.DEGREES_TO_RADIANS,
- distance * DistanceUtils.DEGREES_TO_RADIANS);
+ GeoCircle circle;
+ if (planetModel.isSphere()) {
+ circle = GeoCircleFactory.makeGeoCircle(planetModel,
+ y * DistanceUtils.DEGREES_TO_RADIANS,
+ x * DistanceUtils.DEGREES_TO_RADIANS,
+ distance * DistanceUtils.DEGREES_TO_RADIANS);
+ }
+ else {
+ //accuracy is defined as a linear distance in this class. At tiny distances, linear distance
+ //can be approximated to surface distance in radians.
+ circle = GeoCircleFactory.makeExactGeoCircle(planetModel,
+ y * DistanceUtils.DEGREES_TO_RADIANS,
+ x * DistanceUtils.DEGREES_TO_RADIANS,
+ distance * DistanceUtils.DEGREES_TO_RADIANS,
+ circleAccuracy * DistanceUtils.DEGREES_TO_RADIANS);
+
+ }
return new Geo3dCircleShape(circle, context);
}
@@ -238,8 +268,7 @@ public class Geo3dShapeFactory implements ShapeFactory {
/**
* Geo3d implementation of {@link org.locationtech.spatial4j.shape.ShapeFactory.LineStringBuilder} to generate
- * nine Strings. Note that GeoPath needs a buffer so we set the
- * buffer to 1e-10.
+ * line strings.
*/
private class Geo3dLineStringBuilder extends Geo3dPointBuilder<LineStringBuilder> implements LineStringBuilder {
@@ -373,7 +402,7 @@ public class Geo3dShapeFactory implements ShapeFactory {
/**
* Geo3d implementation of {@link org.locationtech.spatial4j.shape.ShapeFactory.MultiShapeBuilder} to generate
- * geometry collections
+ * geometry collections.
*
* @param <T> is the type of shapes.
*/
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/caf401c4/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java
deleted file mode 100644
index 9873012..0000000
--- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.lucene.spatial.spatial4j;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.lucene.spatial3d.geom.GeoPath;
-import org.apache.lucene.spatial3d.geom.GeoPolygon;
-import org.locationtech.spatial4j.TestLog;
-import org.locationtech.spatial4j.context.SpatialContext;
-import org.locationtech.spatial4j.distance.DistanceUtils;
-import org.locationtech.spatial4j.shape.Circle;
-import org.locationtech.spatial4j.shape.Point;
-import org.locationtech.spatial4j.shape.RectIntersectionTestHelper;
-import org.apache.lucene.spatial3d.geom.LatLonBounds;
-import org.apache.lucene.spatial3d.geom.GeoBBox;
-import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
-import org.apache.lucene.spatial3d.geom.GeoCircle;
-import org.apache.lucene.spatial3d.geom.GeoCircleFactory;
-import org.apache.lucene.spatial3d.geom.GeoPathFactory;
-import org.apache.lucene.spatial3d.geom.GeoPoint;
-import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
-import org.apache.lucene.spatial3d.geom.GeoShape;
-import org.apache.lucene.spatial3d.geom.PlanetModel;
-import org.junit.Rule;
-import org.junit.Test;
-
-import static org.locationtech.spatial4j.distance.DistanceUtils.DEGREES_TO_RADIANS;
-
-public abstract class Geo3dShapeRectRelationTestCase extends RandomizedShapeTestCase {
- protected final static double RADIANS_PER_DEGREE = Math.PI/180.0;
-
- @Rule
- public final TestLog testLog = TestLog.instance;
-
- protected final PlanetModel planetModel;
-
- public Geo3dShapeRectRelationTestCase(PlanetModel planetModel) {
- super(SpatialContext.GEO);
- this.planetModel = planetModel;
- }
-
- protected GeoBBox getBoundingBox(final GeoShape path) {
- LatLonBounds bounds = new LatLonBounds();
- path.getBounds(bounds);
-
- double leftLon;
- double rightLon;
- if (bounds.checkNoLongitudeBound()) {
- leftLon = -Math.PI;
- rightLon = Math.PI;
- } else {
- leftLon = bounds.getLeftLongitude().doubleValue();
- rightLon = bounds.getRightLongitude().doubleValue();
- }
- double minLat;
- if (bounds.checkNoBottomLatitudeBound()) {
- minLat = -Math.PI * 0.5;
- } else {
- minLat = bounds.getMinLatitude().doubleValue();
- }
- double maxLat;
- if (bounds.checkNoTopLatitudeBound()) {
- maxLat = Math.PI * 0.5;
- } else {
- maxLat = bounds.getMaxLatitude().doubleValue();
- }
- return GeoBBoxFactory.makeGeoBBox(planetModel, maxLat, minLat, leftLon, rightLon);
- }
-
- public abstract class Geo3dRectIntersectionTestHelper extends RectIntersectionTestHelper<Geo3dShape> {
-
- public Geo3dRectIntersectionTestHelper(SpatialContext ctx) {
- super(ctx);
- }
-
- //20 times each -- should be plenty
-
- protected int getContainsMinimum(int laps) {
- return 20;
- }
-
- protected int getIntersectsMinimum(int laps) {
- return 20;
- }
-
- // producing "within" cases in Geo3D based on our random shapes doesn't happen often. It'd be nice to increase this.
- protected int getWithinMinimum(int laps) {
- return 2;
- }
-
- protected int getDisjointMinimum(int laps) {
- return 20;
- }
-
- protected int getBoundingMinimum(int laps) {
- return 20;
- }
- }
-
- @Test
- public void testGeoCircleRect() {
- new Geo3dRectIntersectionTestHelper(ctx) {
-
- @Override
- protected Geo3dShape generateRandomShape(Point nearP) {
- final int circleRadius = 180 - random().nextInt(180);//no 0-radius
- final Point point = nearP;
- final GeoCircle shape = GeoCircleFactory.makeGeoCircle(planetModel, point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS,
- circleRadius * DEGREES_TO_RADIANS);
- return new Geo3dShape(shape, ctx);
- }
-
- @Override
- protected Point randomPointInEmptyShape(Geo3dShape shape) {
- GeoPoint geoPoint = ((GeoCircle)shape.shape).getCenter();
- return geoPointToSpatial4jPoint(geoPoint);
- }
-
- }.testRelateWithRectangle();
- }
-
- @Test
- public void testGeoBBoxRect() {
- new Geo3dRectIntersectionTestHelper(ctx) {
-
- @Override
- protected boolean isRandomShapeRectangular() {
- return true;
- }
-
- @Override
- protected Geo3dShape generateRandomShape(Point nearP) {
- // (ignoring nearP)
- Point ulhcPoint = randomPoint();
- Point lrhcPoint = randomPoint();
- if (ulhcPoint.getY() < lrhcPoint.getY()) {
- //swap
- Point temp = ulhcPoint;
- ulhcPoint = lrhcPoint;
- lrhcPoint = temp;
- }
- final GeoBBox shape = GeoBBoxFactory.makeGeoBBox(planetModel, ulhcPoint.getY() * DEGREES_TO_RADIANS,
- lrhcPoint.getY() * DEGREES_TO_RADIANS,
- ulhcPoint.getX() * DEGREES_TO_RADIANS,
- lrhcPoint.getX() * DEGREES_TO_RADIANS);
- return new Geo3dShape(shape, ctx);
- }
-
- @Override
- protected Point randomPointInEmptyShape(Geo3dShape shape) {
- return shape.getBoundingBox().getCenter();
- }
- }.testRelateWithRectangle();
- }
-
- @Test
- public void testGeoPolygonRect() {
- new Geo3dRectIntersectionTestHelper(ctx) {
-
- @Override
- protected Geo3dShape generateRandomShape(Point nearP) {
- final Point centerPoint = randomPoint();
- final int maxDistance = random().nextInt(160) + 20;
- final Circle pointZone = ctx.makeCircle(centerPoint, maxDistance);
- final int vertexCount = random().nextInt(3) + 3;
- while (true) {
- final List<GeoPoint> geoPoints = new ArrayList<>();
- while (geoPoints.size() < vertexCount) {
- final Point point = randomPointIn(pointZone);
- final GeoPoint gPt = new GeoPoint(planetModel, point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS);
- geoPoints.add(gPt);
- }
- try {
- final GeoPolygon shape = GeoPolygonFactory.makeGeoPolygon(planetModel, geoPoints);
- if (shape == null) {
- continue;
- }
- return new Geo3dShape(shape, ctx);
- } catch (IllegalArgumentException e) {
- // This is what happens when we create a shape that is invalid. Although it is conceivable that there are cases where
- // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
- continue;
- }
- }
- }
-
- @Override
- protected Point randomPointInEmptyShape(Geo3dShape shape) {
- throw new IllegalStateException("unexpected; need to finish test code");
- }
-
- @Override
- protected int getWithinMinimum(int laps) {
- // Long/thin so lets just find 1.
- return 1;
- }
-
- }.testRelateWithRectangle();
- }
-
- @Test
- public void testGeoPathRect() {
- new Geo3dRectIntersectionTestHelper(ctx) {
-
- @Override
- protected Geo3dShape generateRandomShape(Point nearP) {
- final Point centerPoint = randomPoint();
- final int maxDistance = random().nextInt(160) + 20;
- final Circle pointZone = ctx.makeCircle(centerPoint, maxDistance);
- final int pointCount = random().nextInt(5) + 1;
- final double width = (random().nextInt(89)+1) * DEGREES_TO_RADIANS;
- final GeoPoint[] points = new GeoPoint[pointCount];
- while (true) {
- for (int i = 0; i < pointCount; i++) {
- final Point nextPoint = randomPointIn(pointZone);
- points[i] = new GeoPoint(planetModel, nextPoint.getY() * DEGREES_TO_RADIANS, nextPoint.getX() * DEGREES_TO_RADIANS);
- }
-
- try {
- final GeoPath path = GeoPathFactory.makeGeoPath(planetModel, width, points);
- return new Geo3dShape(path, ctx);
- } catch (IllegalArgumentException e) {
- // This is what happens when we create a shape that is invalid. Although it is conceivable that there are cases where
- // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
- continue;
- }
- }
- }
-
- @Override
- protected Point randomPointInEmptyShape(Geo3dShape shape) {
- throw new IllegalStateException("unexpected; need to finish test code");
- }
-
- @Override
- protected int getWithinMinimum(int laps) {
- // Long/thin so lets just find 1.
- return 1;
- }
-
- }.testRelateWithRectangle();
- }
-
- private Point geoPointToSpatial4jPoint(GeoPoint geoPoint) {
- return ctx.makePoint(geoPoint.getLongitude() * DistanceUtils.RADIANS_TO_DEGREES,
- geoPoint.getLatitude() * DistanceUtils.RADIANS_TO_DEGREES);
- }
-}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/caf401c4/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeSphereModelRectRelationTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeSphereModelRectRelationTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeSphereModelRectRelationTest.java
index 20db21c..bf152b7 100644
--- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeSphereModelRectRelationTest.java
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeSphereModelRectRelationTest.java
@@ -34,13 +34,13 @@ import org.locationtech.spatial4j.shape.Point;
import org.locationtech.spatial4j.shape.Rectangle;
import org.locationtech.spatial4j.shape.SpatialRelation;
-public class Geo3dShapeSphereModelRectRelationTest extends Geo3dShapeRectRelationTestCase {
+public class Geo3dShapeSphereModelRectRelationTest extends ShapeRectRelationTestCase {
+
+ PlanetModel planetModel = PlanetModel.SPHERE;
public Geo3dShapeSphereModelRectRelationTest() {
- super(PlanetModel.SPHERE);
Geo3dSpatialContextFactory factory = new Geo3dSpatialContextFactory();
- factory.planetModel = PlanetModel.SPHERE;
- //factory.distCalc = new GeodesicSphereDistCalc.Haversine();
+ factory.planetModel = planetModel;
this.ctx = factory.newSpatialContext();
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/caf401c4/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
index 22d7bd4..5a7b4b5 100644
--- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
@@ -30,14 +30,16 @@ import org.locationtech.spatial4j.shape.Circle;
import org.locationtech.spatial4j.shape.Point;
import org.locationtech.spatial4j.shape.SpatialRelation;
-public class Geo3dShapeWGS84ModelRectRelationTest extends Geo3dShapeRectRelationTestCase {
+public class Geo3dShapeWGS84ModelRectRelationTest extends ShapeRectRelationTestCase {
+
+ PlanetModel planetModel = PlanetModel.WGS84;
public Geo3dShapeWGS84ModelRectRelationTest() {
- super(PlanetModel.WGS84);
Geo3dSpatialContextFactory factory = new Geo3dSpatialContextFactory();
- factory.planetModel = PlanetModel.WGS84;
- //factory.distCalc = new GeodesicSphereDistCalc.Haversine();
+ factory.planetModel = planetModel;
this.ctx = factory.newSpatialContext();
+ this.maxRadius = 178;
+ ((Geo3dShapeFactory)ctx.getShapeFactory()).setCircleAccuracy(1e-6);
}
@Test
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/caf401c4/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/ShapeRectRelationTestCase.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/ShapeRectRelationTestCase.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/ShapeRectRelationTestCase.java
new file mode 100644
index 0000000..7ec2a2b
--- /dev/null
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/ShapeRectRelationTestCase.java
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.spatial.spatial4j;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.locationtech.spatial4j.TestLog;
+import org.locationtech.spatial4j.context.SpatialContext;
+import org.locationtech.spatial4j.shape.Circle;
+import org.locationtech.spatial4j.shape.Point;
+import org.locationtech.spatial4j.shape.RectIntersectionTestHelper;
+import org.locationtech.spatial4j.shape.Shape;
+import org.locationtech.spatial4j.shape.ShapeFactory;
+
+import static org.locationtech.spatial4j.distance.DistanceUtils.DEGREES_TO_RADIANS;
+
+public abstract class ShapeRectRelationTestCase extends RandomizedShapeTestCase {
+ protected final static double RADIANS_PER_DEGREE = Math.PI/180.0;
+
+ @Rule
+ public final TestLog testLog = TestLog.instance;
+
+ protected int maxRadius = 180;
+
+ public ShapeRectRelationTestCase() {
+ super(SpatialContext.GEO);
+ }
+
+ public abstract class AbstractRectIntersectionTestHelper extends RectIntersectionTestHelper<Shape> {
+
+ public AbstractRectIntersectionTestHelper(SpatialContext ctx) {
+ super(ctx);
+ }
+
+ //20 times each -- should be plenty
+
+ protected int getContainsMinimum(int laps) {
+ return 20;
+ }
+
+ protected int getIntersectsMinimum(int laps) {
+ return 20;
+ }
+
+ // producing "within" cases in Geo3D based on our random shapes doesn't happen often. It'd be nice to increase this.
+ protected int getWithinMinimum(int laps) {
+ return 2;
+ }
+
+ protected int getDisjointMinimum(int laps) {
+ return 20;
+ }
+
+ protected int getBoundingMinimum(int laps) {
+ return 20;
+ }
+ }
+
+ @Test
+ public void testGeoCircleRect() {
+ new AbstractRectIntersectionTestHelper(ctx) {
+
+ @Override
+ protected Shape generateRandomShape(Point nearP) {
+ final int circleRadius = maxRadius - random().nextInt(maxRadius);//no 0-radius
+ return ctx.getShapeFactory().circle(nearP, circleRadius);
+ }
+
+ @Override
+ protected Point randomPointInEmptyShape(Shape shape) {
+ return shape.getCenter();
+ }
+
+ }.testRelateWithRectangle();
+ }
+
+ @Test
+ public void testGeoBBoxRect() {
+ new AbstractRectIntersectionTestHelper(ctx) {
+
+ @Override
+ protected boolean isRandomShapeRectangular() {
+ return true;
+ }
+
+ @Override
+ protected Shape generateRandomShape(Point nearP) {
+ Point upperRight = randomPoint();
+ Point lowerLeft = randomPoint();
+ if (upperRight.getY() < lowerLeft.getY()) {
+ //swap
+ Point temp = upperRight;
+ upperRight = lowerLeft;
+ lowerLeft = temp;
+ }
+ return ctx.getShapeFactory().rect(lowerLeft, upperRight);
+ }
+
+ @Override
+ protected Point randomPointInEmptyShape(Shape shape) {
+ return shape.getCenter();
+ }
+ }.testRelateWithRectangle();
+ }
+
+ @Test
+ public void testGeoPolygonRect() {
+ new AbstractRectIntersectionTestHelper(ctx) {
+
+ @Override
+ protected Shape generateRandomShape(Point nearP) {
+ final Point centerPoint = randomPoint();
+ final int maxDistance = random().nextInt(maxRadius -20) + 20;
+ final Circle pointZone = ctx.getShapeFactory().circle(centerPoint, maxDistance);
+ final int vertexCount = random().nextInt(3) + 3;
+ while (true) {
+ ShapeFactory.PolygonBuilder builder = ctx.getShapeFactory().polygon();
+ for (int i = 0; i < vertexCount; i++) {
+ final Point point = randomPointIn(pointZone);
+ builder.pointXY(point.getX(), point.getY());
+ }
+ try {
+ return builder.build();
+ } catch (IllegalArgumentException e) {
+ // This is what happens when we create a shape that is invalid. Although it is conceivable that there are cases where
+ // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
+ continue;
+ }
+ }
+ }
+
+ @Override
+ protected Point randomPointInEmptyShape(Shape shape) {
+ throw new IllegalStateException("unexpected; need to finish test code");
+ }
+
+ @Override
+ protected int getWithinMinimum(int laps) {
+ // Long/thin so lets just find 1.
+ return 1;
+ }
+
+ }.testRelateWithRectangle();
+ }
+
+ @Test
+ public void testGeoPathRect() {
+ new AbstractRectIntersectionTestHelper(ctx) {
+
+ @Override
+ protected Shape generateRandomShape(Point nearP) {
+ final Point centerPoint = randomPoint();
+ final int maxDistance = random().nextInt(maxRadius -20) + 20;
+ final Circle pointZone = ctx.getShapeFactory().circle(centerPoint, maxDistance);
+ final int pointCount = random().nextInt(5) + 1;
+ final double width = (random().nextInt(89)+1) * DEGREES_TO_RADIANS;
+ final ShapeFactory.LineStringBuilder builder = ctx.getShapeFactory().lineString();
+ while (true) {
+ for (int i = 0; i < pointCount; i++) {
+ final Point nextPoint = randomPointIn(pointZone);
+ builder.pointXY(nextPoint.getX(), nextPoint.getY());
+ }
+ builder.buffer(width);
+ try {
+ return builder.build();
+ } catch (IllegalArgumentException e) {
+ // This is what happens when we create a shape that is invalid. Although it is conceivable that there are cases where
+ // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
+ continue;
+ }
+ }
+ }
+
+ @Override
+ protected Point randomPointInEmptyShape(Shape shape) {
+ throw new IllegalStateException("unexpected; need to finish test code");
+ }
+
+ @Override
+ protected int getWithinMinimum(int laps) {
+ // Long/thin so lets just find 1.
+ return 1;
+ }
+
+ }.testRelateWithRectangle();
+ }
+}