Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling indexed envelopes crossing the dateline in mvt API #91105

Merged
merged 5 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/changelog/91105.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 91105
summary: Fix handling indexed envelopes crossing the dateline in mvt API
area: Geo
type: bug
issues:
- 91060
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,61 @@ private Geometry normalize(Geometry geometry) {
}
}

public void testFetchSourceValueDateLine() throws IOException {
public void testFetchSourcePolygonDateLine() throws IOException {
assertFetchSourceGeometry(
"POLYGON((170 -10, -170 -10, -170 10, 170 10, 170 -10))",
"MULTIPOLYGON (((180.0 -10.0, 180.0 10.0, 170.0 10.0, 170.0 -10.0, 180.0 -10.0)),"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious why the polygon test has a single polygon split to a multipolygon by the function:

fetchSourceValue(mapper, sourceValue, "wkt")

But the BBOX is not split by the same function in the envelope test?

Perhaps this is not part of this PR, since this PR focuses on MVT, and the MVT call:

fetchSourceValue(mapper, sourceValue, "mvt(0/0/0@4096)")

Does seem to split both the polygon and the envelope.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about the same. The didn't like the options I had to return a split geometry. Either return a multipolygon which didn't feel right for an input envelope, or a geometry collection containing two envelopes which I did not like it either.

Therefore I decided to return it unchanged. We can visit it later if it dies not feel right.

+ "((-180.0 10.0, -180.0 -10.0, -170.0 -10.0, -170.0 10.0, -180.0 10.0)))",
Map.of(
"type",
"MultiPolygon",
"coordinates",
List.of(
List.of(
List.of(
List.of(180.0, -10.0),
List.of(180.0, 10.0),
List.of(170.0, 10.0),
List.of(170.0, -10.0),
List.of(180.0, -10.0)
)
),
List.of(
List.of(
List.of(-180.0, 10.0),
List.of(-180.0, -10.0),
List.of(-170.0, -10.0),
List.of(-170.0, 10.0),
List.of(-180.0, 10.0)
)
)
)
),
"MULTIPOLYGON (((180.0 -10.0, 180.0 10.0, 170.0 10.0, 170.0 -10.0, 180.0 -10.0)),"
+ "((-180.0 10.0, -180.0 -10.0, -170.0 -10.0, -170.0 10.0, -180.0 10.0)))"
);
}

public void testFetchSourceEnvelope() throws IOException {
assertFetchSourceGeometry(
"BBOX(-10, 10, 10, -10)",
"BBOX (-10.0, 10.0, 10.0, -10.0)",
Map.of("type", "Envelope", "coordinates", List.of(List.of(-10.0, 10.0), List.of(10.0, -10.0))),
"POLYGON ((-10 -10, 10 -10, 10 10, -10 10, -10 -10)))"
);
}

public void testFetchSourceEnvelopeDateLine() throws IOException {
assertFetchSourceGeometry(
"BBOX(10, -10, 10, -10)",
"BBOX (10.0, -10.0, 10.0, -10.0)",
Map.of("type", "Envelope", "coordinates", List.of(List.of(10.0, 10.0), List.of(-10.0, -10.0))),
"MULTIPOLYGON (((-180 -10, -10 -10, -10 10, -180 10, -180 -10)), ((10 -10, 180 -10, 180 10, 10 10, 10 -10)))"
);
}

private void assertFetchSourceGeometry(Object sourceValue, String wktValue, Map<String, Object> jsonValue, String mvtEquivalentAsWKT)
throws IOException {
final GeoFormatterFactory<Geometry> geoFormatterFactory = new GeoFormatterFactory<>(
new SpatialGeometryFormatterExtension().getGeometryFormatterFactories()
);
Expand All @@ -161,38 +215,12 @@ public void testFetchSourceValueDateLine() throws IOException {
false,
geoFormatterFactory
).build(MapperBuilderContext.ROOT).fieldType();
// Test a polygon crossing the dateline
Object sourceValue = "POLYGON((170 -10, -170 -10, -170 10, 170 10, 170 -10))";
String polygonDateLine = "MULTIPOLYGON (((180.0 -10.0, 180.0 10.0, 170.0 10.0, 170.0 -10.0, 180.0 -10.0)),"
+ "((-180.0 10.0, -180.0 -10.0, -170.0 -10.0, -170.0 10.0, -180.0 10.0)))";
Map<String, Object> jsonPolygonDateLine = Map.of(
"type",
"MultiPolygon",
"coordinates",
List.of(
List.of(
List.of(List.of(180.0, -10.0), List.of(180.0, 10.0), List.of(170.0, 10.0), List.of(170.0, -10.0), List.of(180.0, -10.0))
),
List.of(
List.of(
List.of(-180.0, 10.0),
List.of(-180.0, -10.0),
List.of(-170.0, -10.0),
List.of(-170.0, 10.0),
List.of(-180.0, 10.0)
)
)
)
);

assertEquals(List.of(jsonPolygonDateLine), fetchSourceValue(mapper, sourceValue, null));
assertEquals(List.of(polygonDateLine), fetchSourceValue(mapper, sourceValue, "wkt"));

String mvtPolygonDateLine = "MULTIPOLYGON (((180.0 -10.0, 180.0 10.0, 170.0 10.0, 170.0 -10.0, 180.0 -10.0)),"
+ "((-180.0 10.0, -180.0 -10.0, -170.0 -10.0, -170.0 10.0, -180.0 10.0)))";
assertEquals(List.of(jsonValue), fetchSourceValue(mapper, sourceValue, null));
assertEquals(List.of(wktValue), fetchSourceValue(mapper, sourceValue, "wkt"));

List<?> mvtExpected = fetchSourceValue(mapper, mvtPolygonDateLine, "mvt(0/0/0@256)");
List<?> mvt = fetchSourceValue(mapper, sourceValue, "mvt(0/0/0@256)");
List<?> mvtExpected = fetchSourceValue(mapper, mvtEquivalentAsWKT, "mvt(0/0/0@4096)");
List<?> mvt = fetchSourceValue(mapper, sourceValue, "mvt(0/0/0@4096)");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests still pass with the original @256, what was the reason for changing to @4096? I presume it was just to match the default value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's weird, I changed it so the extent is random.

assertThat(mvt.size(), Matchers.equalTo(1));
assertThat(mvt.size(), Matchers.equalTo(mvtExpected.size()));
assertThat(mvtExpected.get(0), Matchers.instanceOf(byte[].class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,15 @@ public org.locationtech.jts.geom.Geometry visit(Rectangle rectangle) throws Runt
final double yMin = SphericalMercatorUtils.latToSphericalMercator(rectangle.getMinY());
final double xMax = SphericalMercatorUtils.lonToSphericalMercator(rectangle.getMaxX());
final double yMax = SphericalMercatorUtils.latToSphericalMercator(rectangle.getMaxY());
final Envelope envelope = new Envelope(xMin, xMax, yMin, yMax);
return geomFactory.toGeometry(envelope);
if (rectangle.getMinX() > rectangle.getMaxX()) {
// crosses dateline
final Envelope westEnvelope = new Envelope(-SphericalMercatorUtils.MERCATOR_BOUNDS, xMax, yMin, yMax);
final Envelope eastEnvelope = new Envelope(xMin, SphericalMercatorUtils.MERCATOR_BOUNDS, yMin, yMax);
return geomFactory.buildGeometry(List.of(geomFactory.toGeometry(westEnvelope), geomFactory.toGeometry(eastEnvelope)));
} else {
final Envelope envelope = new Envelope(xMin, xMax, yMin, yMax);
return geomFactory.toGeometry(envelope);
}
}
}

Expand Down