blob: 3113aed5fd60d59406117c805c1fe1688bd67337 [file] [log] [blame]
/*
* 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 java.util.Random;
import com.carrotsearch.randomizedtesting.RandomizedContext;
import com.spatial4j.core.TestLog;
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.shape.Circle;
import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.RectIntersectionTestHelper;
import org.apache.lucene.geo3d.LatLonBounds;
import org.apache.lucene.geo3d.GeoBBox;
import org.apache.lucene.geo3d.GeoBBoxFactory;
import org.apache.lucene.geo3d.GeoStandardCircle;
import org.apache.lucene.geo3d.GeoPath;
import org.apache.lucene.geo3d.GeoPoint;
import org.apache.lucene.geo3d.GeoPolygonFactory;
import org.apache.lucene.geo3d.GeoShape;
import org.apache.lucene.geo3d.PlanetModel;
import org.junit.Rule;
import org.junit.Test;
import static com.spatial4j.core.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);
}
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;
}
}
@AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/LUCENE-6867")
@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 GeoShape shape = new GeoStandardCircle(planetModel, point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS,
circleRadius * DEGREES_TO_RADIANS);
return new Geo3dShape(planetModel, shape, ctx);
}
@Override
protected Point randomPointInEmptyShape(Geo3dShape shape) {
GeoPoint geoPoint = ((GeoStandardCircle)shape.shape).getCenter();
return geoPointToSpatial4jPoint(geoPoint);
}
}.testRelateWithRectangle();
}
@AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/LUCENE-6867")
@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 GeoShape 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(planetModel, shape, ctx);
}
@Override
protected Point randomPointInEmptyShape(Geo3dShape shape) {
return shape.getBoundingBox().getCenter();
}
}.testRelateWithRectangle();
}
@AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/LUCENE-6867")
@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);
}
final int convexPointIndex = random().nextInt(vertexCount); //If we get this wrong, hopefully we get IllegalArgumentException
try {
final GeoShape shape = GeoPolygonFactory.makeGeoPolygon(planetModel, geoPoints, convexPointIndex);
return new Geo3dShape(planetModel, 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();
}
@AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/LUCENE-6867")
@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;
while (true) {
try {
final GeoPath path = new GeoPath(planetModel, width);
for (int i = 0; i < pointCount; i++) {
final Point nextPoint = randomPointIn(pointZone);
path.addPoint(nextPoint.getY() * DEGREES_TO_RADIANS, nextPoint.getX() * DEGREES_TO_RADIANS);
}
path.done();
return new Geo3dShape(planetModel, 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.getLongitude() * DistanceUtils.RADIANS_TO_DEGREES);
}
}