Check for degenerated lines when calculating the centroid (#58216)

This commit is contained in:
Ignacio Vera 2020-06-17 09:34:49 +02:00 committed by GitHub
parent b22e91cefc
commit 7080ba5b05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 25 deletions

View File

@ -224,18 +224,18 @@ public class CentroidCalculator {
@Override @Override
public Void visit(Rectangle rectangle) { public Void visit(Rectangle rectangle) {
double sumX = rectangle.getMaxX() + rectangle.getMinX();
double sumY = rectangle.getMaxY() + rectangle.getMinY();
double diffX = rectangle.getMaxX() - rectangle.getMinX(); double diffX = rectangle.getMaxX() - rectangle.getMinX();
double diffY = rectangle.getMaxY() - rectangle.getMinY(); double diffY = rectangle.getMaxY() - rectangle.getMinY();
if (diffX != 0 && diffY != 0) { double rectWeight = Math.abs(diffX * diffY);
calculator.addCoordinate(sumX / 2, sumY / 2, Math.abs(diffX * diffY), DimensionalShapeType.POLYGON); if (rectWeight != 0) {
} else if (diffX != 0) { double sumX = rectangle.getMaxX() + rectangle.getMinX();
calculator.addCoordinate(sumX / 2, rectangle.getMinY(), diffX, DimensionalShapeType.LINE); double sumY = rectangle.getMaxY() + rectangle.getMinY();
} else if (diffY != 0) { calculator.addCoordinate(sumX / 2, sumY / 2, rectWeight, DimensionalShapeType.POLYGON);
calculator.addCoordinate(rectangle.getMinX(), sumY / 2, diffY, DimensionalShapeType.LINE);
} else { } else {
visitPoint(rectangle.getMinX(), rectangle.getMinY()); // degenerated rectangle, transform to Line
Line line = new Line(new double[]{rectangle.getMinX(), rectangle.getMaxX()},
new double[]{rectangle.getMinY(), rectangle.getMaxY()});
visit(line);
} }
return null; return null;
} }
@ -246,22 +246,20 @@ public class CentroidCalculator {
} }
private void visitLine(int length, CoordinateSupplier x, CoordinateSupplier y) { private void visitLine(int length, CoordinateSupplier x, CoordinateSupplier y) {
// check line has length // a line's centroid is calculated by summing the center of each
double originDiffX = x.get(0) - x.get(1); // line segment weighted by the line segment's length in degrees
double originDiffY = y.get(0) - y.get(1); for (int i = 0; i < length - 1; i++) {
if (originDiffX != 0 || originDiffY != 0) { double diffX = x.get(i) - x.get(i + 1);
// a line's centroid is calculated by summing the center of each double diffY = y.get(i) - y.get(i + 1);
// line segment weighted by the line segment's length in degrees double xAvg = (x.get(i) + x.get(i + 1)) / 2;
for (int i = 0; i < length - 1; i++) { double yAvg = (y.get(i) + y.get(i + 1)) / 2;
double diffX = x.get(i) - x.get(i + 1); double weight = Math.sqrt(diffX * diffX + diffY * diffY);
double diffY = y.get(i) - y.get(i + 1); if (weight == 0) {
double xAvg = (x.get(i) + x.get(i + 1)) / 2; // degenerated line, it can be considered a point
double yAvg = (y.get(i) + y.get(i + 1)) / 2; visitPoint(x.get(i), y.get(i));
double weight = Math.sqrt(diffX * diffX + diffY * diffY); } else {
calculator.addCoordinate(xAvg, yAvg, weight, DimensionalShapeType.LINE); calculator.addCoordinate(xAvg, yAvg, weight, DimensionalShapeType.LINE);
} }
} else {
visitPoint(x.get(0), y.get(0));
} }
} }

View File

@ -31,6 +31,7 @@ import static org.elasticsearch.xpack.spatial.index.fielddata.DimensionalShapeTy
import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.closeTo; import static org.hamcrest.Matchers.closeTo;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
public class CentroidCalculatorTests extends ESTestCase { public class CentroidCalculatorTests extends ESTestCase {
private static final double DELTA = 0.000000001; private static final double DELTA = 0.000000001;
@ -190,6 +191,13 @@ public class CentroidCalculatorTests extends ESTestCase {
} }
} }
public void testRectangle() {
for (int i = 0; i < 100; i++) {
CentroidCalculator calculator = new CentroidCalculator(GeometryTestUtils.randomRectangle());
assertThat(calculator.sumWeight(), greaterThan(0.0));
}
}
public void testLineAsClosedPoint() { public void testLineAsClosedPoint() {
double lon = GeometryTestUtils.randomLon(); double lon = GeometryTestUtils.randomLon();
double lat = GeometryTestUtils.randomLat(); double lat = GeometryTestUtils.randomLat();
@ -250,7 +258,7 @@ public class CentroidCalculatorTests extends ESTestCase {
CentroidCalculator calculator = new CentroidCalculator(polygon); CentroidCalculator calculator = new CentroidCalculator(polygon);
assertThat(calculator.getX(), equalTo(GeoUtils.normalizeLon(point.getX()))); assertThat(calculator.getX(), equalTo(GeoUtils.normalizeLon(point.getX())));
assertThat(calculator.getY(), equalTo(GeoUtils.normalizeLat(point.getY()))); assertThat(calculator.getY(), equalTo(GeoUtils.normalizeLat(point.getY())));
assertThat(calculator.sumWeight(), equalTo(1.0)); assertThat(calculator.sumWeight(), equalTo(3.0));
assertThat(calculator.getDimensionalShapeType(), equalTo(POINT)); assertThat(calculator.getDimensionalShapeType(), equalTo(POINT));
} }

View File

@ -255,7 +255,6 @@ public class TriangleTreeTests extends ESTestCase {
assertRelation(GeoRelation.QUERY_CROSSES, reader, getExtentFromBox(xMin, yMin, xMax, yMax)); assertRelation(GeoRelation.QUERY_CROSSES, reader, getExtentFromBox(xMin, yMin, xMax, yMax));
} }
@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/56755")
public void testRandomMultiLineIntersections() throws IOException { public void testRandomMultiLineIntersections() throws IOException {
GeoShapeIndexer indexer = new GeoShapeIndexer(true, "test"); GeoShapeIndexer indexer = new GeoShapeIndexer(true, "test");
MultiLine geometry = randomMultiLine(false); MultiLine geometry = randomMultiLine(false);