This commit is contained in:
Erick Erickson 2020-02-14 10:46:53 -05:00
commit 2b4fad53e5
29 changed files with 640 additions and 198 deletions

View File

@ -108,6 +108,8 @@ API Changes
* LUCENE-8621: Refactor LatLonShape, XYShape, and all query and utility classes to core. (Nick Knize) * LUCENE-8621: Refactor LatLonShape, XYShape, and all query and utility classes to core. (Nick Knize)
* LUCENE-9218: XY geometries API works in float space. (Ignacio Vera)
New Features New Features
--------------------- ---------------------

View File

@ -50,7 +50,7 @@ final class Line2D implements Component2D {
this.maxY = line.maxY; this.maxY = line.maxY;
this.minX = line.minX; this.minX = line.minX;
this.maxX = line.maxX; this.maxX = line.maxX;
this.tree = EdgeTree.createTree(line.getX(), line.getY()); this.tree = EdgeTree.createTree(XYEncodingUtils.floatArrayToDoubleArray(line.getX()), XYEncodingUtils.floatArrayToDoubleArray(line.getY()));
} }
@Override @Override

View File

@ -49,10 +49,10 @@ final class Polygon2D implements Component2D {
} }
private Polygon2D(XYPolygon polygon, Component2D holes) { private Polygon2D(XYPolygon polygon, Component2D holes) {
this(polygon.minX, polygon.maxX, polygon.minY, polygon.maxY, polygon.getPolyX(), polygon.getPolyY(), holes); this(polygon.minX, polygon.maxX, polygon.minY, polygon.maxY, XYEncodingUtils.floatArrayToDoubleArray(polygon.getPolyX()), XYEncodingUtils.floatArrayToDoubleArray(polygon.getPolyY()), holes);
} }
protected Polygon2D(Polygon polygon, Component2D holes) { private Polygon2D(Polygon polygon, Component2D holes) {
this(polygon.minLon, polygon.maxLon, polygon.minLat, polygon.maxLat, polygon.getPolyLons(), polygon.getPolyLats(), holes); this(polygon.minLon, polygon.maxLon, polygon.minLat, polygon.maxLat, polygon.getPolyLons(), polygon.getPolyLats(), holes);
} }

View File

