LUCENE-7163: refactor GeoRect, Polygon, and GeoUtils tests to geo package in core.

This commit is contained in:
nknize 2016-04-01 13:12:34 -05:00
parent d0156b1126
commit 6c219e99e4
20 changed files with 275 additions and 206 deletions

View File

@ -14,21 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.spatial.util;
package org.apache.lucene.geo;
import java.util.Arrays;
import org.apache.lucene.geo.GeoUtils;
/**
/**
* Represents a closed polygon on the earth's surface.
* @lucene.experimental
* @lucene.experimental
*/
public final class Polygon {
private final double[] polyLats;
private final double[] polyLons;
private final Polygon[] holes;
/** minimum latitude of this polygon's bounding box area */
public final double minLat;
/** maximum latitude of this polygon's bounding box area */
@ -37,10 +35,13 @@ public final class Polygon {
public final double minLon;
/** maximum longitude of this polygon's bounding box area */
public final double maxLon;
// TODO: refactor to GeoUtils once LUCENE-7165 is complete
private static final double ENCODING_TOLERANCE = 1e-6;
// TODO: we could also compute the maximal inner bounding box, to make relations faster to compute?
/**
/**
* Creates a new Polygon from the supplied latitude/longitude array, and optionally any holes.
*/
public Polygon(double[] polyLats, double[] polyLons, Polygon... holes) {
@ -99,14 +100,14 @@ public final class Polygon {
this.minLon = minLon;
this.maxLon = maxLon;
}
/** Returns true if the point is contained within this polygon */
public boolean contains(double latitude, double longitude) {
// check bounding box
if (latitude < minLat || latitude > maxLat || longitude < minLon || longitude > maxLon) {
return false;
}
/*
/*
* simple even-odd point in polygon computation
* 1. Determine if point is contained in the longitudinal range
* 2. Determine whether point crosses the edge by computing the latitudinal delta
@ -139,7 +140,7 @@ public final class Polygon {
return false;
}
}
/**
* Computes whether a rectangle is within a polygon (shared boundaries not allowed)
*/
@ -149,9 +150,9 @@ public final class Polygon {
boolean contains = crosses(minLat, maxLat, minLon, maxLon) == false &&
contains(minLat, minLon) &&
contains(minLat, maxLon) &&
contains(maxLat, maxLon) &&
contains(maxLat, maxLon) &&
contains(maxLat, minLon);
if (contains) {
// if we intersect with any hole, game over
for (Polygon hole : holes) {
@ -164,7 +165,7 @@ public final class Polygon {
return false;
}
}
/**
* Convenience method for accurately computing whether a rectangle crosses a poly.
*/
@ -207,14 +208,15 @@ public final class Polygon {
c2 = a2*polyLons[p+1] + b2*polyLats[p+1];
s = (1/d)*(b2*c1 - b1*c2);
t = (1/d)*(a1*c2 - a2*c1);
x00 = Math.min(bbox[b][0], bbox[b+1][0]) - GeoEncodingUtils.TOLERANCE;
x01 = Math.max(bbox[b][0], bbox[b+1][0]) + GeoEncodingUtils.TOLERANCE;
y00 = Math.min(bbox[b][1], bbox[b+1][1]) - GeoEncodingUtils.TOLERANCE;
y01 = Math.max(bbox[b][1], bbox[b+1][1]) + GeoEncodingUtils.TOLERANCE;
x10 = Math.min(polyLons[p], polyLons[p+1]) - GeoEncodingUtils.TOLERANCE;
x11 = Math.max(polyLons[p], polyLons[p+1]) + GeoEncodingUtils.TOLERANCE;
y10 = Math.min(polyLats[p], polyLats[p+1]) - GeoEncodingUtils.TOLERANCE;
y11 = Math.max(polyLats[p], polyLats[p+1]) + GeoEncodingUtils.TOLERANCE;
// todo TOLERANCE SHOULD MATCH EVERYWHERE this is currently blocked by LUCENE-7165
x00 = Math.min(bbox[b][0], bbox[b+1][0]) - ENCODING_TOLERANCE;
x01 = Math.max(bbox[b][0], bbox[b+1][0]) + ENCODING_TOLERANCE;
y00 = Math.min(bbox[b][1], bbox[b+1][1]) - ENCODING_TOLERANCE;
y01 = Math.max(bbox[b][1], bbox[b+1][1]) + ENCODING_TOLERANCE;
x10 = Math.min(polyLons[p], polyLons[p+1]) - ENCODING_TOLERANCE;
x11 = Math.max(polyLons[p], polyLons[p+1]) + ENCODING_TOLERANCE;
y10 = Math.min(polyLats[p], polyLats[p+1]) - ENCODING_TOLERANCE;
y11 = Math.max(polyLats[p], polyLats[p+1]) + ENCODING_TOLERANCE;
// check whether the intersection point is touching one of the line segments
boolean touching = ((x00 == s && y00 == t) || (x01 == s && y01 == t))
|| ((x10 == s && y10 == t) || (x11 == s && y11 == t));
@ -227,22 +229,22 @@ public final class Polygon {
} // for each bbox edge
return false;
}
/** Returns a copy of the internal latitude array */
public double[] getPolyLats() {
return polyLats.clone();
}
/** Returns a copy of the internal longitude array */
public double[] getPolyLons() {
return polyLons.clone();
}
/** Returns a copy of the internal holes array */
public Polygon[] getHoles() {
return holes.clone();
}
/** Helper for multipolygon logic: returns true if any of the supplied polygons contain the point */
public static boolean contains(Polygon[] polygons, double latitude, double longitude) {
for (Polygon polygon : polygons) {
@ -252,7 +254,7 @@ public final class Polygon {
}
return false;
}
/** Helper for multipolygon logic: returns true if any of the supplied polygons contain the rectangle */
public static boolean contains(Polygon[] polygons, double minLat, double maxLat, double minLon, double maxLon) {
for (Polygon polygon : polygons) {
@ -262,7 +264,7 @@ public final class Polygon {
}
return false;
}
/** Helper for multipolygon logic: returns true if any of the supplied polygons crosses the rectangle */
public static boolean crosses(Polygon[] polygons, double minLat, double maxLat, double minLon, double maxLon) {
for (Polygon polygon : polygons) {
@ -272,7 +274,7 @@ public final class Polygon {
}
return false;
}
@Override
public int hashCode() {
final int prime = 31;

View File

@ -14,9 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.spatial.util;
import org.apache.lucene.geo.GeoUtils;
package org.apache.lucene.geo;
import static java.lang.Math.PI;
import static java.lang.Math.max;
@ -38,7 +36,7 @@ import static org.apache.lucene.util.SloppyMath.asin;
import static org.apache.lucene.util.SloppyMath.cos;
/** Represents a lat/lon rectangle. */
public class GeoRect {
public class Rectangle {
/** maximum longitude value (in degrees) */
public final double minLat;
/** minimum longitude value (in degrees) */
@ -51,7 +49,7 @@ public class GeoRect {
/**
* Constructs a bounding box by first validating the provided latitude and longitude coordinates
*/
public GeoRect(double minLat, double maxLat, double minLon, double maxLon) {
public Rectangle(double minLat, double maxLat, double minLon, double maxLon) {
GeoUtils.checkLatitude(minLat);
GeoUtils.checkLatitude(maxLat);
GeoUtils.checkLongitude(minLon);
@ -90,7 +88,7 @@ public class GeoRect {
}
/** Compute Bounding Box for a circle using WGS-84 parameters */
public static GeoRect fromPointDistance(final double centerLat, final double centerLon, final double radiusMeters) {
public static Rectangle fromPointDistance(final double centerLat, final double centerLon, final double radiusMeters) {
checkLatitude(centerLat);
checkLongitude(centerLon);
final double radLat = toRadians(centerLat);
@ -120,7 +118,7 @@ public class GeoRect {
maxLon = MAX_LON_RADIANS;
}
return new GeoRect(toDegrees(minLat), toDegrees(maxLat), toDegrees(minLon), toDegrees(maxLon));
return new Rectangle(toDegrees(minLat), toDegrees(maxLat), toDegrees(minLon), toDegrees(maxLon));
}
/** maximum error from {@link #axisLat(double, double)}. logic must be prepared to handle this */
@ -172,7 +170,7 @@ public class GeoRect {
}
/** Returns the bounding box over an array of polygons */
public static GeoRect fromPolygon(Polygon[] polygons) {
public static Rectangle fromPolygon(Polygon[] polygons) {
// compute bounding box
double minLat = Double.POSITIVE_INFINITY;
double maxLat = Double.NEGATIVE_INFINITY;
@ -186,6 +184,6 @@ public class GeoRect {
maxLon = Math.max(polygons[i].maxLon, maxLon);
}
return new GeoRect(minLat, maxLat, minLon, maxLon);
return new Rectangle(minLat, maxLat, minLon, maxLon);
}
}

View File

@ -14,12 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.spatial.util;
package org.apache.lucene.geo;
import java.util.Locale;
import org.apache.lucene.geo.GeoUtils;
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.SloppyMath;
import org.junit.BeforeClass;
@ -61,65 +59,6 @@ public class TestGeoUtils extends LuceneTestCase {
return result;
}
/**
* Tests stability of {@link GeoEncodingUtils#geoCodedToPrefixCoded}
*/
public void testGeoPrefixCoding() throws Exception {
int numIters = atLeast(1000);
long hash;
long decodedHash;
BytesRefBuilder brb = new BytesRefBuilder();
while (numIters-- >= 0) {
hash = GeoEncodingUtils.mortonHash(randomLat(false), randomLon(false));
for (int i=32; i<64; ++i) {
GeoEncodingUtils.geoCodedToPrefixCoded(hash, i, brb);
decodedHash = GeoEncodingUtils.prefixCodedToGeoCoded(brb.get());
assertEquals((hash >>> i) << i, decodedHash);
}
}
}
public void testMortonEncoding() throws Exception {
long hash = GeoEncodingUtils.mortonHash(90, 180);
assertEquals(180.0, GeoEncodingUtils.mortonUnhashLon(hash), 0);
assertEquals(90.0, GeoEncodingUtils.mortonUnhashLat(hash), 0);
}
public void testEncodeDecode() throws Exception {
int iters = atLeast(10000);
boolean small = random().nextBoolean();
for(int iter=0;iter<iters;iter++) {
double lat = randomLat(small);
double lon = randomLon(small);
long enc = GeoEncodingUtils.mortonHash(lat, lon);
double latEnc = GeoEncodingUtils.mortonUnhashLat(enc);
double lonEnc = GeoEncodingUtils.mortonUnhashLon(enc);
assertEquals("lat=" + lat + " latEnc=" + latEnc + " diff=" + (lat - latEnc), lat, latEnc, GeoEncodingUtils.TOLERANCE);
assertEquals("lon=" + lon + " lonEnc=" + lonEnc + " diff=" + (lon - lonEnc), lon, lonEnc, GeoEncodingUtils.TOLERANCE);
}
}
public void testScaleUnscaleIsStable() throws Exception {
int iters = atLeast(1000);
boolean small = random().nextBoolean();
for(int iter=0;iter<iters;iter++) {
double lat = randomLat(small);
double lon = randomLon(small);
long enc = GeoEncodingUtils.mortonHash(lat, lon);
double latEnc = GeoEncodingUtils.mortonUnhashLat(enc);
double lonEnc = GeoEncodingUtils.mortonUnhashLon(enc);
long enc2 = GeoEncodingUtils.mortonHash(lat, lon);
double latEnc2 = GeoEncodingUtils.mortonUnhashLat(enc2);
double lonEnc2 = GeoEncodingUtils.mortonUnhashLon(enc2);
assertEquals(latEnc, latEnc2, 0.0);
assertEquals(lonEnc, lonEnc2, 0.0);
}
}
// We rely heavily on GeoUtils.circleToBBox so we test it here:
public void testRandomCircleToBBox() throws Exception {
int iters = atLeast(1000);
@ -141,7 +80,7 @@ public class TestGeoUtils extends LuceneTestCase {
// TODO: randomly quantize radius too, to provoke exact math errors?
GeoRect bbox = GeoRect.fromPointDistance(centerLat, centerLon, radiusMeters);
Rectangle bbox = Rectangle.fromPointDistance(centerLat, centerLon, radiusMeters);
int numPointsToTry = 1000;
for(int i=0;i<numPointsToTry;i++) {
@ -197,24 +136,24 @@ public class TestGeoUtils extends LuceneTestCase {
}
}
}
// similar to testRandomCircleToBBox, but different, less evil, maybe simpler
public void testBoundingBoxOpto() {
for (int i = 0; i < 1000; i++) {
double lat = GeoTestUtil.nextLatitude();
double lon = GeoTestUtil.nextLongitude();
double radius = 50000000 * random().nextDouble();
GeoRect box = GeoRect.fromPointDistance(lat, lon, radius);
final GeoRect box1;
final GeoRect box2;
Rectangle box = Rectangle.fromPointDistance(lat, lon, radius);
final Rectangle box1;
final Rectangle box2;
if (box.crossesDateline()) {
box1 = new GeoRect(box.minLat, box.maxLat, -180, box.maxLon);
box2 = new GeoRect(box.minLat, box.maxLat, box.minLon, 180);
box1 = new Rectangle(box.minLat, box.maxLat, -180, box.maxLon);
box2 = new Rectangle(box.minLat, box.maxLat, box.minLon, 180);
} else {
box1 = box;
box2 = null;
}
for (int j = 0; j < 10000; j++) {
double lat2 = GeoTestUtil.nextLatitude();
double lon2 = GeoTestUtil.nextLongitude();
@ -233,12 +172,12 @@ public class TestGeoUtils extends LuceneTestCase {
double lat = GeoTestUtil.nextLatitude();
double lon = GeoTestUtil.nextLongitude();
double radius = 50000000 * random().nextDouble();
GeoRect box = GeoRect.fromPointDistance(lat, lon, radius);
Rectangle box = Rectangle.fromPointDistance(lat, lon, radius);
if (box.maxLon - lon < 90 && lon - box.minLon < 90) {
double minPartialDistance = Math.max(SloppyMath.haversinSortKey(lat, lon, lat, box.maxLon),
SloppyMath.haversinSortKey(lat, lon, box.maxLat, lon));
for (int j = 0; j < 10000; j++) {
double lat2 = GeoTestUtil.nextLatitude();
double lon2 = GeoTestUtil.nextLongitude();
@ -256,7 +195,7 @@ public class TestGeoUtils extends LuceneTestCase {
for (int i = 0; i < 1000; i++) {
double centerLat = GeoTestUtil.nextLatitude();
double centerLon = GeoTestUtil.nextLongitude();
GeoRect rect = GeoRect.fromPointDistance(centerLat, centerLon, Double.POSITIVE_INFINITY);
Rectangle rect = Rectangle.fromPointDistance(centerLat, centerLon, Double.POSITIVE_INFINITY);
assertEquals(-180.0, rect.minLon, 0.0D);
assertEquals(180.0, rect.maxLon, 0.0D);
assertEquals(-90.0, rect.minLat, 0.0D);
@ -264,19 +203,19 @@ public class TestGeoUtils extends LuceneTestCase {
assertFalse(rect.crossesDateline());
}
}
public void testAxisLat() {
double earthCircumference = 2D * Math.PI * GeoUtils.EARTH_MEAN_RADIUS_METERS;
assertEquals(90, GeoRect.axisLat(0, earthCircumference / 4), 0.0D);
assertEquals(90, Rectangle.axisLat(0, earthCircumference / 4), 0.0D);
for (int i = 0; i < 100; ++i) {
boolean reallyBig = random().nextInt(10) == 0;
final double maxRadius = reallyBig ? 1.1 * earthCircumference : earthCircumference / 8;
final double radius = maxRadius * random().nextDouble();
double prevAxisLat = GeoRect.axisLat(0.0D, radius);
double prevAxisLat = Rectangle.axisLat(0.0D, radius);
for (double lat = 0.1D; lat < 90D; lat += 0.1D) {
double nextAxisLat = GeoRect.axisLat(lat, radius);
GeoRect bbox = GeoRect.fromPointDistance(lat, 180D, radius);
double nextAxisLat = Rectangle.axisLat(lat, radius);
Rectangle bbox = Rectangle.fromPointDistance(lat, 180D, radius);
double dist = SloppyMath.haversinMeters(lat, 180D, nextAxisLat, bbox.maxLon);
if (nextAxisLat < GeoUtils.MAX_LAT_INCL) {
assertEquals("lat = " + lat, dist, radius, 0.1D);
@ -285,10 +224,10 @@ public class TestGeoUtils extends LuceneTestCase {
prevAxisLat = nextAxisLat;
}
prevAxisLat = GeoRect.axisLat(-0.0D, radius);
prevAxisLat = Rectangle.axisLat(-0.0D, radius);
for (double lat = -0.1D; lat > -90D; lat -= 0.1D) {
double nextAxisLat = GeoRect.axisLat(lat, radius);
GeoRect bbox = GeoRect.fromPointDistance(lat, 180D, radius);
double nextAxisLat = Rectangle.axisLat(lat, radius);
Rectangle bbox = Rectangle.fromPointDistance(lat, 180D, radius);
double dist = SloppyMath.haversinMeters(lat, 180D, nextAxisLat, bbox.maxLon);
if (nextAxisLat > GeoUtils.MIN_LAT_INCL) {
assertEquals("lat = " + lat, dist, radius, 0.1D);
@ -298,7 +237,7 @@ public class TestGeoUtils extends LuceneTestCase {
}
}
}
// TODO: does not really belong here, but we test it like this for now
// we can make a fake IndexReader to send boxes directly to Point visitors instead?
public void testCircleOpto() throws Exception {
@ -307,13 +246,13 @@ public class TestGeoUtils extends LuceneTestCase {
final double centerLat = -90 + 180.0 * random().nextDouble();
final double centerLon = -180 + 360.0 * random().nextDouble();
final double radius = 50_000_000D * random().nextDouble();
final GeoRect box = GeoRect.fromPointDistance(centerLat, centerLon, radius);
final Rectangle box = Rectangle.fromPointDistance(centerLat, centerLon, radius);
// TODO: remove this leniency!
if (box.crossesDateline()) {
--i; // try again...
continue;
}
final double axisLat = GeoRect.axisLat(centerLat, radius);
final double axisLat = Rectangle.axisLat(centerLat, radius);
for (int k = 0; k < 1000; ++k) {
@ -366,7 +305,7 @@ public class TestGeoUtils extends LuceneTestCase {
"lonMax=%s) == false BUT\n" +
"haversin(%s, %s, %s, %s) = %s\nbbox=%s",
centerLat, centerLon, radius, latMin, latMax, lonMin, lonMax,
centerLat, centerLon, lat, lon, distance, GeoRect.fromPointDistance(centerLat, centerLon, radius)),
centerLat, centerLon, lat, lon, distance, Rectangle.fromPointDistance(centerLat, centerLon, radius)),
distance > radius);
} catch (AssertionError e) {
GeoTestUtil.toWebGLEarth(latMin, latMax, lonMin, lonMax, centerLat, centerLon, radius);
@ -381,9 +320,9 @@ public class TestGeoUtils extends LuceneTestCase {
static double randomInRange(double min, double max) {
return min + (max - min) * random().nextDouble();
}
static boolean isDisjoint(double centerLat, double centerLon, double radius, double axisLat, double latMin, double latMax, double lonMin, double lonMax) {
if ((centerLon < lonMin || centerLon > lonMax) && (axisLat+GeoRect.AXISLAT_ERROR < latMin || axisLat-GeoRect.AXISLAT_ERROR > latMax)) {
if ((centerLon < lonMin || centerLon > lonMax) && (axisLat+ Rectangle.AXISLAT_ERROR < latMin || axisLat- Rectangle.AXISLAT_ERROR > latMax)) {
// circle not fully inside / crossing axis
if (SloppyMath.haversinMeters(centerLat, centerLon, latMin, lonMin) > radius &&
SloppyMath.haversinMeters(centerLat, centerLon, latMin, lonMax) > radius &&
@ -393,7 +332,7 @@ public class TestGeoUtils extends LuceneTestCase {
return true;
}
}
return false;
}
}

View File

@ -29,7 +29,7 @@ import org.apache.lucene.search.FieldDoc;
import org.apache.lucene.search.PointRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.spatial.util.Polygon;
import org.apache.lucene.geo.Polygon;
/**
* An indexed location field.

View File

@ -26,8 +26,7 @@ import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.LeafFieldComparator;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.spatial.util.GeoRect;
import org.apache.lucene.geo.GeoUtils;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.util.SloppyMath;
/**
@ -83,7 +82,7 @@ class LatLonPointDistanceComparator extends FieldComparator<Double> implements L
// sampling if we get called way too much: don't make gobs of bounding
// boxes if comparator hits a worst case order (e.g. backwards distance order)
if (setBottomCounter < 1024 || (setBottomCounter & 0x3F) == 0x3F) {
GeoRect box = GeoRect.fromPointDistance(latitude, longitude, haversin2(bottom));
Rectangle box = Rectangle.fromPointDistance(latitude, longitude, haversin2(bottom));
// pre-encode our box to our integer encoding, so we don't have to decode
// to double values for uncompetitive hits. This has some cost!
minLat = LatLonPoint.encodeLatitude(box.minLat);

View File

@ -18,6 +18,7 @@ package org.apache.lucene.document;
import java.io.IOException;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.LeafReader;
@ -35,7 +36,6 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.TwoPhaseIterator;
import org.apache.lucene.search.Weight;
import org.apache.lucene.spatial.util.GeoRect;
import org.apache.lucene.geo.GeoUtils;
import org.apache.lucene.util.BitSet;
import org.apache.lucene.util.DocIdSetBuilder;
@ -71,7 +71,7 @@ final class LatLonPointDistanceQuery extends Query {
@Override
public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
GeoRect box = GeoRect.fromPointDistance(latitude, longitude, radiusMeters);
Rectangle box = Rectangle.fromPointDistance(latitude, longitude, radiusMeters);
// create bounding box(es) for the distance range
// these are pre-encoded with LatLonPoint's encoding
final byte minLat[] = new byte[Integer.BYTES];
@ -108,7 +108,7 @@ final class LatLonPointDistanceQuery extends Query {
maxPartialDistance = Double.POSITIVE_INFINITY;
}
final double axisLat = GeoRect.axisLat(latitude, radiusMeters);
final double axisLat = Rectangle.axisLat(latitude, radiusMeters);
return new ConstantScoreWeight(this) {
@ -196,7 +196,7 @@ final class LatLonPointDistanceQuery extends Query {
double latMax = LatLonPoint.decodeLatitude(maxPackedValue, 0);
double lonMax = LatLonPoint.decodeLongitude(maxPackedValue, Integer.BYTES);
if ((longitude < lonMin || longitude > lonMax) && (axisLat+GeoRect.AXISLAT_ERROR < latMin || axisLat-GeoRect.AXISLAT_ERROR > latMax)) {
if ((longitude < lonMin || longitude > lonMax) && (axisLat+ Rectangle.AXISLAT_ERROR < latMin || axisLat- Rectangle.AXISLAT_ERROR > latMax)) {
// circle not fully inside / crossing axis
if (SloppyMath.haversinMeters(latitude, longitude, latMin, lonMin) > radiusMeters &&
SloppyMath.haversinMeters(latitude, longitude, latMin, lonMax) > radiusMeters &&

View File

@ -19,6 +19,7 @@ package org.apache.lucene.document;
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.index.PointValues.IntersectVisitor;
import org.apache.lucene.index.PointValues.Relation;
import org.apache.lucene.search.ConstantScoreScorer;
@ -42,8 +43,7 @@ import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.SparseFixedBitSet;
import org.apache.lucene.util.StringHelper;
import org.apache.lucene.spatial.util.GeoRect;
import org.apache.lucene.spatial.util.Polygon;
import org.apache.lucene.geo.Polygon;
/** Finds all previously indexed points that fall within the specified polygons.
*
@ -84,7 +84,7 @@ final class LatLonPointInPolygonQuery extends Query {
// bounding box over all polygons, this can speed up tree intersection/cheaply improve approximation for complex multi-polygons
// these are pre-encoded with LatLonPoint's encoding
final GeoRect box = GeoRect.fromPolygon(polygons);
final Rectangle box = Rectangle.fromPolygon(polygons);
final byte minLat[] = new byte[Integer.BYTES];
final byte maxLat[] = new byte[Integer.BYTES];
final byte minLon[] = new byte[Integer.BYTES];

View File

@ -19,6 +19,7 @@ package org.apache.lucene.document;
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.geo.GeoTestUtil;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.RandomIndexWriter;
@ -29,7 +30,6 @@ import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.spatial.util.GeoTestUtil;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.SloppyMath;

View File

@ -19,7 +19,7 @@ package org.apache.lucene.search;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.LatLonPoint;
import org.apache.lucene.spatial.util.BaseGeoPointTestCase;
import org.apache.lucene.spatial.util.Polygon;
import org.apache.lucene.geo.Polygon;
public class TestLatLonPointQueries extends BaseGeoPointTestCase {

View File

@ -21,7 +21,7 @@ import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.spatial.geopoint.document.GeoPointField.TermEncoding;
import org.apache.lucene.spatial.util.GeoRect;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.geo.GeoUtils;
/** Implements a simple point distance query on a GeoPoint field. This is based on
@ -80,10 +80,10 @@ public class GeoPointDistanceQuery extends GeoPointInBBoxQuery {
* {@link org.apache.lucene.spatial.geopoint.document.GeoPointField.TermEncoding} parameter
**/
public GeoPointDistanceQuery(final String field, final TermEncoding termEncoding, final double centerLat, final double centerLon, final double radiusMeters) {
this(field, termEncoding, GeoRect.fromPointDistance(centerLat, centerLon, checkRadius(radiusMeters)), centerLat, centerLon, radiusMeters);
this(field, termEncoding, Rectangle.fromPointDistance(centerLat, centerLon, checkRadius(radiusMeters)), centerLat, centerLon, radiusMeters);
}
private GeoPointDistanceQuery(final String field, final TermEncoding termEncoding, final GeoRect bbox,
private GeoPointDistanceQuery(final String field, final TermEncoding termEncoding, final Rectangle bbox,
final double centerLat, final double centerLon, final double radiusMeters) {
super(field, termEncoding, bbox.minLat, bbox.maxLat, bbox.minLon, bbox.maxLon);
@ -105,7 +105,7 @@ public class GeoPointDistanceQuery extends GeoPointInBBoxQuery {
unwrappedLon += -360.0D;
}
GeoPointDistanceQueryImpl left = new GeoPointDistanceQueryImpl(field, termEncoding, this, unwrappedLon,
new GeoRect(minLat, maxLat, GeoUtils.MIN_LON_INCL, maxLon));
new Rectangle(minLat, maxLat, GeoUtils.MIN_LON_INCL, maxLon));
bqb.add(new BooleanClause(left, BooleanClause.Occur.SHOULD));
if (unwrappedLon < maxLon) {
@ -113,13 +113,13 @@ public class GeoPointDistanceQuery extends GeoPointInBBoxQuery {
unwrappedLon += 360.0D;
}
GeoPointDistanceQueryImpl right = new GeoPointDistanceQueryImpl(field, termEncoding, this, unwrappedLon,
new GeoRect(minLat, maxLat, minLon, GeoUtils.MAX_LON_INCL));
new Rectangle(minLat, maxLat, minLon, GeoUtils.MAX_LON_INCL));
bqb.add(new BooleanClause(right, BooleanClause.Occur.SHOULD));
return bqb.build();
}
return new GeoPointDistanceQueryImpl(field, termEncoding, this, centerLon,
new GeoRect(this.minLat, this.maxLat, this.minLon, this.maxLon));
new Rectangle(this.minLat, this.maxLat, this.minLon, this.maxLon));
}
@Override

View File

@ -16,9 +16,9 @@
*/
package org.apache.lucene.spatial.geopoint.search;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.spatial.geopoint.document.GeoPointField.TermEncoding;
import org.apache.lucene.spatial.util.GeoRect;
import org.apache.lucene.util.SloppyMath;
/** Package private implementation for the public facing GeoPointDistanceQuery delegate class.
@ -36,7 +36,7 @@ final class GeoPointDistanceQueryImpl extends GeoPointInBBoxQueryImpl {
final double axisLat;
GeoPointDistanceQueryImpl(final String field, final TermEncoding termEncoding, final GeoPointDistanceQuery q,
final double centerLonUnwrapped, final GeoRect bbox) {
final double centerLonUnwrapped, final Rectangle bbox) {
super(field, termEncoding, bbox.minLat, bbox.maxLat, bbox.minLon, bbox.maxLon);
distanceQuery = q;
centerLon = centerLonUnwrapped;
@ -49,7 +49,7 @@ final class GeoPointDistanceQueryImpl extends GeoPointInBBoxQueryImpl {
} else {
maxPartialDistance = Double.POSITIVE_INFINITY;
}
axisLat = GeoRect.axisLat(distanceQuery.centerLat, distanceQuery.radiusMeters);
axisLat = Rectangle.axisLat(distanceQuery.centerLat, distanceQuery.radiusMeters);
}
@Override
@ -75,7 +75,7 @@ final class GeoPointDistanceQueryImpl extends GeoPointInBBoxQueryImpl {
minLat > GeoPointDistanceQueryImpl.this.maxLat ||
minLon > GeoPointDistanceQueryImpl.this.maxLon) {
return false;
} else if ((centerLon < minLon || centerLon > maxLon) && (axisLat+GeoRect.AXISLAT_ERROR < minLat || axisLat-GeoRect.AXISLAT_ERROR > maxLat)) {
} else if ((centerLon < minLon || centerLon > maxLon) && (axisLat+ Rectangle.AXISLAT_ERROR < minLat || axisLat- Rectangle.AXISLAT_ERROR > maxLat)) {
if (SloppyMath.haversinMeters(distanceQuery.centerLat, centerLon, minLat, minLon) > distanceQuery.radiusMeters &&
SloppyMath.haversinMeters(distanceQuery.centerLat, centerLon, minLat, maxLon) > distanceQuery.radiusMeters &&
SloppyMath.haversinMeters(distanceQuery.centerLat, centerLon, maxLat, minLon) > distanceQuery.radiusMeters &&

View File

@ -23,8 +23,8 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.spatial.geopoint.document.GeoPointField;
import org.apache.lucene.spatial.geopoint.document.GeoPointField.TermEncoding;
import org.apache.lucene.spatial.util.GeoEncodingUtils;
import org.apache.lucene.spatial.util.GeoRect;
import org.apache.lucene.spatial.util.Polygon;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.geo.Polygon;
/** Implements a simple point in polygon query on a GeoPoint field. This is based on
* {@code GeoPointInBBoxQueryImpl} and is implemented using a
@ -82,11 +82,11 @@ public final class GeoPointInPolygonQuery extends GeoPointInBBoxQuery {
* that fall within or on the boundary of the polygon defined by the input parameters.
*/
public GeoPointInPolygonQuery(String field, TermEncoding termEncoding, Polygon... polygons) {
this(field, termEncoding, GeoRect.fromPolygon(polygons), polygons);
this(field, termEncoding, Rectangle.fromPolygon(polygons), polygons);
}
// internal constructor
private GeoPointInPolygonQuery(String field, TermEncoding termEncoding, GeoRect boundingBox, Polygon... polygons) {
private GeoPointInPolygonQuery(String field, TermEncoding termEncoding, Rectangle boundingBox, Polygon... polygons) {
super(field, termEncoding, boundingBox.minLat, boundingBox.maxLat, boundingBox.minLon, boundingBox.maxLon);
this.polygons = polygons.clone();
}

View File

@ -20,7 +20,7 @@ import java.util.Objects;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.spatial.geopoint.document.GeoPointField.TermEncoding;
import org.apache.lucene.spatial.util.Polygon;
import org.apache.lucene.geo.Polygon;
/** Package private implementation for the public facing GeoPointInPolygonQuery delegate class.
*

View File

@ -19,7 +19,7 @@ package org.apache.lucene.spatial.geopoint.search;
import org.apache.lucene.document.Document;
import org.apache.lucene.search.Query;
import org.apache.lucene.spatial.util.GeoEncodingUtils;
import org.apache.lucene.spatial.util.Polygon;
import org.apache.lucene.geo.Polygon;
import org.apache.lucene.spatial.geopoint.document.GeoPointField;
import org.apache.lucene.spatial.geopoint.document.GeoPointField.TermEncoding;
import org.apache.lucene.spatial.util.BaseGeoPointTestCase;

View File

@ -19,7 +19,7 @@ package org.apache.lucene.spatial.geopoint.search;
import org.apache.lucene.document.Document;
import org.apache.lucene.search.Query;
import org.apache.lucene.spatial.util.GeoEncodingUtils;
import org.apache.lucene.spatial.util.Polygon;
import org.apache.lucene.geo.Polygon;
import org.apache.lucene.spatial.geopoint.document.GeoPointField;
import org.apache.lucene.spatial.geopoint.document.GeoPointField.TermEncoding;
import org.apache.lucene.spatial.util.BaseGeoPointTestCase;

View File

@ -37,7 +37,10 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.geo.GeoTestUtil;
import org.apache.lucene.geo.GeoUtils;
import org.apache.lucene.geo.Polygon;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
@ -537,7 +540,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
int iters = atLeast(25);
for (int iter=0;iter<iters;iter++) {
GeoRect rect = randomRect(small);
Rectangle rect = randomRect(small);
if (VERBOSE) {
System.out.println("\nTEST: iter=" + iter + " rect=" + rect);
@ -716,7 +719,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
return lon;
}
protected GeoRect randomRect(boolean small) {
protected Rectangle randomRect(boolean small) {
if (small) {
return GeoTestUtil.nextBoxNear(originLat, originLon);
} else {
@ -732,7 +735,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
protected abstract Query newPolygonQuery(String field, Polygon... polygon);
static final boolean rectContainsPoint(GeoRect rect, double pointLat, double pointLon) {
static final boolean rectContainsPoint(Rectangle rect, double pointLat, double pointLon) {
assert Double.isNaN(pointLat) == false;
if (rect.minLon < rect.maxLon) {
@ -820,7 +823,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
System.out.println("\nTEST: iter=" + iter + " s=" + s);
}
GeoRect rect = randomRect(small);
Rectangle rect = randomRect(small);
Query query = newRectQuery(FIELD_NAME, rect.minLat, rect.maxLat, rect.minLon, rect.maxLon);
@ -1173,7 +1176,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
}
public void testRectBoundariesAreInclusive() throws Exception {
GeoRect rect;
Rectangle rect;
// TODO: why this dateline leniency???
while (true) {
rect = randomRect(random().nextBoolean());
@ -1182,7 +1185,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
}
}
// this test works in quantized space: for testing inclusiveness of exact edges it must be aware of index-time quantization!
rect = new GeoRect(quantizeLat(rect.minLat), quantizeLat(rect.maxLat), quantizeLon(rect.minLon), quantizeLon(rect.maxLon));
rect = new Rectangle(quantizeLat(rect.minLat), quantizeLat(rect.maxLat), quantizeLon(rect.minLon), quantizeLon(rect.maxLon));
Directory dir = newDirectory();
IndexWriterConfig iwc = newIndexWriterConfig();
// Else seeds may not reproduce:
@ -1341,7 +1344,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
public void testEquals() throws Exception {
Query q1, q2;
GeoRect rect = randomRect(false);
Rectangle rect = randomRect(false);
q1 = newRectQuery("field", rect.minLat, rect.maxLat, rect.minLon, rect.maxLon);
q2 = newRectQuery("field", rect.minLat, rect.maxLat, rect.minLon, rect.maxLon);

View File

@ -0,0 +1,101 @@
package org.apache.lucene.spatial.util;
/*
* 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.
*/
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.LuceneTestCase;
import static org.apache.lucene.geo.GeoTestUtil.nextLatitude;
import static org.apache.lucene.geo.GeoTestUtil.nextLongitude;
/**
* Tests methods in {@link GeoEncodingUtils}
*/
public class TestGeoEncodingUtils extends LuceneTestCase {
/**
* Tests stability of {@link GeoEncodingUtils#geoCodedToPrefixCoded}
*/
public void testGeoPrefixCoding() throws Exception {
int numIters = atLeast(1000);
long hash;
long decodedHash;
BytesRefBuilder brb = new BytesRefBuilder();
while (numIters-- >= 0) {
hash = GeoEncodingUtils.mortonHash(nextLatitude(), nextLongitude());
for (int i=32; i<64; ++i) {
GeoEncodingUtils.geoCodedToPrefixCoded(hash, i, brb);
decodedHash = GeoEncodingUtils.prefixCodedToGeoCoded(brb.get());
assertEquals((hash >>> i) << i, decodedHash);
}
}
}
public void testMortonEncoding() throws Exception {
long hash = GeoEncodingUtils.mortonHash(90, 180);
assertEquals(180.0, GeoEncodingUtils.mortonUnhashLon(hash), 0);
assertEquals(90.0, GeoEncodingUtils.mortonUnhashLat(hash), 0);
}
public void testEncodeDecode() throws Exception {
int iters = atLeast(10000);
for(int iter=0;iter<iters;iter++) {
double lat = nextLatitude();
double lon = nextLongitude();
long enc = GeoEncodingUtils.mortonHash(lat, lon);
double latEnc = GeoEncodingUtils.mortonUnhashLat(enc);
double lonEnc = GeoEncodingUtils.mortonUnhashLon(enc);
assertEquals("lat=" + lat + " latEnc=" + latEnc + " diff=" + (lat - latEnc), lat, latEnc, GeoEncodingUtils.TOLERANCE);
assertEquals("lon=" + lon + " lonEnc=" + lonEnc + " diff=" + (lon - lonEnc), lon, lonEnc, GeoEncodingUtils.TOLERANCE);
}
}
/** make sure values always go down: this is important for edge case consistency */
public void testEncodeDecodeRoundsDown() throws Exception {
int iters = atLeast(1000);
for(int iter=0;iter<iters;iter++) {
double lat = -90 + 180.0 * random().nextDouble();
double lon = -180 + 360.0 * random().nextDouble();
long enc = GeoEncodingUtils.mortonHash(lat, lon);
double latEnc = GeoEncodingUtils.mortonUnhashLat(enc);
double lonEnc = GeoEncodingUtils.mortonUnhashLon(enc);
assertTrue(latEnc <= lat);
assertTrue(lonEnc <= lon);
}
}
public void testScaleUnscaleIsStable() throws Exception {
int iters = atLeast(1000);
for(int iter=0;iter<iters;iter++) {
double lat = nextLatitude();
double lon = nextLongitude();
long enc = GeoEncodingUtils.mortonHash(lat, lon);
double latEnc = GeoEncodingUtils.mortonUnhashLat(enc);
double lonEnc = GeoEncodingUtils.mortonUnhashLon(enc);
long enc2 = GeoEncodingUtils.mortonHash(lat, lon);
double latEnc2 = GeoEncodingUtils.mortonUnhashLat(enc2);
double lonEnc2 = GeoEncodingUtils.mortonUnhashLon(enc2);
assertEquals(latEnc, latEnc2, 0.0);
assertEquals(lonEnc, lonEnc2, 0.0);
}
}
}

View File

@ -16,8 +16,15 @@
*/
package org.apache.lucene.spatial.util;
import org.apache.lucene.geo.Polygon;
import org.apache.lucene.util.LuceneTestCase;
import static org.apache.lucene.geo.GeoTestUtil.nextLatitude;
import static org.apache.lucene.geo.GeoTestUtil.nextLatitudeAround;
import static org.apache.lucene.geo.GeoTestUtil.nextLongitude;
import static org.apache.lucene.geo.GeoTestUtil.nextLongitudeAround;
import static org.apache.lucene.geo.GeoTestUtil.nextPolygon;
public class TestPolygon extends LuceneTestCase {
/** null polyLats not allowed */
@ -109,11 +116,11 @@ public class TestPolygon extends LuceneTestCase {
public void testBoundingBox() throws Exception {
for (int i = 0; i < 100; i++) {
Polygon polygon = GeoTestUtil.nextPolygon();
Polygon polygon = nextPolygon();
for (int j = 0; j < 100; j++) {
double latitude = GeoTestUtil.nextLatitude();
double longitude = GeoTestUtil.nextLongitude();
double latitude = nextLatitude();
double longitude = nextLongitude();
// if the point is within poly, then it should be in our bounding box
if (polygon.contains(latitude, longitude)) {
assertTrue(latitude >= polygon.minLat && latitude <= polygon.maxLat);
@ -125,11 +132,11 @@ public class TestPolygon extends LuceneTestCase {
public void testBoundingBoxEdgeCases() throws Exception {
for (int i = 0; i < 100; i++) {
Polygon polygon = GeoTestUtil.nextPolygon();
Polygon polygon = nextPolygon();
for (int j = 0; j < 100; j++) {
double latitude = GeoTestUtil.nextLatitudeAround(polygon.minLat, polygon.maxLat);
double longitude = GeoTestUtil.nextLongitudeAround(polygon.minLon, polygon.maxLon);
double latitude = nextLatitudeAround(polygon.minLat, polygon.maxLat);
double longitude = nextLongitudeAround(polygon.minLon, polygon.maxLon);
// if the point is within poly, then it should be in our bounding box
if (polygon.contains(latitude, longitude)) {
assertTrue(latitude >= polygon.minLat && latitude <= polygon.maxLat);

View File

@ -14,13 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.spatial.util;
package org.apache.lucene.geo;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.lucene.geo.GeoUtils;
import org.apache.lucene.util.SloppyMath;
import com.carrotsearch.randomizedtesting.RandomizedContext;
@ -32,25 +31,25 @@ public class GeoTestUtil {
public static double nextLatitude() {
return -90 + 180.0 * random().nextDouble();
}
/** returns next pseudorandom longitude (anywhere) */
public static double nextLongitude() {
return -180 + 360.0 * random().nextDouble();
}
/** returns next pseudorandom latitude, kinda close to {@code otherLatitude} */
public static double nextLatitudeNear(double otherLatitude) {
GeoUtils.checkLatitude(otherLatitude);
return normalizeLatitude(otherLatitude + random().nextDouble() - 0.5);
}
/** returns next pseudorandom longitude, kinda close to {@code otherLongitude} */
public static double nextLongitudeNear(double otherLongitude) {
GeoUtils.checkLongitude(otherLongitude);
return normalizeLongitude(otherLongitude + random().nextDouble() - 0.5);
}
/**
/**
* returns next pseudorandom latitude, kinda close to {@code minLatitude/maxLatitude}
* <b>NOTE:</b>minLatitude/maxLatitude are merely guidelines. the returned value is sometimes
* outside of that range! this is to facilitate edge testing.
@ -60,8 +59,8 @@ public class GeoTestUtil {
GeoUtils.checkLatitude(maxLatitude);
return normalizeLatitude(randomRangeMaybeSlightlyOutside(minLatitude, maxLatitude));
}
/**
/**
* returns next pseudorandom longitude, kinda close to {@code minLongitude/maxLongitude}
* <b>NOTE:</b>minLongitude/maxLongitude are merely guidelines. the returned value is sometimes
* outside of that range! this is to facilitate edge testing.
@ -71,27 +70,27 @@ public class GeoTestUtil {
GeoUtils.checkLongitude(maxLongitude);
return normalizeLongitude(randomRangeMaybeSlightlyOutside(minLongitude, maxLongitude));
}
/** returns next pseudorandom box: can cross the 180th meridian */
public static GeoRect nextBox() {
public static Rectangle nextBox() {
return nextBoxInternal(nextLatitude(), nextLatitude(), nextLongitude(), nextLongitude(), true);
}
/** returns next pseudorandom box, can cross the 180th meridian, kinda close to {@code otherLatitude} and {@code otherLongitude} */
public static GeoRect nextBoxNear(double otherLatitude, double otherLongitude) {
public static Rectangle nextBoxNear(double otherLatitude, double otherLongitude) {
GeoUtils.checkLongitude(otherLongitude);
GeoUtils.checkLongitude(otherLongitude);
return nextBoxInternal(nextLatitudeNear(otherLatitude), nextLatitudeNear(otherLatitude),
return nextBoxInternal(nextLatitudeNear(otherLatitude), nextLatitudeNear(otherLatitude),
nextLongitudeNear(otherLongitude), nextLongitudeNear(otherLongitude), true);
}
/** returns next pseudorandom polygon */
public static Polygon nextPolygon() {
if (random().nextBoolean()) {
return surpriseMePolygon(null, null);
}
GeoRect box = nextBoxInternal(nextLatitude(), nextLatitude(), nextLongitude(), nextLongitude(), false);
Rectangle box = nextBoxInternal(nextLatitude(), nextLatitude(), nextLongitude(), nextLongitude(), false);
if (random().nextBoolean()) {
// box
return boxPolygon(box);
@ -100,14 +99,14 @@ public class GeoTestUtil {
return trianglePolygon(box);
}
}
/** returns next pseudorandom polygon, kinda close to {@code otherLatitude} and {@code otherLongitude} */
public static Polygon nextPolygonNear(double otherLatitude, double otherLongitude) {
if (random().nextBoolean()) {
return surpriseMePolygon(otherLatitude, otherLongitude);
}
GeoRect box = nextBoxInternal(nextLatitudeNear(otherLatitude), nextLatitudeNear(otherLatitude),
Rectangle box = nextBoxInternal(nextLatitudeNear(otherLatitude), nextLatitudeNear(otherLatitude),
nextLongitudeNear(otherLongitude), nextLongitudeNear(otherLongitude), false);
if (random().nextBoolean()) {
// box
@ -118,7 +117,7 @@ public class GeoTestUtil {
}
}
private static GeoRect nextBoxInternal(double lat0, double lat1, double lon0, double lon1, boolean canCrossDateLine) {
private static Rectangle nextBoxInternal(double lat0, double lat1, double lon0, double lon1, boolean canCrossDateLine) {
if (lat1 < lat0) {
double x = lat0;
lat0 = lat1;
@ -131,10 +130,10 @@ public class GeoTestUtil {
lon1 = x;
}
return new GeoRect(lat0, lat1, lon0, lon1);
return new Rectangle(lat0, lat1, lon0, lon1);
}
private static Polygon boxPolygon(GeoRect box) {
private static Polygon boxPolygon(Rectangle box) {
assert box.crossesDateline() == false;
final double[] polyLats = new double[5];
final double[] polyLons = new double[5];
@ -150,8 +149,8 @@ public class GeoTestUtil {
polyLons[4] = box.minLon;
return new Polygon(polyLats, polyLons);
}
private static Polygon trianglePolygon(GeoRect box) {
private static Polygon trianglePolygon(Rectangle box) {
assert box.crossesDateline() == false;
final double[] polyLats = new double[4];
final double[] polyLons = new double[4];
@ -165,7 +164,7 @@ public class GeoTestUtil {
polyLons[3] = box.minLon;
return new Polygon(polyLats, polyLons);
}
private static Polygon surpriseMePolygon(Double otherLatitude, Double otherLongitude) {
// repeat until we get a poly that doesn't cross dateline:
newPoly:
@ -235,7 +234,7 @@ public class GeoTestUtil {
return new Polygon(latsArray, lonsArray);
}
}
/** Returns random double min to max or up to 1% outside of that range */
private static double randomRangeMaybeSlightlyOutside(double min, double max) {
return min + (random().nextDouble() + (0.5 - random().nextDouble()) * .02) * (max - min);
@ -249,7 +248,7 @@ public class GeoTestUtil {
double off = Math.abs((latitude + 90) % 360);
return (off <= 180 ? off : 360-off) - 90;
}
/** Puts longitude in range of -180 to +180. */
private static double normalizeLongitude(double longitude) {
if (longitude >= -180 && longitude <= 180) {
@ -264,14 +263,14 @@ public class GeoTestUtil {
return -180 + off;
}
}
/** Keep it simple, we don't need to take arbitrary Random for geo tests */
private static Random random() {
return RandomizedContext.current().getRandom();
}
// craziness for plotting stuff :)
private static double wrapLat(double lat) {
//System.out.println("wrapLat " + lat);
if (lat > 90) {
@ -299,7 +298,7 @@ public class GeoTestUtil {
return lon;
}
}
private static void drawRectApproximatelyOnEarthSurface(String name, String color, double minLat, double maxLat, double minLon, double maxLon) {
int steps = 20;
System.out.println(" var " + name + " = WE.polygon([");
@ -324,7 +323,7 @@ public class GeoTestUtil {
System.out.println(" ], {color: \"" + color + "\", fillColor: \"" + color + "\"});");
System.out.println(" " + name + ".addTo(earth);");
}
private static void plotLatApproximatelyOnEarthSurface(String name, String color, double lat, double minLon, double maxLon) {
System.out.println(" var " + name + " = WE.polygon([");
double lon;
@ -373,7 +372,7 @@ public class GeoTestUtil {
double lon = poly[1][i];
System.out.println(" [" + lat + ", " + lon + "],");
}
System.out.println(" ], {color: '#00ff00'});");
System.out.println(" ], {color: '#00ff00'});");
System.out.println(" poly" + count + ".addTo(earth);");
}
@ -399,7 +398,7 @@ public class GeoTestUtil {
double rectMinLongitude, double rectMaxLongitude,
double centerLatitude, double centerLongitude,
double radiusMeters) {
GeoRect box = GeoRect.fromPointDistance(centerLatitude, centerLongitude, radiusMeters);
Rectangle box = Rectangle.fromPointDistance(centerLatitude, centerLongitude, radiusMeters);
System.out.println("<!DOCTYPE HTML>");
System.out.println("<html>");
System.out.println(" <head>");
@ -413,7 +412,7 @@ public class GeoTestUtil {
StringBuilder b = new StringBuilder();
inverseHaversin(b, centerLatitude, centerLongitude, radiusMeters);
System.out.println(b);
System.out.println(" ], {color: '#00ff00'});");
System.out.println(" ], {color: '#00ff00'});");
System.out.println(" polygonB.addTo(earth);");
drawRectApproximatelyOnEarthSurface("bbox", "#00ff00", box.minLat, box.maxLat, box.minLon, box.maxLon);
System.out.println(" WE.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{");
@ -421,7 +420,7 @@ public class GeoTestUtil {
System.out.println(" }).addTo(earth);");
plotLatApproximatelyOnEarthSurface("lat0", "#ffffff", 4.68, 0.0, 360.0);
plotLatApproximatelyOnEarthSurface("lat1", "#ffffff", 180-93.09, 0.0, 360.0);
plotLatApproximatelyOnEarthSurface("axisLat", "#00ff00", GeoRect.axisLat(centerLatitude, radiusMeters), box.minLon, box.maxLon);
plotLatApproximatelyOnEarthSurface("axisLat", "#00ff00", Rectangle.axisLat(centerLatitude, radiusMeters), box.minLon, box.maxLon);
plotLonApproximatelyOnEarthSurface("axisLon", "#00ff00", centerLongitude, box.minLat, box.maxLat);
System.out.println(" }");
System.out.println(" </script>");

View File

@ -0,0 +1,21 @@
/*
* 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.
*/
/**
* Reusable Geo test utilities.
*/
package org.apache.lucene.geo;