Skip to content

Commit

Permalink
Add randomized shape GeometryTree tests
Browse files Browse the repository at this point in the history
The tests is disabled at the moment since it fails regularly.

Relates elastic#37206
  • Loading branch information
imotov committed Nov 14, 2019
1 parent 0ad1b36 commit bdb181c
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,25 @@
package org.elasticsearch.common.geo;

import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.geo.GeometryTestUtils;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.geometry.Line;
import org.elasticsearch.geometry.LinearRing;
import org.elasticsearch.geometry.MultiPoint;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.mapper.GeoShapeIndexer;
import org.elasticsearch.test.ESTestCase;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;

import static org.elasticsearch.geo.GeometryTestUtils.fold;
import static org.elasticsearch.geo.GeometryTestUtils.randomPoint;
import static org.hamcrest.Matchers.equalTo;

public class GeometryTreeTests extends ESTestCase {
Expand All @@ -56,8 +61,8 @@ public void testRectangleShape() throws IOException {

assertThat(Extent.fromPoints(minX, minY, maxX, maxY), equalTo(reader.getExtent()));
// encoder loses precision when casting to integer, so centroid is calculated using integer division here
assertThat(reader.getCentroidX(), equalTo((double) ((minX + maxX)/2)));
assertThat(reader.getCentroidY(), equalTo((double) ((minY + maxY)/2)));
assertThat(reader.getCentroidX(), equalTo((double) ((minX + maxX) / 2)));
assertThat(reader.getCentroidY(), equalTo((double) ((minY + maxY) / 2)));

// box-query touches bottom-left corner
assertTrue(reader.intersects(Extent.fromPoints(minX - randomIntBetween(1, 10), minY - randomIntBetween(1, 10), minX, minY)));
Expand Down Expand Up @@ -117,8 +122,8 @@ public void testPacManPolygon() throws Exception {

// adapted from org.apache.lucene.geo.TestPolygon2D#testMultiPolygon
public void testPolygonWithHole() throws Exception {
Polygon polyWithHole = new Polygon(new LinearRing(new double[] { -50, 50, 50, -50, -50 }, new double[] { -50, -50, 50, 50, -50 }),
Collections.singletonList(new LinearRing(new double[] { -10, 10, 10, -10, -10 }, new double[] { -10, -10, 10, 10, -10 })));
Polygon polyWithHole = new Polygon(new LinearRing(new double[]{-50, 50, 50, -50, -50}, new double[]{-50, -50, 50, 50, -50}),
Collections.singletonList(new LinearRing(new double[]{-10, 10, 10, -10, -10}, new double[]{-10, -10, 10, 10, -10})));

GeometryTreeWriter writer = new GeometryTreeWriter(polyWithHole, TestCoordinateEncoder.INSTANCE);
BytesStreamOutput output = new BytesStreamOutput();
Expand All @@ -135,13 +140,13 @@ public void testPolygonWithHole() throws Exception {
}

public void testCombPolygon() throws Exception {
double[] px = {0, 10, 10, 20, 20, 30, 30, 40, 40, 50, 50, 0, 0};
double[] py = {0, 0, 20, 20, 0, 0, 20, 20, 0, 0, 30, 30, 0};
double[] px = {0, 10, 10, 20, 20, 30, 30, 40, 40, 50, 50, 0, 0};
double[] py = {0, 0, 20, 20, 0, 0, 20, 20, 0, 0, 30, 30, 0};

double[] hx = {21, 21, 29, 29, 21};
double[] hy = {1, 20, 20, 1, 1};

Polygon polyWithHole = new Polygon(new LinearRing(px, py), Collections.singletonList(new LinearRing(hx, hy)));
Polygon polyWithHole = new Polygon(new LinearRing(px, py), Collections.singletonList(new LinearRing(hx, hy)));
// test cell crossing poly
GeometryTreeWriter writer = new GeometryTreeWriter(polyWithHole, TestCoordinateEncoder.INSTANCE);
BytesStreamOutput output = new BytesStreamOutput();
Expand Down Expand Up @@ -217,4 +222,53 @@ public void testPacManPoints() throws Exception {
GeometryTreeReader reader = new GeometryTreeReader(output.bytes().toBytesRef(), TestCoordinateEncoder.INSTANCE);
assertTrue(reader.intersects(Extent.fromPoints(xMin, yMin, xMax, yMax)));
}

@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/37206")
public void testRandomGeometryIntersection() throws IOException {
int testPointCount = randomIntBetween(100, 200);
Point[] testPoints = new Point[testPointCount];
double extentSize = randomDoubleBetween(1, 10, true);
boolean[] intersects = new boolean[testPointCount];
for (int i = 0; i < testPoints.length; i++) {
testPoints[i] = randomPoint(false);
}

Geometry geometry = randomGeometryTreeGeometry();
GeoShapeIndexer indexer = new GeoShapeIndexer(true, "test");
geometry = indexer.prepareForIndexing(geometry);

for (int i = 0; i < testPointCount; i++) {
int cur = i;
intersects[cur] = fold(geometry, false, (g, s) -> s || intersects(g, testPoints[cur], extentSize));
}

for (int i = 0; i < testPointCount; i++) {
assertEquals(intersects[i], intersects(geometry, testPoints[i], extentSize));
}
}

private boolean intersects(Geometry g, Point p, double extentSize) throws IOException {
// TODO: Make this independent from GeometryTree
GeometryTreeWriter writer = new GeometryTreeWriter(g, GeoShapeCoordinateEncoder.INSTANCE);
BytesStreamOutput output = new BytesStreamOutput();
writer.writeTo(output);
output.close();
int xMin = GeoShapeCoordinateEncoder.INSTANCE.encodeX(Math.max(p.getX() - extentSize, -180.0));
int xMax = GeoShapeCoordinateEncoder.INSTANCE.encodeX(Math.min(p.getX() + extentSize, 180.0));
int yMin = GeoShapeCoordinateEncoder.INSTANCE.encodeY(Math.max(p.getY() - extentSize, -90));
int yMax = GeoShapeCoordinateEncoder.INSTANCE.encodeY(Math.min(p.getY() + extentSize, 90));
GeometryTreeReader reader = new GeometryTreeReader(output.bytes().toBytesRef(), GeoShapeCoordinateEncoder.INSTANCE);
return reader.intersects(Extent.fromPoints(xMin, yMin, xMax, yMax));
}

private static Geometry randomGeometryTreeGeometry() {
@SuppressWarnings("unchecked") Function<Boolean, Geometry> geometry = ESTestCase.randomFrom(
GeometryTestUtils::randomLine,
GeometryTestUtils::randomPoint,
GeometryTestUtils::randomPolygon,
GeometryTestUtils::randomMultiLine,
GeometryTestUtils::randomMultiPoint
);
return geometry.apply(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.elasticsearch.geo;

import org.apache.lucene.geo.GeoTestUtil;
import org.elasticsearch.common.CheckedBiFunction;
import org.elasticsearch.geometry.Circle;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.geometry.GeometryCollection;
Expand Down Expand Up @@ -258,4 +259,66 @@ public MultiPoint visit(Rectangle rectangle) throws RuntimeException {
}
});
}

/**
* Preforms left fold operation on all primitive geometries (points, lines polygons, circles and rectangles).
* All collection geometries are iterated depth first.
*/
public static <R, E extends Exception> R fold(Geometry geometry, R state, CheckedBiFunction<Geometry, R, R, E> operation) throws E {
return geometry.visit(new GeometryVisitor<R, E>() {
@Override
public R visit(Circle circle) throws E {
return operation.apply(geometry, state);
}

@Override
public R visit(GeometryCollection<?> collection) throws E {
R ret = state;
for (Geometry g : collection) {
ret = fold(g, ret, operation);
}
return ret;
}

@Override
public R visit(Line line) throws E {
return operation.apply(line, state);
}

@Override
public R visit(LinearRing ring) throws E {
return operation.apply(ring, state);
}

@Override
public R visit(MultiLine multiLine) throws E {
return visit((GeometryCollection<?>) multiLine);
}

@Override
public R visit(MultiPoint multiPoint) throws E {
return visit((GeometryCollection<?>) multiPoint); }

@Override
public R visit(MultiPolygon multiPolygon) throws E {
return visit((GeometryCollection<?>) multiPolygon);
}

@Override
public R visit(Point point) throws E {
return operation.apply(point, state);
}

@Override
public R visit(Polygon polygon) throws E {
return operation.apply(polygon, state);
}

@Override
public R visit(Rectangle rectangle) throws E {
return operation.apply(rectangle, state);
}
});
}

}

0 comments on commit bdb181c

Please sign in to comment.