forked from osmlab/atlas-checks
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* InvalidGeometryCheck * docs * better refactor
- Loading branch information
Showing
9 changed files
with
392 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Invalid Geometry Check | ||
|
||
#### Description | ||
|
||
This check flags invalid polyline and polygon geometries. | ||
|
||
#### Live Example | ||
|
||
The Way [id:803496316](https://www.openstreetmap.org/way/803496316) is an invalid self intersecting polygon. | ||
|
||
#### Code Review | ||
|
||
This check looks at three types of Atlas Items: [Areas](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Area.java), [Edges](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Edge.java), and [Lines](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Line.java). | ||
A feature is considered valid for the check if it is one of those types and has not been country sliced. | ||
|
||
Geometries are validated using the [Java Topology Suite](https://github.com/locationtech/jts) (JTS). | ||
The Atlas geometries are converted to JTS geometries. | ||
If a features fails to pass the JTS geometry `.isSimple()` or `.isValid()` methods then it is flagged. | ||
|
||
To learn more about the code, please look at the comments in the source code for the check. | ||
[InvalidGeometryCheck.java](../../src/main/java/org/openstreetmap/atlas/checks/validation/geometry/InvalidGeometryCheck.java) |
73 changes: 52 additions & 21 deletions
73
src/main/java/org/openstreetmap/atlas/checks/validation/GeometryValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
src/main/java/org/openstreetmap/atlas/checks/validation/geometry/InvalidGeometryCheck.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package org.openstreetmap.atlas.checks.validation.geometry; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import org.openstreetmap.atlas.checks.base.BaseCheck; | ||
import org.openstreetmap.atlas.checks.flag.CheckFlag; | ||
import org.openstreetmap.atlas.checks.validation.GeometryValidator; | ||
import org.openstreetmap.atlas.geography.atlas.items.Area; | ||
import org.openstreetmap.atlas.geography.atlas.items.AtlasItem; | ||
import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; | ||
import org.openstreetmap.atlas.geography.atlas.items.Edge; | ||
import org.openstreetmap.atlas.geography.atlas.items.LineItem; | ||
import org.openstreetmap.atlas.tags.SyntheticBoundaryNodeTag; | ||
import org.openstreetmap.atlas.tags.SyntheticGeometrySlicedTag; | ||
import org.openstreetmap.atlas.utilities.configuration.Configuration; | ||
|
||
/** | ||
* Checks Atlas items using {@link org.locationtech.jts.geom.Geometry} isValid and isSimple methods. | ||
* Generates flag based on JTS provided invalidity and non simplicity causes. | ||
* | ||
* @author jklamer | ||
* @author bbreithaupt | ||
*/ | ||
public class InvalidGeometryCheck extends BaseCheck<Long> | ||
{ | ||
private static final String NOT_SIMPLE_TEMPLATE = "Geometry is Not Simple: {0}. "; | ||
private static final String NOT_VALID_TEMPLATE = "Geometry is Not Valid: {0}. "; | ||
private static final List<String> FALLBACK_INSTRUCTIONS = Arrays.asList(NOT_SIMPLE_TEMPLATE, | ||
NOT_VALID_TEMPLATE); | ||
private static final long serialVersionUID = 4212714363153085279L; | ||
|
||
public InvalidGeometryCheck(final Configuration configuration) | ||
{ | ||
super(configuration); | ||
} | ||
|
||
@Override | ||
public boolean validCheckForObject(final AtlasObject object) | ||
{ | ||
return (object instanceof Area || object instanceof LineItem) | ||
&& !SyntheticGeometrySlicedTag.isGeometrySliced(object) | ||
&& !(object instanceof Edge && ((Edge) object).connectedNodes().stream() | ||
.anyMatch(SyntheticBoundaryNodeTag::isBoundaryNode)); | ||
} | ||
|
||
@Override | ||
protected Optional<CheckFlag> flag(final AtlasObject object) | ||
{ | ||
final List<String> instructions = new ArrayList<>(); | ||
|
||
// check if simple if not a LineItem (too many correct in OSM but not simple linear | ||
// geometries) | ||
final Optional<String> simpleTest = object instanceof LineItem ? Optional.empty() | ||
: GeometryValidator.testSimplicity(((AtlasItem) object).getRawGeometry()); | ||
// check if valid | ||
final Optional<String> validTest = GeometryValidator | ||
.testValidity(((AtlasItem) object).getRawGeometry()); | ||
|
||
simpleTest.ifPresent(reason -> instructions.add(this.getLocalizedInstruction(0, reason))); | ||
validTest.ifPresent(reason -> instructions.add(this.getLocalizedInstruction(1, reason))); | ||
|
||
return instructions.isEmpty() ? Optional.empty() | ||
: Optional.of(new CheckFlag(this.getTaskIdentifier(object), | ||
Collections.singleton(object), instructions)); | ||
} | ||
|
||
@Override | ||
protected List<String> getFallbackInstructions() | ||
{ | ||
return FALLBACK_INSTRUCTIONS; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
...est/java/org/openstreetmap/atlas/checks/validation/geometry/InvalidGeometryCheckTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package org.openstreetmap.atlas.checks.validation.geometry; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.openstreetmap.atlas.checks.configuration.ConfigurationResolver; | ||
import org.openstreetmap.atlas.checks.validation.verifier.ConsumerBasedExpectedCheckVerifier; | ||
import org.openstreetmap.atlas.utilities.configuration.Configuration; | ||
|
||
/** | ||
* Test class for {@link InvalidGeometryCheck} | ||
* | ||
* @author jklamer | ||
* @author bbreithaupt | ||
*/ | ||
public class InvalidGeometryCheckTest | ||
{ | ||
|
||
@Rule | ||
public InvalidGeometryCheckTestRule setup = new InvalidGeometryCheckTestRule(); | ||
@Rule | ||
public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier(); | ||
private final Configuration configuration = ConfigurationResolver.emptyConfiguration(); | ||
|
||
@Test | ||
public void borderSlicedPolygonTest() | ||
{ | ||
this.verifier.actual(this.setup.borderSlicedPolygonAtlas(), | ||
new InvalidGeometryCheck(this.configuration)); | ||
this.verifier.verifyEmpty(); | ||
} | ||
|
||
@Test | ||
public void boundaryNodeTest() | ||
{ | ||
this.verifier.actual(this.setup.boundaryNodeAtlas(), | ||
new InvalidGeometryCheck(this.configuration)); | ||
this.verifier.verifyEmpty(); | ||
} | ||
|
||
@Test | ||
public void bowtiePolygonInvalidTest() | ||
{ | ||
this.verifier.actual(this.setup.getBowtiePolygonAtlas(), | ||
new InvalidGeometryCheck(this.configuration)); | ||
this.verifier.verifyNotEmpty(); | ||
this.verifier.verify(flag -> Assert.assertEquals(InvalidGeometryCheckTestRule.TEST_ID_5, | ||
flag.getIdentifier())); | ||
} | ||
|
||
@Test | ||
public void disconnectedCenterPolygonInvalidTest() | ||
{ | ||
this.verifier.actual(this.setup.getDisconnectedCenterPolygonAtlas(), | ||
new InvalidGeometryCheck(this.configuration)); | ||
this.verifier.verifyNotEmpty(); | ||
this.verifier.verify(flag -> Assert.assertEquals(InvalidGeometryCheckTestRule.TEST_ID_7, | ||
flag.getIdentifier())); | ||
} | ||
|
||
@Test | ||
public void hangNailPolygonInvalidTest() | ||
{ | ||
this.verifier.actual(this.setup.getHangNailPolygonAtlas(), | ||
new InvalidGeometryCheck(this.configuration)); | ||
this.verifier.verifyNotEmpty(); | ||
this.verifier.verify(flag -> Assert.assertEquals(InvalidGeometryCheckTestRule.TEST_ID_6, | ||
flag.getIdentifier())); | ||
} | ||
|
||
@Test | ||
public void testFineLinearTest() | ||
{ | ||
this.verifier.actual(this.setup.getFineLinearAtlas(), | ||
new InvalidGeometryCheck(this.configuration)); | ||
this.verifier.verifyEmpty(); | ||
} | ||
|
||
@Test | ||
public void testFinePolygonTest() | ||
{ | ||
this.verifier.actual(this.setup.getFinePolygonAtlas(), | ||
new InvalidGeometryCheck(this.configuration)); | ||
this.verifier.verifyEmpty(); | ||
} | ||
|
||
@Test | ||
public void testNotValidLinearTest() | ||
{ | ||
this.verifier.actual(this.setup.getNotValidLinearAtlas(), | ||
new InvalidGeometryCheck(this.configuration)); | ||
this.verifier.verifyNotEmpty(); | ||
this.verifier.verify(flag -> Assert.assertEquals(InvalidGeometryCheckTestRule.TEST_ID_2, | ||
flag.getIdentifier())); | ||
} | ||
} |
Oops, something went wrong.