blob: 518c9bef3972cce3b768780a3ffac8ddcaea5079 [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.document;
import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitudeCeil;
import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitudeCeil;
import static org.apache.lucene.geo.GeoTestUtil.nextLatitude;
import static org.apache.lucene.geo.GeoTestUtil.nextLongitude;
import com.carrotsearch.randomizedtesting.generators.RandomPicks;
import java.util.Arrays;
import org.apache.lucene.document.ShapeField.QueryRelation;
import org.apache.lucene.geo.Circle;
import org.apache.lucene.geo.Component2D;
import org.apache.lucene.geo.GeoTestUtil;
import org.apache.lucene.geo.GeoUtils;
import org.apache.lucene.geo.LatLonGeometry;
import org.apache.lucene.geo.Line;
import org.apache.lucene.geo.Point;
import org.apache.lucene.geo.Polygon;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.geo.Tessellator;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.TestUtil;
/** Base test case for testing geospatial indexing and search functionality * */
public abstract class BaseLatLonSpatialTestCase extends BaseSpatialTestCase {
protected abstract ShapeType getShapeType();
protected Object nextShape() {
return getShapeType().nextShape();
}
@Override
protected Component2D toLine2D(Object... lines) {
return LatLonGeometry.create(Arrays.stream(lines).toArray(Line[]::new));
}
@Override
protected Component2D toPolygon2D(Object... polygons) {
return LatLonGeometry.create(Arrays.stream(polygons).toArray(Polygon[]::new));
}
@Override
protected Component2D toRectangle2D(double minX, double maxX, double minY, double maxY) {
return LatLonGeometry.create(new Rectangle(minY, maxY, minX, maxX));
}
@Override
protected Component2D toPoint2D(Object... points) {
double[][] p = Arrays.stream(points).toArray(double[][]::new);
Point[] pointArray = new Point[points.length];
for (int i = 0; i < points.length; i++) {
pointArray[i] = new Point(p[i][0], p[i][1]);
}
return LatLonGeometry.create(pointArray);
}
@Override
protected Component2D toCircle2D(Object circle) {
return LatLonGeometry.create((Circle) circle);
}
@Override
protected Circle nextCircle() {
final double radiusMeters =
random().nextDouble() * GeoUtils.EARTH_MEAN_RADIUS_METERS * Math.PI / 2.0 + 1.0;
return new Circle(nextLatitude(), nextLongitude(), radiusMeters);
}
@Override
public Rectangle randomQueryBox() {
return GeoTestUtil.nextBox();
}
@Override
protected Object[] nextPoints() {
int numPoints = TestUtil.nextInt(random(), 1, 20);
double[][] points = new double[numPoints][2];
for (int i = 0; i < numPoints; i++) {
points[i][0] = nextLatitude();
points[i][1] = nextLongitude();
}
return points;
}
@Override
protected double rectMinX(Object rect) {
return ((Rectangle) rect).minLon;
}
@Override
protected double rectMaxX(Object rect) {
return ((Rectangle) rect).maxLon;
}
@Override
protected double rectMinY(Object rect) {
return ((Rectangle) rect).minLat;
}
/** factory method to create a new polygon query */
protected Query newPolygonQuery(String field, QueryRelation queryRelation, Polygon... polygons) {
return LatLonShape.newPolygonQuery(field, queryRelation, polygons);
}
@Override
protected double rectMaxY(Object rect) {
return ((Rectangle) rect).maxLat;
}
@Override
protected boolean rectCrossesDateline(Object rect) {
return ((Rectangle) rect).crossesDateline();
}
@Override
public Line nextLine() {
return GeoTestUtil.nextLine();
}
@Override
protected Polygon nextPolygon() {
return GeoTestUtil.nextPolygon();
}
@Override
protected Encoder getEncoder() {
return new Encoder() {
@Override
double decodeX(int encoded) {
return decodeLongitude(encoded);
}
@Override
double decodeY(int encoded) {
return decodeLatitude(encoded);
}
@Override
double quantizeX(double raw) {
return decodeLongitude(encodeLongitude(raw));
}
@Override
double quantizeXCeil(double raw) {
return decodeLongitude(encodeLongitudeCeil(raw));
}
@Override
double quantizeY(double raw) {
return decodeLatitude(encodeLatitude(raw));
}
@Override
double quantizeYCeil(double raw) {
return decodeLatitude(encodeLatitudeCeil(raw));
}
};
}
/** internal shape type for testing different shape types */
protected enum ShapeType {
POINT() {
public Point nextShape() {
return GeoTestUtil.nextPoint();
}
},
LINE() {
public Line nextShape() {
return GeoTestUtil.nextLine();
}
},
POLYGON() {
public Polygon nextShape() {
while (true) {
Polygon p = GeoTestUtil.nextPolygon();
try {
Tessellator.tessellate(p);
return p;
} catch (IllegalArgumentException e) {
// if we can't tessellate; then random polygon generator created a malformed shape
}
}
}
},
MIXED() {
public Object nextShape() {
return RandomPicks.randomFrom(random(), subList).nextShape();
}
};
static ShapeType[] subList;
static {
subList = new ShapeType[] {POINT, LINE, POLYGON};
}
public abstract Object nextShape();
}
}