Skip to content

Commit

Permalink
add outers/inners filter + slight adjustment to vertices filter
Browse files Browse the repository at this point in the history
  • Loading branch information
tyrasd committed Nov 25, 2021
1 parent c9a3d08 commit aaccc30
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ public FilterParser(TagTranslator tt, boolean allowContributorFilters) {
final Parser<Void> length = Patterns.string("length").toScanner("length");
final Parser<Void> perimeter = Patterns.string("perimeter").toScanner("perimeter");
final Parser<Void> vertices = Patterns.string("vertices").toScanner("vertices");
final Parser<Void> outers = Patterns.string("outers").toScanner("outers");
final Parser<Void> inners = Patterns.string("inners").toScanner("inners");
final Parser<Void> changeset = Patterns.string("changeset").toScanner("changeset");
final Parser<Void> contributor = Patterns.string("contributor").toScanner("contributor");

Expand Down Expand Up @@ -208,15 +210,15 @@ public FilterParser(TagTranslator tt, boolean allowContributorFilters) {
),
Scanners.isChar(')')
);
final Parser<ValueRange> decimalRange = Parsers.between(
final Parser<ValueRange> positiveIntegerRange = Parsers.between(
Scanners.isChar('('),
Parsers.or(
Parsers.sequence(number, dotdot, number,
(min, ignored, max) -> new ValueRange(min, max)),
number.followedBy(dotdot).map(
min -> new ValueRange(min, Double.POSITIVE_INFINITY)),
Parsers.sequence(dotdot, number).map(
max -> new ValueRange(Double.NEGATIVE_INFINITY, max))
max -> new ValueRange(0, max))
),
Scanners.isChar(')')
);
Expand All @@ -230,13 +232,21 @@ public FilterParser(TagTranslator tt, boolean allowContributorFilters) {
perimeter, colon, floatingRange
).map(GeometryFilterPerimeter::new);
final Parser<GeometryFilter> geometryFilterVertices = Parsers.sequence(
vertices, colon, decimalRange
vertices, colon, positiveIntegerRange
).map(GeometryFilterVertices::new);
final Parser<GeometryFilter> geometryFilterOuters = Parsers.sequence(
outers, colon, Parsers.or(positiveIntegerRange, number.map(n -> new ValueRange(n, n)))
).map(GeometryFilterOuterRings::new);
final Parser<GeometryFilter> geometryFilterInners = Parsers.sequence(
inners, colon, Parsers.or(positiveIntegerRange, number.map(n -> new ValueRange(n, n)))
).map(GeometryFilterInnerRings::new);
final Parser<GeometryFilter> geometryFilter = Parsers.or(
geometryFilterArea,
geometryFilterLength,
geometryFilterPerimeter,
geometryFilterVertices);
geometryFilterVertices,
geometryFilterOuters,
geometryFilterInners);