@ -122,9 +122,9 @@ final public class Tessellator {
public static final List<Triangle> tessellate(final XYPolygon polygon) { public static final List<Triangle> tessellate(final XYPolygon polygon) {
// Attempt to establish a doubly-linked list of the provided shell points (should be CCW, but this will correct); // Attempt to establish a doubly-linked list of the provided shell points (should be CCW, but this will correct);
// then filter instances of intersections. // then filter instances of intersections.0
Node outerNode = createDoublyLinkedList(polygon.getPolyX(), polygon.getPolyY(), polygon.getWindingOrder(), false, Node outerNode = createDoublyLinkedList(XYEncodingUtils.floatArrayToDoubleArray(polygon.getPolyX()), XYEncodingUtils.floatArrayToDoubleArray(polygon.getPolyY()),
0, WindingOrder.CW); polygon.getWindingOrder(), false, 0, WindingOrder.CW);
// If an outer node hasn't been detected, the shape is malformed. (must comply with OGC SFA specification) // If an outer node hasn't been detected, the shape is malformed. (must comply with OGC SFA specification)
if(outerNode == null) { if(outerNode == null) {
throw new IllegalArgumentException("Malformed shape detected in Tessellator!"); throw new IllegalArgumentException("Malformed shape detected in Tessellator!");
@ -193,7 +193,8 @@ final public class Tessellator {
int nodeIndex = polygon.numPoints() ; int nodeIndex = polygon.numPoints() ;
for(int i = 0; i < polygon.numHoles(); ++i) { for(int i = 0; i < polygon.numHoles(); ++i) {
// create the doubly-linked hole list // create the doubly-linked hole list
Node list = createDoublyLinkedList(holes[i].getPolyX(), holes[i].getPolyY(), holes[i].getWindingOrder(), false, nodeIndex, WindingOrder.CCW); Node list = createDoublyLinkedList(XYEncodingUtils.floatArrayToDoubleArray(holes[i].getPolyX()),
XYEncodingUtils.floatArrayToDoubleArray(holes[i].getPolyY()), holes[i].getWindingOrder(), false, nodeIndex, WindingOrder.CCW);
// Determine if the resulting hole polygon was successful. // Determine if the resulting hole polygon was successful.
if(list != null) { if(list != null) {
// Add the leftmost vertex of the hole. // Add the leftmost vertex of the hole.
@ -1059,8 +1060,9 @@ final public class Tessellator {
this.vrtxIdx = vertexIndex; this.vrtxIdx = vertexIndex;
this.polyX = x; this.polyX = x;
this.polyY = y; this.polyY = y;
this.y = isGeo ? encodeLatitude(polyY[vrtxIdx]) : XYEncodingUtils.encode(polyY[vrtxIdx]); // casting to float is safe as original values for non-geo are represented as floats
this.x = isGeo ? encodeLongitude(polyX[vrtxIdx]) : XYEncodingUtils.encode(polyX[vrtxIdx]); this.y = isGeo ? encodeLatitude(polyY[vrtxIdx]) : XYEncodingUtils.encode((float) polyY[vrtxIdx]);
this.x = isGeo ? encodeLongitude(polyX[vrtxIdx]) : XYEncodingUtils.encode((float) polyX[vrtxIdx]);
this.morton = BitUtil.interleave(this.x ^ 0x80000000, this.y ^ 0x80000000); this.morton = BitUtil.interleave(this.x ^ 0x80000000, this.y ^ 0x80000000);
this.previous = null; this.previous = null;
this.next = null; this.next = null;

View File

@ -33,11 +33,12 @@ public final class XYEncodingUtils {
private XYEncodingUtils() { private XYEncodingUtils() {
} }
/** validates value is within +/-{@link Float#MAX_VALUE} coordinate bounds */ /** validates value is a number and finite */
public static void checkVal(double x) { static float checkVal(float x) {
if (Double.isNaN(x) || x < MIN_VAL_INCL || x > MAX_VAL_INCL) { if (Float.isFinite(x) == false) {
throw new IllegalArgumentException("invalid value " + x + "; must be between " + MIN_VAL_INCL + " and " + MAX_VAL_INCL); throw new IllegalArgumentException("invalid value " + x + "; must be between " + MIN_VAL_INCL + " and " + MAX_VAL_INCL);
} }
return x;
} }
/** /**
@ -46,9 +47,8 @@ public final class XYEncodingUtils {
* @return encoded value as a 32-bit {@code int} * @return encoded value as a 32-bit {@code int}
* @throws IllegalArgumentException if value is out of bounds * @throws IllegalArgumentException if value is out of bounds
*/ */
public static int encode(double x) { public static int encode(float x) {
checkVal(x); return NumericUtils.floatToSortableInt(checkVal(x));
return NumericUtils.floatToSortableInt((float)x);
} }
/** /**
@ -56,8 +56,8 @@ public final class XYEncodingUtils {
* @param encoded encoded value: 32-bit quantized value. * @param encoded encoded value: 32-bit quantized value.
* @return decoded value value. * @return decoded value value.
*/ */
public static double decode(int encoded) { public static float decode(int encoded) {
double result = NumericUtils.sortableIntToFloat(encoded); float result = NumericUtils.sortableIntToFloat(encoded);
assert result >= MIN_VAL_INCL && result <= MAX_VAL_INCL; assert result >= MIN_VAL_INCL && result <= MAX_VAL_INCL;
return result; return result;
} }
@ -68,7 +68,15 @@ public final class XYEncodingUtils {
* @param offset offset into {@code src} to decode from. * @param offset offset into {@code src} to decode from.
* @return decoded value. * @return decoded value.
*/ */
public static double decode(byte[] src, int offset) { public static float decode(byte[] src, int offset) {
return decode(NumericUtils.sortableBytesToInt(src, offset)); return decode(NumericUtils.sortableBytesToInt(src, offset));
} }
static double[] floatArrayToDoubleArray(float[] f) {
double[] d = new double[f.length];
for (int i = 0; i < f.length; i++) {
d[i] = f[i];
}
return d;
}
} }

View File

@ -18,24 +18,26 @@ package org.apache.lucene.geo;
import java.util.Arrays; import java.util.Arrays;
import static org.apache.lucene.geo.XYEncodingUtils.checkVal;
/** /**
* Represents a line in cartesian space. You can construct the Line directly with {@code float[]}, {@code float[]} x, y arrays * Represents a line in cartesian space. You can construct the Line directly with {@code float[]}, {@code float[]} x, y arrays
* coordinates. * coordinates.
*/ */
public class XYLine extends XYGeometry { public class XYLine extends XYGeometry {
/** array of x coordinates */ /** array of x coordinates */
private final double[] x; private final float[] x;
/** array of y coordinates */ /** array of y coordinates */
private final double[] y; private final float[] y;
/** minimum x of this line's bounding box */ /** minimum x of this line's bounding box */
public final double minX; public final float minX;
/** maximum y of this line's bounding box */ /** maximum y of this line's bounding box */
public final double maxX; public final float maxX;
/** minimum y of this line's bounding box */ /** minimum y of this line's bounding box */
public final double minY; public final float minY;
/** maximum y of this line's bounding box */ /** maximum y of this line's bounding box */
public final double maxY; public final float maxY;
/** /**
* Creates a new Line from the supplied X/Y array. * Creates a new Line from the supplied X/Y array.
@ -55,23 +57,19 @@ public class XYLine extends XYGeometry {
} }
// compute bounding box // compute bounding box
double minX = x[0]; float minX = Float.MAX_VALUE;
double minY = y[0]; float minY = Float.MAX_VALUE;
double maxX = x[0]; float maxX = -Float.MAX_VALUE;
double maxY = y[0]; float maxY = -Float.MAX_VALUE;
for (int i = 0; i < x.length; ++i) { for (int i = 0; i < x.length; ++i) {
minX = Math.min(x[i], minX); minX = Math.min(checkVal(x[i]), minX);
minY = Math.min(y[i], minY); minY = Math.min(checkVal(y[i]), minY);
maxX = Math.max(x[i], maxX); maxX = Math.max(x[i], maxX);
maxY = Math.max(y[i], maxY); maxY = Math.max(y[i], maxY);
} }
this.x = x.clone();
this.y = y.clone();
this.x = new double[x.length];
this.y = new double[y.length];
for (int i = 0; i < x.length; ++i) {
this.x[i] = (double)x[i];
this.y[i] = (double)y[i];
}
this.minX = minX; this.minX = minX;
this.maxX = maxX; this.maxX = maxX;
this.minY = minY; this.minY = minY;
@ -84,22 +82,22 @@ public class XYLine extends XYGeometry {
} }
/** Returns x value at given index */ /** Returns x value at given index */
public double getX(int vertex) { public float getX(int vertex) {
return x[vertex]; return x[vertex];
} }
/** Returns y value at given index */ /** Returns y value at given index */
public double getY(int vertex) { public float getY(int vertex) {
return y[vertex]; return y[vertex];
} }
/** Returns a copy of the internal x array */ /** Returns a copy of the internal x array */
public double[] getX() { public float[] getX() {
return x.clone(); return x.clone();
} }
/** Returns a copy of the internal y array */ /** Returns a copy of the internal y array */
public double[] getY() { public float[] getY() {
return y.clone(); return y.clone();
} }
@ -108,14 +106,6 @@ public class XYLine extends XYGeometry {
return Line2D.create(this); return Line2D.create(this);
} }
public String toGeoJSON() {
StringBuilder sb = new StringBuilder();
sb.append("[");
sb.append(Polygon.verticesToGeoJSON(x, y));
sb.append("]");
return sb.toString();
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;

View File

@ -17,6 +17,8 @@
package org.apache.lucene.geo; package org.apache.lucene.geo;
import static org.apache.lucene.geo.XYEncodingUtils.checkVal;
/** /**
* Represents a point on the earth's surface. You can construct the point directly with {@code double} * Represents a point on the earth's surface. You can construct the point directly with {@code double}
* coordinates. * coordinates.
@ -30,25 +32,25 @@ package org.apache.lucene.geo;
public final class XYPoint extends XYGeometry { public final class XYPoint extends XYGeometry {
/** latitude coordinate */ /** latitude coordinate */
private final double x; private final float x;
/** longitude coordinate */ /** longitude coordinate */
private final double y; private final float y;
/** /**
* Creates a new Point from the supplied latitude/longitude. * Creates a new Point from the supplied latitude/longitude.
*/ */
public XYPoint(float x, float y) { public XYPoint(float x, float y) {
this.x = x; this.x = checkVal(x);
this.y = y; this.y = checkVal(y);
} }
/** Returns latitude value at given index */ /** Returns latitude value at given index */
public double getX() { public float getX() {
return x; return x;
} }
/** Returns longitude value at given index */ /** Returns longitude value at given index */
public double getY() { public float getY() {
return y; return y;
} }
@ -67,8 +69,8 @@ public final class XYPoint extends XYGeometry {
@Override @Override
public int hashCode() { public int hashCode() {
int result = Double.hashCode(x); int result = Float.hashCode(x);
result = 31 * result + Double.hashCode(y); result = 31 * result + Float.hashCode(y);
return result; return result;
} }

View File

@ -18,23 +18,25 @@ package org.apache.lucene.geo;
import java.util.Arrays; import java.util.Arrays;
import static org.apache.lucene.geo.XYEncodingUtils.checkVal;
/** /**
* Represents a polygon in cartesian space. You can construct the Polygon directly with {@code float[]}, {@code float[]} x, y arrays * Represents a polygon in cartesian space. You can construct the Polygon directly with {@code float[]}, {@code float[]} x, y arrays
* coordinates. * coordinates.
*/ */
public final class XYPolygon extends XYGeometry { public final class XYPolygon extends XYGeometry {
private final double[] x; private final float[] x;
private final double[] y; private final float[] y;
private final XYPolygon[] holes; private final XYPolygon[] holes;
/** minimum x of this polygon's bounding box area */ /** minimum x of this polygon's bounding box area */
public final double minX; public final float minX;
/** maximum x of this polygon's bounding box area */ /** maximum x of this polygon's bounding box area */
public final double maxX; public final float maxX;
/** minimum y of this polygon's bounding box area */ /** minimum y of this polygon's bounding box area */
public final double minY; public final float minY;
/** maximum y of this polygon's bounding box area */ /** maximum y of this polygon's bounding box area */
public final double maxY; public final float maxY;
/** winding order of the vertices */ /** winding order of the vertices */
private final GeoUtils.WindingOrder windingOrder; private final GeoUtils.WindingOrder windingOrder;
@ -69,26 +71,22 @@ public final class XYPolygon extends XYGeometry {
throw new IllegalArgumentException("holes may not contain holes: polygons may not nest."); throw new IllegalArgumentException("holes may not contain holes: polygons may not nest.");
} }
} }
this.x = new double[x.length]; this.x = x.clone();
this.y = new double[y.length]; this.y = y.clone();
for (int i = 0; i < x.length; ++i) {
this.x[i] = (double)x[i];
this.y[i] = (double)y[i];
}
this.holes = holes.clone(); this.holes = holes.clone();
// compute bounding box // compute bounding box
double minX = x[0]; float minX = checkVal(x[0]);
double maxX = x[0]; float maxX = x[0];
double minY = y[0]; float minY = checkVal(y[0]);
double maxY = y[0]; float maxY = y[0];
double windingSum = 0d; double windingSum = 0d;
final int numPts = x.length - 1; final int numPts = x.length - 1;
for (int i = 1, j = 0; i < numPts; j = i++) { for (int i = 1, j = 0; i < numPts; j = i++) {
minX = Math.min(x[i], minX); minX = Math.min(checkVal(x[i]), minX);
maxX = Math.max(x[i], maxX); maxX = Math.max(x[i], maxX);
minY = Math.min(y[i], minY); minY = Math.min(checkVal(y[i]), minY);
maxY = Math.max(y[i], maxY); maxY = Math.max(y[i], maxY);
// compute signed area // compute signed area
windingSum += (x[j] - x[numPts])*(y[i] - y[numPts]) windingSum += (x[j] - x[numPts])*(y[i] - y[numPts])
@ -107,22 +105,22 @@ public final class XYPolygon extends XYGeometry {
} }
/** Returns a copy of the internal x array */ /** Returns a copy of the internal x array */
public double[] getPolyX() { public float[] getPolyX() {
return x.clone(); return x.clone();
} }
/** Returns x value at given index */ /** Returns x value at given index */
public double getPolyX(int vertex) { public float getPolyX(int vertex) {
return x[vertex]; return x[vertex];
} }
/** Returns a copy of the internal y array */ /** Returns a copy of the internal y array */
public double[] getPolyY() { public float[] getPolyY() {
return y.clone(); return y.clone();
} }
/** Returns y value at given index */ /** Returns y value at given index */
public double getPolyY(int vertex) { public float getPolyY(int vertex) {
return y[vertex]; return y[vertex];
} }
@ -150,18 +148,6 @@ public final class XYPolygon extends XYGeometry {
return Polygon2D.create(this); return Polygon2D.create(this);
} }
public String toGeoJSON() {
StringBuilder sb = new StringBuilder();
sb.append("[");
sb.append(Polygon.verticesToGeoJSON(y, x));
for (XYPolygon hole : holes) {
sb.append(",");
sb.append(Polygon.verticesToGeoJSON(hole.y, hole.x));
}
sb.append("]");
return sb.toString();
}
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;

View File

@ -16,25 +16,31 @@
*/ */
package org.apache.lucene.geo; package org.apache.lucene.geo;
import static org.apache.lucene.geo.XYEncodingUtils.checkVal;
/** Represents a x/y cartesian rectangle. */ /** Represents a x/y cartesian rectangle. */
public final class XYRectangle extends XYGeometry { public final class XYRectangle extends XYGeometry {
/** minimum x value */ /** minimum x value */
public final double minX; public final float minX;
/** minimum y value */ /** minimum y value */
public final double maxX; public final float maxX;
/** maximum x value */ /** maximum x value */
public final double minY; public final float minY;
/** maximum y value */ /** maximum y value */
public final double maxY; public final float maxY;
/** Constructs a bounding box by first validating the provided x and y coordinates */ /** Constructs a bounding box by first validating the provided x and y coordinates */
public XYRectangle(double minX, double maxX, double minY, double maxY) { public XYRectangle(float minX, float maxX, float minY, float maxY) {
this.minX = minX; if (minX > maxX) {
this.maxX = maxX; throw new IllegalArgumentException("minX must be lower than maxX, got " + minX + " > " + maxX);
this.minY = minY; }
this.maxY = maxY; if (minY > maxY) {
assert minX <= maxX; throw new IllegalArgumentException("minY must be lower than maxY, got " + minY + " > " + maxY);
assert minY <= maxY; }
this.minX = checkVal(minX);
this.maxX = checkVal(maxX);
this.minY = checkVal(minY);
this.maxY = checkVal(maxY);
} }
@Override @Override
@ -49,10 +55,10 @@ public final class XYRectangle extends XYGeometry {
XYRectangle rectangle = (XYRectangle) o; XYRectangle rectangle = (XYRectangle) o;
if (Double.compare(rectangle.minX, minX) != 0) return false; if (Float.compare(rectangle.minX, minX) != 0) return false;
if (Double.compare(rectangle.minY, minY) != 0) return false; if (Float.compare(rectangle.minY, minY) != 0) return false;
if (Double.compare(rectangle.maxX, maxX) != 0) return false; if (Float.compare(rectangle.maxX, maxX) != 0) return false;
return Double.compare(rectangle.maxY, maxY) == 0; return Float.compare(rectangle.maxY, maxY) == 0;
} }
@ -60,13 +66,13 @@ public final class XYRectangle extends XYGeometry {
public int hashCode() { public int hashCode() {
int result; int result;
long temp; long temp;
temp = Double.doubleToLongBits(minX); temp = Float.floatToIntBits(minX);
result = (int) (temp ^ (temp >>> 32)); result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(minY); temp = Float.floatToIntBits(minY);
result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(maxX); temp = Float.floatToIntBits(maxX);
result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(maxY); temp = Float.floatToIntBits(maxY);
result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + (int) (temp ^ (temp >>> 32));
return result; return result;
} }

View File

@ -235,9 +235,6 @@ final class XYRectangle2D implements Component2D {
/** create a component2D from the provided XY rectangle */ /** create a component2D from the provided XY rectangle */
static Component2D create(XYRectangle rectangle) { static Component2D create(XYRectangle rectangle) {
return new XYRectangle2D(XYEncodingUtils.decode(XYEncodingUtils.encode(rectangle.minX)), return new XYRectangle2D(rectangle.minX, rectangle.maxX, rectangle.minY, rectangle.maxY);
XYEncodingUtils.decode(XYEncodingUtils.encode(rectangle.maxX)),
XYEncodingUtils.decode(XYEncodingUtils.encode(rectangle.minY)),
XYEncodingUtils.decode(XYEncodingUtils.encode(rectangle.maxY)));
} }
} }

View File

@ -202,6 +202,9 @@ public final class LZ4 {
* offsets. A return value of {@code -1} indicates that no other index could * offsets. A return value of {@code -1} indicates that no other index could
* be found. */ * be found. */
abstract int previous(int off); abstract int previous(int off);
// For testing
abstract boolean assertReset();
} }
/** /**
@ -263,6 +266,11 @@ public final class LZ4 {
return -1; return -1;
} }
@Override
boolean assertReset() {
return true;
}
} }
/** /**
@ -369,6 +377,14 @@ public final class LZ4 {
} }
return -1; return -1;
} }
@Override
boolean assertReset() {
for (int i = 0; i < chainTable.length; ++i) {
assert chainTable[i] == (short) 0xFFFF : i;
}
return true;
}
} }
/** /**

View File

@ -126,8 +126,8 @@ public abstract class BaseXYShapeTestCase extends BaseShapeTestCase {
float[] x = new float[poly.numPoints() - 1]; float[] x = new float[poly.numPoints() - 1];
float[] y = new float[x.length]; float[] y = new float[x.length];
for (int i = 0; i < x.length; ++i) { for (int i = 0; i < x.length; ++i) {
x[i] = (float) poly.getPolyX(i); x[i] = poly.getPolyX(i);
y[i] = (float) poly.getPolyY(i); y[i] = poly.getPolyY(i);
} }
return new XYLine(x, y); return new XYLine(x, y);
@ -144,8 +144,8 @@ public abstract class BaseXYShapeTestCase extends BaseShapeTestCase {
int numPoints = TestUtil.nextInt(random, 1, 20); int numPoints = TestUtil.nextInt(random, 1, 20);
float[][] points = new float[numPoints][2]; float[][] points = new float[numPoints][2];
for (int i = 0; i < numPoints; i++) { for (int i = 0; i < numPoints; i++) {
points[i][0] = (float) ShapeTestUtil.nextDouble(random); points[i][0] = ShapeTestUtil.nextFloat(random);
points[i][1] = (float) ShapeTestUtil.nextDouble(random); points[i][1] = ShapeTestUtil.nextFloat(random);
} }
return points; return points;
} }
@ -164,22 +164,22 @@ public abstract class BaseXYShapeTestCase extends BaseShapeTestCase {
} }
@Override @Override
double quantizeX(double raw) { double quantizeX(double raw) {
return decode(encode(raw)); return decode(encode((float) raw));
} }
@Override @Override
double quantizeXCeil(double raw) { double quantizeXCeil(double raw) {
return decode(encode(raw)); return decode(encode((float) raw));
} }
@Override @Override
double quantizeY(double raw) { double quantizeY(double raw) {
return decode(encode(raw)); return decode(encode((float) raw));
} }
@Override @Override
double quantizeYCeil(double raw) { double quantizeYCeil(double raw) {
return decode(encode(raw)); return decode(encode((float) raw));
} }
@Override @Override
@ -191,7 +191,7 @@ public abstract class BaseXYShapeTestCase extends BaseShapeTestCase {
@Override @Override
ShapeField.DecodedTriangle encodeDecodeTriangle(double ax, double ay, boolean ab, double bx, double by, boolean bc, double cx, double cy, boolean ca) { ShapeField.DecodedTriangle encodeDecodeTriangle(double ax, double ay, boolean ab, double bx, double by, boolean bc, double cx, double cy, boolean ca) {
byte[] encoded = new byte[7 * ShapeField.BYTES]; byte[] encoded = new byte[7 * ShapeField.BYTES];
ShapeField.encodeTriangle(encoded, encode(ay), encode(ax), ab, encode(by), encode(bx), bc, encode(cy), encode(cx), ca); ShapeField.encodeTriangle(encoded, encode((float) ay), encode((float) ax), ab, encode((float) by), encode((float) bx), bc, encode((float) cy), encode((float) cx), ca);
ShapeField.DecodedTriangle triangle = new ShapeField.DecodedTriangle(); ShapeField.DecodedTriangle triangle = new ShapeField.DecodedTriangle();
ShapeField.decodeTriangle(encoded, triangle); ShapeField.decodeTriangle(encoded, triangle);
return triangle; return triangle;

View File

@ -51,11 +51,11 @@ public class TestXYLineShapeQueries extends BaseXYShapeTestCase {
XYLine l = (XYLine) (shapes[i]); XYLine l = (XYLine) (shapes[i]);
if (random.nextBoolean() && l != null) { if (random.nextBoolean() && l != null) {
int v = random.nextInt(l.numPoints() - 1); int v = random.nextInt(l.numPoints() - 1);
x[j] = (float)l.getX(v); x[j] = l.getX(v);
y[j] = (float)l.getY(v); y[j] = l.getY(v);
} else { } else {
x[j] = (float)ShapeTestUtil.nextDouble(random); x[j] = ShapeTestUtil.nextFloat(random);
y[j] = (float)ShapeTestUtil.nextDouble(random); y[j] = ShapeTestUtil.nextFloat(random);
} }
} }
return new XYLine(x, y); return new XYLine(x, y);
@ -80,7 +80,7 @@ public class TestXYLineShapeQueries extends BaseXYShapeTestCase {
@Override @Override
public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) { public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY)); Component2D rectangle2D = XYGeometry.create(new XYRectangle((float) minX, (float) maxX, (float) minY, (float) maxY));
return testComponentQuery(rectangle2D, shape); return testComponentQuery(rectangle2D, shape);
} }

View File

@ -76,7 +76,7 @@ public class TestXYMultiLineShapeQueries extends BaseXYShapeTestCase {
@Override @Override
public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) { public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY)); Component2D rectangle2D = XYGeometry.create(new XYRectangle((float) minX, (float) maxX, (float) minY, (float) maxY));
return testComponentQuery(rectangle2D, shape); return testComponentQuery(rectangle2D, shape);
} }

View File

@ -75,7 +75,7 @@ public class TestXYMultiPointShapeQueries extends BaseXYShapeTestCase {
@Override @Override
public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) { public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY)); Component2D rectangle2D = XYGeometry.create(new XYRectangle((float) minX, (float) maxX, (float) minY, (float) maxY));
return testComponentQuery(rectangle2D, shape); return testComponentQuery(rectangle2D, shape);
} }

View File

@ -115,7 +115,7 @@ public class TestXYMultiPolygonShapeQueries extends BaseXYShapeTestCase {
@Override @Override
public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) { public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY)); Component2D rectangle2D = XYGeometry.create(new XYRectangle((float) minX, (float) maxX, (float) minY, (float) maxY));
return testComponentQuery(rectangle2D, shape); return testComponentQuery(rectangle2D, shape);
} }

View File

@ -53,8 +53,8 @@ public class TestXYPointShapeQueries extends BaseXYShapeTestCase {
x[j] = p.x; x[j] = p.x;
y[j] = p.y; y[j] = p.y;
} else { } else {
x[j] = (float)ShapeTestUtil.nextDouble(random); x[j] = ShapeTestUtil.nextFloat(random);
y[j] = (float)ShapeTestUtil.nextDouble(random); y[j] = ShapeTestUtil.nextFloat(random);
} }
} }
return new XYLine(x, y); return new XYLine(x, y);
@ -80,7 +80,7 @@ public class TestXYPointShapeQueries extends BaseXYShapeTestCase {
@Override @Override
public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) { public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY)); Component2D rectangle2D = XYGeometry.create(new XYRectangle((float) minX, (float) maxX, (float) minY, (float) maxY));
return testComponentQuery(rectangle2D, shape); return testComponentQuery(rectangle2D, shape);
} }

View File

@ -66,7 +66,7 @@ public class TestXYPolygonShapeQueries extends BaseXYShapeTestCase {
@Override @Override
public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) { public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY)); Component2D rectangle2D = XYGeometry.create(new XYRectangle((float) minX, (float) maxX, (float) minY, (float) maxY));
return testComponentQuery(rectangle2D, shape); return testComponentQuery(rectangle2D, shape);
} }

View File

@ -51,8 +51,8 @@ public class TestXYShape extends LuceneTestCase {
} }
} }
protected Query newRectQuery(String field, double minX, double maxX, double minY, double maxY) { protected Query newRectQuery(String field, float minX, float maxX, float minY, float maxY) {
return XYShape.newBoxQuery(field, QueryRelation.INTERSECTS, (float)minX, (float)maxX, (float)minY, (float)maxY); return XYShape.newBoxQuery(field, QueryRelation.INTERSECTS, minX, maxX, minY, maxY);
} }
/** test we can search for a point with a standard number of vertices*/ /** test we can search for a point with a standard number of vertices*/
@ -73,8 +73,8 @@ public class TestXYShape extends LuceneTestCase {
float x[] = new float[p.numPoints() - 1]; float x[] = new float[p.numPoints() - 1];
float y[] = new float[p.numPoints() - 1]; float y[] = new float[p.numPoints() - 1];
for (int i = 0; i < x.length; ++i) { for (int i = 0; i < x.length; ++i) {
x[i] = (float)p.getPolyX(i); x[i] = p.getPolyX(i);
y[i] = (float)p.getPolyY(i); y[i] = p.getPolyY(i);
} }
XYLine l = new XYLine(x, y); XYLine l = new XYLine(x, y);
addLineToDoc(FIELDNAME, document, l); addLineToDoc(FIELDNAME, document, l);
@ -85,28 +85,28 @@ public class TestXYShape extends LuceneTestCase {
IndexReader reader = writer.getReader(); IndexReader reader = writer.getReader();
writer.close(); writer.close();
IndexSearcher searcher = newSearcher(reader); IndexSearcher searcher = newSearcher(reader);
double minX = Math.min(x[0], x[1]); float minX = Math.min(x[0], x[1]);
double minY = Math.min(y[0], y[1]); float minY = Math.min(y[0], y[1]);
double maxX = Math.max(x[0], x[1]); float maxX = Math.max(x[0], x[1]);
double maxY = Math.max(y[0], y[1]); float maxY = Math.max(y[0], y[1]);
Query q = newRectQuery(FIELDNAME, minX, maxX, minY, maxY); Query q = newRectQuery(FIELDNAME, minX, maxX, minY, maxY);
assertEquals(2, searcher.count(q)); assertEquals(2, searcher.count(q));
// search a disjoint bbox // search a disjoint bbox
q = newRectQuery(FIELDNAME, p.minX-1d, p.minX+1, p.minY-1d, p.minY+1d); q = newRectQuery(FIELDNAME, p.minX-1f, p.minX + 1f, p.minY - 1f, p.minY + 1f);
assertEquals(0, searcher.count(q)); assertEquals(0, searcher.count(q));
// search w/ an intersecting polygon // search w/ an intersecting polygon
q = XYShape.newPolygonQuery(FIELDNAME, QueryRelation.INTERSECTS, new XYPolygon( q = XYShape.newPolygonQuery(FIELDNAME, QueryRelation.INTERSECTS, new XYPolygon(
new float[] {(float)minX, (float)minX, (float)maxX, (float)maxX, (float)minX}, new float[] {minX, minX, maxX, maxX, minX},
new float[] {(float)minY, (float)maxY, (float)maxY, (float)minY, (float)minY} new float[] {minY, maxY, maxY, minY, minY}
)); ));
assertEquals(2, searcher.count(q)); assertEquals(2, searcher.count(q));
// search w/ an intersecting line // search w/ an intersecting line
q = XYShape.newLineQuery(FIELDNAME, QueryRelation.INTERSECTS, new XYLine( q = XYShape.newLineQuery(FIELDNAME, QueryRelation.INTERSECTS, new XYLine(
new float[] {(float)minX, (float)minX, (float)maxX, (float)maxX}, new float[] {minX, minX, maxX, maxX},
new float[] {(float)minY, (float)maxY, (float)maxY, (float)minY} new float[] {minY, maxY, maxY, minY}
)); ));
assertEquals(2, searcher.count(q)); assertEquals(2, searcher.count(q));
@ -153,18 +153,18 @@ public class TestXYShape extends LuceneTestCase {
q = newRectQuery(FIELDNAME, r1.minX, r1.maxX, r1.minY, r1.maxY); q = newRectQuery(FIELDNAME, r1.minX, r1.maxX, r1.minY, r1.maxY);
assertEquals(1, searcher.count(q)); assertEquals(1, searcher.count(q));
// r1 contains r2, WITHIN should match // r1 contains r2, WITHIN should match
q = XYShape.newBoxQuery(FIELDNAME, QueryRelation.WITHIN, (float) r1.minX, (float) r1.maxX, (float) r1.minY, (float) r1.maxY); q = XYShape.newBoxQuery(FIELDNAME, QueryRelation.WITHIN, r1.minX, r1.maxX, r1.minY, r1.maxY);
assertEquals(1, searcher.count(q)); assertEquals(1, searcher.count(q));
IOUtils.close(reader, dir); IOUtils.close(reader, dir);
} }
private static boolean areBoxDisjoint(XYRectangle r1, XYRectangle r2) { private static boolean areBoxDisjoint(XYRectangle r1, XYRectangle r2) {
return ((float) r1.minX <= (float) r2.minX && (float) r1.minY <= (float) r2.minY && (float) r1.maxX >= (float) r2.maxX && (float) r1.maxY >= (float) r2.maxY); return ( r1.minX <= r2.minX && r1.minY <= r2.minY && r1.maxX >= r2.maxX && r1.maxY >= r2.maxY);
} }
private static XYPolygon toPolygon(XYRectangle r) { private static XYPolygon toPolygon(XYRectangle r) {
return new XYPolygon(new float[]{(float) r.minX, (float) r.maxX, (float) r.maxX, (float) r.minX, (float) r.minX}, return new XYPolygon(new float[]{ r.minX, r.maxX, r.maxX, r.minX, r.minX},
new float[]{(float) r.minY, (float) r.minY, (float) r.maxY, (float) r.maxY, (float) r.minY}); new float[]{ r.minY, r.minY, r.maxY, r.maxY, r.minY});
} }
} }

View File

@ -26,12 +26,12 @@ import org.apache.lucene.geo.XYPolygon;
public class TestXYShapeEncoding extends BaseShapeEncodingTestCase { public class TestXYShapeEncoding extends BaseShapeEncodingTestCase {
@Override @Override
protected int encodeX(double x) { protected int encodeX(double x) {
return XYEncodingUtils.encode(x); return XYEncodingUtils.encode((float) x);
} }
@Override @Override
protected int encodeY(double y) { protected int encodeY(double y) {
return XYEncodingUtils.encode(y); return XYEncodingUtils.encode((float) y);
} }
@Override @Override
@ -46,12 +46,12 @@ public class TestXYShapeEncoding extends BaseShapeEncodingTestCase {
@Override @Override
protected double nextX() { protected double nextX() {
return ShapeTestUtil.nextDouble(random()); return ShapeTestUtil.nextFloat(random());
} }
@Override @Override
protected double nextY() { protected double nextY() {
return ShapeTestUtil.nextDouble(random()); return ShapeTestUtil.nextFloat(random());
} }
@Override @Override

View File

@ -40,7 +40,7 @@ public class ShapeTestUtil {
// So the poly can cover at most 50% of the earth's surface: // So the poly can cover at most 50% of the earth's surface:
double radius = random.nextDouble() * 0.5 * Float.MAX_VALUE + 1.0; double radius = random.nextDouble() * 0.5 * Float.MAX_VALUE + 1.0;
try { try {
return createRegularPolygon(nextDouble(random), nextDouble(random), radius, gons); return createRegularPolygon(nextFloat(random), nextFloat(random), radius, gons);
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
// we tried to cross dateline or pole ... try again // we tried to cross dateline or pole ... try again
} }
@ -57,42 +57,53 @@ public class ShapeTestUtil {
} }
} }
public static XYLine nextLine() {
XYPolygon poly = ShapeTestUtil.nextPolygon();
float[] x = new float[poly.numPoints() - 1];
float[] y = new float[x.length];
for (int i = 0; i < x.length; ++i) {
x[i] = poly.getPolyX(i);
y[i] = poly.getPolyY(i);
}
return new XYLine(x, y);
}
private static XYPolygon trianglePolygon(XYRectangle box) { private static XYPolygon trianglePolygon(XYRectangle box) {
final float[] polyX = new float[4]; final float[] polyX = new float[4];
final float[] polyY = new float[4]; final float[] polyY = new float[4];
polyX[0] = (float)box.minX; polyX[0] = box.minX;
polyY[0] = (float)box.minY; polyY[0] = box.minY;
polyX[1] = (float)box.minX; polyX[1] = box.minX;
polyY[1] = (float)box.minY; polyY[1] = box.minY;
polyX[2] = (float)box.minX; polyX[2] = box.minX;
polyY[2] = (float)box.minY; polyY[2] = box.minY;
polyX[3] = (float)box.minX; polyX[3] = box.minX;
polyY[3] = (float)box.minY; polyY[3] = box.minY;
return new XYPolygon(polyX, polyY); return new XYPolygon(polyX, polyY);
} }
public static XYRectangle nextBox(Random random) { public static XYRectangle nextBox(Random random) {
// prevent lines instead of boxes // prevent lines instead of boxes
double x0 = nextDouble(random); float x0 = nextFloat(random);
double x1 = nextDouble(random); float x1 = nextFloat(random);
while (x0 == x1) { while (x0 == x1) {
x1 = nextDouble(random); x1 = nextFloat(random);
} }
// prevent lines instead of boxes // prevent lines instead of boxes
double y0 = nextDouble(random); float y0 = nextFloat(random);
double y1 = nextDouble(random); float y1 = nextFloat(random);
while (y0 == y1) { while (y0 == y1) {
y1 = nextDouble(random); y1 = nextFloat(random);
} }
if (x1 < x0) { if (x1 < x0) {
double x = x0; float x = x0;
x0 = x1; x0 = x1;
x1 = x; x1 = x;
} }
if (y1 < y0) { if (y1 < y0) {
double y = y0; float y = y0;
y0 = y1; y0 = y1;
y1 = y; y1 = y;
} }
@ -103,16 +114,16 @@ public class ShapeTestUtil {
private static XYPolygon boxPolygon(XYRectangle box) { private static XYPolygon boxPolygon(XYRectangle box) {
final float[] polyX = new float[5]; final float[] polyX = new float[5];
final float[] polyY = new float[5]; final float[] polyY = new float[5];
polyX[0] = (float)box.minX; polyX[0] = box.minX;
polyY[0] = (float)box.minY; polyY[0] = box.minY;
polyX[1] = (float)box.minX; polyX[1] = box.minX;
polyY[1] = (float)box.minY; polyY[1] = box.minY;
polyX[2] = (float)box.minX; polyX[2] = box.minX;
polyY[2] = (float)box.minY; polyY[2] = box.minY;
polyX[3] = (float)box.minX; polyX[3] = box.minX;
polyY[3] = (float)box.minY; polyY[3] = box.minY;
polyX[4] = (float)box.minX; polyX[4] = box.minX;
polyY[4] = (float)box.minY; polyY[4] = box.minY;
return new XYPolygon(polyX, polyY); return new XYPolygon(polyX, polyY);
} }
@ -120,8 +131,8 @@ public class ShapeTestUtil {
// repeat until we get a poly that doesn't cross dateline: // repeat until we get a poly that doesn't cross dateline:
while (true) { while (true) {
//System.out.println("\nPOLY ITER"); //System.out.println("\nPOLY ITER");
double centerX = nextDouble(random); float centerX = nextFloat(random);
double centerY = nextDouble(random); float centerY = nextFloat(random);
double radius = 0.1 + 20 * random.nextDouble(); double radius = 0.1 + 20 * random.nextDouble();
double radiusDelta = random.nextDouble(); double radiusDelta = random.nextDouble();
@ -135,8 +146,8 @@ public class ShapeTestUtil {
break; break;
} }
double len = radius * (1.0 - radiusDelta + radiusDelta * random.nextDouble()); double len = radius * (1.0 - radiusDelta + radiusDelta * random.nextDouble());
double maxX = StrictMath.min(StrictMath.abs(Float.MAX_VALUE - centerX), StrictMath.abs(-Float.MAX_VALUE - centerX)); float maxX = StrictMath.min(StrictMath.abs(Float.MAX_VALUE - centerX), StrictMath.abs(-Float.MAX_VALUE - centerX));
double maxY = StrictMath.min(StrictMath.abs(Float.MAX_VALUE - centerY), StrictMath.abs(-Float.MAX_VALUE - centerY)); float maxY = StrictMath.min(StrictMath.abs(Float.MAX_VALUE - centerY), StrictMath.abs(-Float.MAX_VALUE - centerY));
len = StrictMath.min(len, StrictMath.min(maxX, maxY)); len = StrictMath.min(len, StrictMath.min(maxX, maxY));
@ -195,8 +206,8 @@ public class ShapeTestUtil {
return new XYPolygon(result[0], result[1]); return new XYPolygon(result[0], result[1]);
} }
public static double nextDouble(Random random) { public static float nextFloat(Random random) {
return BiasedNumbers.randomDoubleBetween(random, -Float.MAX_VALUE, Float.MAX_VALUE); return BiasedNumbers.randomFloatBetween(random, -Float.MAX_VALUE, Float.MAX_VALUE);
} }
/** Keep it simple, we don't need to take arbitrary Random for geo tests */ /** Keep it simple, we don't need to take arbitrary Random for geo tests */

View File

@ -0,0 +1,99 @@
/*
* 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.geo;
import java.util.Arrays;
import org.apache.lucene.util.LuceneTestCase;
public class TestXYLine extends LuceneTestCase {
/** null x not allowed */
public void testLineNullXs() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYLine(null, new float[] { -66, -65, -65, -66, -66 });
});
assertTrue(expected.getMessage().contains("x must not be null"));
}
/** null y not allowed */
public void testPolygonNullYs() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYLine(new float[] {18, 18, 19, 19, 18 }, null);
});
assertTrue(expected.getMessage().contains("y must not be null"));
}
/** needs at least 3 vertices */
public void testLineEnoughPoints() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYLine(new float[] {18}, new float[] { -66});
});
assertTrue(expected.getMessage().contains("at least 2 line points required"));
}
/** lines needs same number of x as y */
public void testLinesBogus() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYLine(new float[] { 18, 18, 19, 19 }, new float[] { -66, -65, -65, -66, -66 });
});
assertTrue(expected.getMessage().contains("must be equal length"));
}
/** line values cannot be NaN */
public void testLineNaN() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYLine(new float[] { 18, 18, 19, Float.NaN, 18 }, new float[] { -66, -65, -65, -66, -66 });
});
assertTrue(expected.getMessage(), expected.getMessage().contains("invalid value NaN"));
}
/** line values cannot be finite */
public void testLinePositiveInfinite() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYLine(new float[] { 18, 18, 19, 19, 18 }, new float[] { -66, Float.POSITIVE_INFINITY, -65, -66, -66 });
});
assertTrue(expected.getMessage(), expected.getMessage().contains("invalid value Inf"));
}
/** line values cannot be finite */
public void testLineNegativeInfinite() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYLine(new float[] { 18, 18, 19, 19, 18 }, new float[] { -66, -65, -65, Float.NEGATIVE_INFINITY, -66 });
});
assertTrue(expected.getMessage(), expected.getMessage().contains("invalid value -Inf"));
}
/** equals and hashcode */
public void testEqualsAndHashCode() {
XYLine line = ShapeTestUtil.nextLine();
XYLine copy = new XYLine(line.getX(), line.getY());
assertEquals(line, copy);
assertEquals(line.hashCode(), copy.hashCode());
XYLine otherLine = ShapeTestUtil.nextLine();
if (Arrays.equals(line.getX(), otherLine.getX()) == false ||
Arrays.equals(line.getY(), otherLine.getY()) == false) {
assertNotEquals(line, otherLine);
assertNotEquals(line.hashCode(), otherLine.hashCode());
} else {
assertEquals(line, otherLine);
assertEquals(line.hashCode(), otherLine.hashCode());
}
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.geo;
import org.apache.lucene.util.LuceneTestCase;
public class TestXYPoint extends LuceneTestCase {
/** point values cannot be NaN */
public void testNaN() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPoint(Float.NaN, 45.23f);
});
assertTrue(expected.getMessage().contains("invalid value NaN"));
expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPoint(43.5f, Float.NaN);
});
assertTrue(expected.getMessage().contains("invalid value NaN"));
}
/** point values mist be finite */
public void testPositiveInf() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPoint(Float.POSITIVE_INFINITY, 45.23f);
});
assertTrue(expected.getMessage().contains("invalid value Inf"));
expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPoint(43.5f, Float.POSITIVE_INFINITY);
});
assertTrue(expected.getMessage().contains("invalid value Inf"));
}
/** point values mist be finite */
public void testNegativeInf() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPoint(Float.NEGATIVE_INFINITY, 45.23f);
});
assertTrue(expected.getMessage().contains("invalid value -Inf"));
expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPoint(43.5f, Float.NEGATIVE_INFINITY);
});
assertTrue(expected.getMessage().contains("invalid value -Inf"));
}
/** equals and hashcode */
public void testEqualsAndHashCode() {
XYPoint point = new XYPoint(ShapeTestUtil.nextFloat(random()), ShapeTestUtil.nextFloat(random()));
XYPoint copy = new XYPoint(point.getX(), point.getY());
assertEquals(point, copy);
assertEquals(point.hashCode(), copy.hashCode());
XYPoint otherPoint = new XYPoint(ShapeTestUtil.nextFloat(random()), ShapeTestUtil.nextFloat(random()));
if (point.getX() != otherPoint.getX() || point.getY() != otherPoint.getY()) {
assertNotEquals(point, otherPoint);
assertNotEquals(point.hashCode(), otherPoint.hashCode());
} else {
assertEquals(point, otherPoint);
assertEquals(point.hashCode(), otherPoint.hashCode());
}
}
}

View File

@ -0,0 +1,107 @@
/*
* 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.geo;
import java.util.Arrays;
import org.apache.lucene.util.LuceneTestCase;
public class TestXYPolygon extends LuceneTestCase {
/** null x not allowed */
public void testPolygonNullPolyLats() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPolygon(null, new float[] { -66, -65, -65, -66, -66 });
});
assertTrue(expected.getMessage().contains("x must not be null"));
}
/** null y not allowed */
public void testPolygonNullPolyLons() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPolygon(new float[] {18, 18, 19, 19, 18 }, null);
});
assertTrue(expected.getMessage().contains("y must not be null"));
}
/** polygon needs at least 3 vertices */
public void testPolygonLine() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPolygon(new float[] { 18, 18, 18 }, new float[] { -66, -65, -66 });
});
assertTrue(expected.getMessage().contains("at least 4 polygon points required"));
}
/** polygon needs same number of latitudes as longitudes */
public void testPolygonBogus() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPolygon(new float[] { 18, 18, 19, 19 }, new float[] { -66, -65, -65, -66, -66 });
});
assertTrue(expected.getMessage().contains("must be equal length"));
}
/** polygon must be closed */
public void testPolygonNotClosed() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPolygon(new float[] { 18, 18, 19, 19, 19 }, new float[] { -66, -65, -65, -66, -67 });
});
assertTrue(expected.getMessage(), expected.getMessage().contains("it must close itself"));
}
/** polygon values cannot be NaN */
public void testPolygonNaN() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPolygon(new float[] { 18, 18, 19, Float.NaN, 18 }, new float[] { -66, -65, -65, -66, -66 });
});
assertTrue(expected.getMessage(), expected.getMessage().contains("invalid value NaN"));
}
/** polygon values cannot be finite */
public void testPolygonPositiveInfinite() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPolygon(new float[] { 18, 18, 19, 19, 18 }, new float[] { -66, Float.POSITIVE_INFINITY, -65, -66, -66 });
});
assertTrue(expected.getMessage(), expected.getMessage().contains("invalid value Inf"));
}
/** polygon values cannot be finite */
public void testPolygonNegativeInfinite() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYPolygon(new float[] { 18, 18, 19, 19, 18 }, new float[] { -66, -65, -65, Float.NEGATIVE_INFINITY, -66 });
});
assertTrue(expected.getMessage(), expected.getMessage().contains("invalid value -Inf"));
}
/** equals and hashcode */
public void testEqualsAndHashCode() {
XYPolygon polygon = ShapeTestUtil.nextPolygon();
XYPolygon copy = new XYPolygon(polygon.getPolyX(), polygon.getPolyY(), polygon.getHoles());
assertEquals(polygon, copy);
assertEquals(polygon.hashCode(), copy.hashCode());
XYPolygon otherPolygon = ShapeTestUtil.nextPolygon();
if (Arrays.equals(polygon.getPolyX(), otherPolygon.getPolyX()) == false ||
Arrays.equals(polygon.getPolyY(), otherPolygon.getPolyY()) == false ||
Arrays.equals(polygon.getHoles(), otherPolygon.getHoles()) == false) {
assertNotEquals(polygon, otherPolygon);
assertNotEquals(polygon.hashCode(), otherPolygon.hashCode());
} else {
assertEquals(polygon, otherPolygon);
assertEquals(polygon.hashCode(), otherPolygon.hashCode());
}
}
}