// changeset id filters
final Parser<ChangesetIdFilterEquals> changesetIdFilter = Parsers.sequence(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.heigit.ohsome.oshdb.filter;

import javax.annotation.Nonnull;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Polygon;

/**
* A filter which checks the number of inner rings of a multipolygon relation.
*/
public class GeometryFilterInnerRings extends GeometryFilter {
/**
* Creates a new inner rings filter object.
*
* @param range the allowed range (inclusive) of values to pass the filter
*/
public GeometryFilterInnerRings(@Nonnull ValueRange range) {
super(range, GeometryMetricEvaluator.fromLambda(geometry -> {
if (geometry instanceof Polygon) {
return ((Polygon) geometry).getNumInteriorRing();
} else if (geometry instanceof MultiPolygon) {
var counter = 0;
for (var i = 0; i < geometry.getNumGeometries(); i++) {
counter += ((Polygon) geometry.getGeometryN(i)).getNumInteriorRing();
}
return counter;
} else {
return -1;
}
}, "outers"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.heigit.ohsome.oshdb.filter;

import javax.annotation.Nonnull;
import org.locationtech.jts.geom.Polygonal;

/**
* A filter which checks the number of outer rings of a multipolygon relation.
*/
public class GeometryFilterOuterRings extends GeometryFilter {
/**
* Creates a new outer rings filter object.
*
* @param range the allowed range (inclusive) of values to pass the filter
*/
public GeometryFilterOuterRings(@Nonnull ValueRange range) {
super(range, GeometryMetricEvaluator.fromLambda(geometry ->
geometry instanceof Polygonal ? geometry.getNumGeometries() : -1,
"outers"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
* A filter which checks the perimeter of polygonal OSM feature geometries.
*/
public class GeometryFilterPerimeter extends GeometryFilter {
/**
* Creates a new perimeter filter object.
*
* @param range the allowed range (inclusive) of values to pass the filter
*/
public GeometryFilterPerimeter(@Nonnull ValueRange range) {
super(range, GeometryMetricEvaluator.fromLambda(geometry -> {
if (!(geometry instanceof Polygonal)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public FilterExpression negate() {
throw new IllegalStateException("Invalid call of inner negate() on a negatable filter");
}

/** Inverse of {@link FilterExpression#applyOSH(OSHEntity)} */
/** Inverse of {@link FilterExpression#applyOSH(OSHEntity)}. */
@Contract(pure = true)
boolean applyOSHNegated(OSHEntity entity) {
return true;
Expand All @@ -32,7 +32,7 @@ public boolean applyOSM(OSMEntity entity) {
return true;
}

/** Inverse of {@link FilterExpression#applyOSM(OSMEntity)} */
/** Inverse of {@link FilterExpression#applyOSM(OSMEntity)}. */
@Contract(pure = true)
boolean applyOSMNegated(OSMEntity entity) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ public void testGeometryFilterPerimeter() {
@Test
public void testGeometryFilterVertices() {
FilterExpression expression = parser.parse("vertices:(11..13)");
// point
assertFalse(expression.applyOSMGeometry(
createTestOSMEntityNode("natural", "tree"),
gf.createPoint(new Coordinate(0, 0))));
// lines
BiConsumer<Integer, Consumer<Boolean>> testLineN = (n, tester) -> {
var entity = createTestOSMEntityWay(LongStream.rangeClosed(1, n).toArray());
Expand Down Expand Up @@ -261,6 +265,61 @@ public void testGeometryFilterVertices() {
testMultiPolyonN.accept(12, Assert::assertTrue);
testMultiPolyonN.accept(13, Assert::assertTrue);
testMultiPolyonN.accept(14, Assert::assertFalse);
}

@Test
public void testGeometryFilterOuters() {
FilterExpression expression = parser.parse("outers:1");
OSMEntity entity = createTestOSMEntityRelation("type", "multipolygon");
assertFalse(expression.applyOSMGeometry(entity, gf.createMultiPolygon(new Polygon[] {
OSHDBGeometryBuilder.getGeometry(OSHDBBoundingBox.bboxWgs84Coordinates(1, 1, 2, 2)),
OSHDBGeometryBuilder.getGeometry(OSHDBBoundingBox.bboxWgs84Coordinates(3, 3, 4, 4))
})));
assertTrue(expression.applyOSMGeometry(entity, gf.createMultiPolygon(new Polygon[] {
OSHDBGeometryBuilder.getGeometry(OSHDBBoundingBox.bboxWgs84Coordinates(1, 1, 2, 2))
})));
assertTrue(expression.applyOSMGeometry(entity,
OSHDBGeometryBuilder.getGeometry(OSHDBBoundingBox.bboxWgs84Coordinates(1, 1, 2, 2))
));
// range
expression = parser.parse("outers:(2..)");
assertTrue(expression.applyOSMGeometry(entity, gf.createMultiPolygon(new Polygon[] {
OSHDBGeometryBuilder.getGeometry(OSHDBBoundingBox.bboxWgs84Coordinates(1, 1, 2, 2)),
OSHDBGeometryBuilder.getGeometry(OSHDBBoundingBox.bboxWgs84Coordinates(3, 3, 4, 4))
})));
}

@Test
public void testGeometryFilterInners() {
FilterExpression expression = parser.parse("inners:0");
OSMEntity entity = createTestOSMEntityRelation("type", "multipolygon");
assertTrue(expression.applyOSMGeometry(entity,
OSHDBGeometryBuilder.getGeometry(OSHDBBoundingBox.bboxWgs84Coordinates(1, 1, 2, 2))
));
assertFalse(expression.applyOSMGeometry(entity, gf.createPolygon(
OSHDBGeometryBuilder.getGeometry(
OSHDBBoundingBox.bboxWgs84Coordinates(0, 0, 10, 10)).getExteriorRing(),
new LinearRing[] { OSHDBGeometryBuilder.getGeometry(
OSHDBBoundingBox.bboxWgs84Coordinates(1, 1, 2, 2)).getExteriorRing()
})));
assertTrue(expression.applyOSMGeometry(entity, gf.createMultiPolygon(new Polygon[] {
OSHDBGeometryBuilder.getGeometry(OSHDBBoundingBox.bboxWgs84Coordinates(1, 1, 2, 2))
})));
assertFalse(expression.applyOSMGeometry(entity, gf.createMultiPolygon(new Polygon[] {
gf.createPolygon(
OSHDBGeometryBuilder.getGeometry(
OSHDBBoundingBox.bboxWgs84Coordinates(0, 0, 10, 10)).getExteriorRing(),
new LinearRing[] { OSHDBGeometryBuilder.getGeometry(
OSHDBBoundingBox.bboxWgs84Coordinates(1, 1, 2, 2)).getExteriorRing()
})
})));
// range
expression = parser.parse("inners:(1..)");
assertTrue(expression.applyOSMGeometry(entity, gf.createPolygon(
OSHDBGeometryBuilder.getGeometry(
OSHDBBoundingBox.bboxWgs84Coordinates(0, 0, 10, 10)).getExteriorRing(),
new LinearRing[] { OSHDBGeometryBuilder.getGeometry(
OSHDBBoundingBox.bboxWgs84Coordinates(1, 1, 2, 2)).getExteriorRing()
})));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,28 @@ public void testGeometryFilterPerimeter() {
assertTrue(expression instanceof GeometryFilterPerimeter);
}

@Test
public void testGeometryFilterVertices() {
FilterExpression expression = parser.parse("vertices:(1..10)");
assertTrue(expression instanceof GeometryFilterVertices);
}

@Test
public void testGeometryFilterOuters() {
FilterExpression expression = parser.parse("outers:2");
assertTrue(expression instanceof GeometryFilterOuterRings);
expression = parser.parse("outers:(1..10)");
assertTrue(expression instanceof GeometryFilterOuterRings);
}

@Test
public void testGeometryFilterInners() {
FilterExpression expression = parser.parse("inners:0");
assertTrue(expression instanceof GeometryFilterInnerRings);
expression = parser.parse("inners:(1..10)");
assertTrue(expression instanceof GeometryFilterInnerRings);
}

@Test
public void testChangesetIdFilter() {
FilterExpression expression = parser.parse("changeset:42");
Expand Down

0 comments on commit aaccc30

Please sign in to comment.