View File

@ -0,0 +1,106 @@
/*
* 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.geo;
import org.apache.lucene.util.LuceneTestCase;
public class TestXYRectangle extends LuceneTestCase {
/** maxX must be gte minX */
public void tesInvalidMinMaxX() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(5, 4, 3 ,4);
});
assertTrue(expected.getMessage().contains("5 > 4"));
}
/** maxY must be gte minY */
public void tesInvalidMinMaxY() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(4, 5, 5 ,4);
});
assertTrue(expected.getMessage().contains("5 > 4"));
}
/** rectangle values cannot be NaN */
public void testNaN() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(Float.NaN, 4, 3 ,4);
});
assertTrue(expected.getMessage().contains("invalid value NaN"));
expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(3, Float.NaN, 3 ,4);
});
assertTrue(expected.getMessage().contains("invalid value NaN"));
expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(3, 4, Float.NaN ,4);
});
assertTrue(expected.getMessage().contains("invalid value NaN"));
expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(3, 4, 3 , Float.NaN);
});
assertTrue(expected.getMessage().contains("invalid value NaN"));
}
/** rectangle values must be finite */
public void testPositiveInf() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(3, Float.POSITIVE_INFINITY, 3 ,4);
});
assertTrue(expected.getMessage().contains("invalid value Inf"));
expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(3, 4, 3 , Float.POSITIVE_INFINITY);
});
assertTrue(expected.getMessage().contains("invalid value Inf"));
}
/** rectangle values must be finite */
public void testNegativeInf() {
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(Float.NEGATIVE_INFINITY, 4, 3 ,4);
});
assertTrue(expected.getMessage().contains("invalid value -Inf"));
expected = expectThrows(IllegalArgumentException.class, () -> {
new XYRectangle(3, 4, Float.NEGATIVE_INFINITY ,4);
});
assertTrue(expected.getMessage().contains("invalid value -Inf"));
}
/** equals and hashcode */
public void testEqualsAndHashCode() {
XYRectangle rectangle = ShapeTestUtil.nextBox(random());
XYRectangle copy = new XYRectangle(rectangle.minX, rectangle.maxX, rectangle.minY, rectangle.maxY);
assertEquals(rectangle, copy);
assertEquals(rectangle.hashCode(), copy.hashCode());
XYRectangle otherRectangle = ShapeTestUtil.nextBox(random());
if (rectangle.minX != otherRectangle.minX || rectangle.maxX != otherRectangle.maxX ||
rectangle.minY != otherRectangle.minY || rectangle.maxY != otherRectangle.maxY) {
assertNotEquals(rectangle, otherRectangle);
assertNotEquals(rectangle.hashCode(), otherRectangle.hashCode());
} else {
assertEquals(rectangle, otherRectangle);
assertEquals(rectangle.hashCode(), otherRectangle.hashCode());
}
}
}

View File

@ -26,7 +26,7 @@ import org.apache.lucene.util.LuceneTestCase;
public class TestXYRectangle2D extends LuceneTestCase { public class TestXYRectangle2D extends LuceneTestCase {
public void testTriangleDisjoint() { public void testTriangleDisjoint() {
XYRectangle rectangle = new XYRectangle(0d, 1d, 0d, 1d); XYRectangle rectangle = new XYRectangle(0f, 1f, 0f, 1f);
Component2D rectangle2D = XYRectangle2D.create(rectangle); Component2D rectangle2D = XYRectangle2D.create(rectangle);
float ax = 4f; float ax = 4f;
float ay = 4f; float ay = 4f;
@ -38,7 +38,7 @@ public class TestXYRectangle2D extends LuceneTestCase {
} }
public void testTriangleIntersects() { public void testTriangleIntersects() {
XYRectangle rectangle = new XYRectangle(0d, 1d, 0d, 1d); XYRectangle rectangle = new XYRectangle(0f, 1f, 0f, 1f);
Component2D rectangle2D = XYRectangle2D.create(rectangle); Component2D rectangle2D = XYRectangle2D.create(rectangle);
float ax = 0.5f; float ax = 0.5f;
float ay = 0.5f; float ay = 0.5f;
@ -66,12 +66,12 @@ public class TestXYRectangle2D extends LuceneTestCase {
XYRectangle rectangle = ShapeTestUtil.nextBox(random); XYRectangle rectangle = ShapeTestUtil.nextBox(random);
Component2D rectangle2D = XYRectangle2D.create(rectangle); Component2D rectangle2D = XYRectangle2D.create(rectangle);
for (int i =0; i < 100; i++) { for (int i =0; i < 100; i++) {
float ax = (float) ShapeTestUtil.nextDouble(random); float ax = ShapeTestUtil.nextFloat(random);
float ay = (float) ShapeTestUtil.nextDouble(random); float ay = ShapeTestUtil.nextFloat(random);
float bx = (float) ShapeTestUtil.nextDouble(random); float bx = ShapeTestUtil.nextFloat(random);
float by = (float) ShapeTestUtil.nextDouble(random); float by = ShapeTestUtil.nextFloat(random);
float cx = (float) ShapeTestUtil.nextDouble(random); float cx = ShapeTestUtil.nextFloat(random);
float cy = (float) ShapeTestUtil.nextDouble(random); float cy = ShapeTestUtil.nextFloat(random);
float tMinX = StrictMath.min(StrictMath.min(ax, bx), cx); float tMinX = StrictMath.min(StrictMath.min(ax, bx), cx);
float tMaxX = StrictMath.max(StrictMath.max(ax, bx), cx); float tMaxX = StrictMath.max(StrictMath.max(ax, bx), cx);

View File

@ -30,6 +30,37 @@ public abstract class LZ4TestCase extends LuceneTestCase {
protected abstract LZ4.HashTable newHashTable(); protected abstract LZ4.HashTable newHashTable();
protected static class AssertingHashTable extends LZ4.HashTable {
private final LZ4.HashTable in;
AssertingHashTable(LZ4.HashTable in) {
this.in = in;
}
@Override
void reset(byte[] b, int off, int len) {
in.reset(b, off, len);
assertTrue(in.assertReset());
}
@Override
int get(int off) {
return in.get(off);
}
@Override
int previous(int off) {
return in.previous(off);
}
@Override
boolean assertReset() {
throw new UnsupportedOperationException();
}
}
private void doTest(byte[] data, LZ4.HashTable hashTable) throws IOException { private void doTest(byte[] data, LZ4.HashTable hashTable) throws IOException {
int offset = random().nextBoolean() int offset = random().nextBoolean()
? random().nextInt(10) ? random().nextInt(10)

View File

@ -22,7 +22,8 @@ public class TestFastLZ4 extends LZ4TestCase {
@Override @Override
protected HashTable newHashTable() { protected HashTable newHashTable() {
return new LZ4.FastCompressionHashTable(); LZ4.HashTable hashTable = new LZ4.FastCompressionHashTable();
return new AssertingHashTable(hashTable);
} }
} }

View File

@ -22,7 +22,8 @@ public class TestHighLZ4 extends LZ4TestCase {
@Override @Override
protected HashTable newHashTable() { protected HashTable newHashTable() {
return new LZ4.HighCompressionHashTable(); LZ4.HashTable hashTable = new LZ4.HighCompressionHashTable();
return new AssertingHashTable(hashTable);
} }
} }