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.
* AddressStreetNameCheck * config default; docs * consistency * pr feedback * code clean up * move package
- Loading branch information
Showing
5 changed files
with
271 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Address Street Name Check | ||
|
||
This check flags Points that have an `addr:street` value that does not match any of the names of surrounding streets. | ||
The search distance for surrounding streets is based on a configurable value that has a default of 100 meters. | ||
|
||
#### Live Examples | ||
|
||
1. Node [id:847673678](https://www.openstreetmap.org/node/847673678) has an `addr:street` value of Stykkishólmsvegur that does not match any name of surrounding streets. | ||
2. Node [id:2416844306](https://www.openstreetmap.org/node/2416844306) has an `addr:street` value of Vitatorg that is a typo of the nearby street V**í**tatorg. | ||
|
||
#### Code Review | ||
|
||
In [Atlas](https://github.com/osmlab/atlas), OSM elements are represented as Edges, Points, Lines, Nodes, Areas & Relations; | ||
in our case, we’re are looking at | ||
[Points](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Point.java) and | ||
[Edges](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Edge.java). | ||
|
||
This check first validates objects by checking that they are Points with an `addr:street` tag. | ||
|
||
If an object is valid, the check gathers all name tag values from surrounding roads (Edges). The surrounding roads are defined by a | ||
configurable search distance that is 100m by default. All name tag values are collected (`name` and localized name tags). | ||
|
||
The `addr:street` is then compared against the collected list of street names. If no match is found the Point is flagged. | ||
|
||
To learn more about the code, please look at the comments in the source code for the check. | ||
[AddressStreetNameCheck](../../src/main/java/org/openstreetmap/atlas/checks/validation/tag/AddressStreetNameCheck.java) |
100 changes: 100 additions & 0 deletions
100
src/main/java/org/openstreetmap/atlas/checks/validation/points/AddressStreetNameCheck.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,100 @@ | ||
package org.openstreetmap.atlas.checks.validation.points; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
|
||
import org.openstreetmap.atlas.checks.base.BaseCheck; | ||
import org.openstreetmap.atlas.checks.flag.CheckFlag; | ||
import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; | ||
import org.openstreetmap.atlas.geography.atlas.items.Edge; | ||
import org.openstreetmap.atlas.geography.atlas.items.Point; | ||
import org.openstreetmap.atlas.tags.AddressStreetTag; | ||
import org.openstreetmap.atlas.tags.annotations.validation.Validators; | ||
import org.openstreetmap.atlas.tags.names.NameTag; | ||
import org.openstreetmap.atlas.utilities.collections.Iterables; | ||
import org.openstreetmap.atlas.utilities.configuration.Configuration; | ||
import org.openstreetmap.atlas.utilities.scalars.Distance; | ||
|
||
/** | ||
* This flags {@link Point}s where their addr:street tag value does not match any of the name tag | ||
* values of {@link Edge}s within a configurable search distance. | ||
* | ||
* @author bbreithaupt | ||
*/ | ||
public class AddressStreetNameCheck extends BaseCheck<Long> | ||
{ | ||
|
||
private static final long serialVersionUID = 5401402333350044455L; | ||
|
||
private static final List<String> FALLBACK_INSTRUCTIONS = Collections.singletonList( | ||
"Address node {0,number,#} has an addr:street value that does not match the name of any roads within {1,number,#} meters."); | ||
private static final Double SEARCH_DISTANCE_DEFAULT = 100.0; | ||
|
||
// Distance to search for Edges around a Point | ||
private final Distance searchDistance; | ||
|
||
/** | ||
* The default constructor that must be supplied. The Atlas Checks framework will generate the | ||
* checks with this constructor, supplying a configuration that can be used to adjust any | ||
* parameters that the check uses during operation. | ||
* | ||
* @param configuration | ||
* the JSON configuration for this check | ||
*/ | ||
public AddressStreetNameCheck(final Configuration configuration) | ||
{ | ||
super(configuration); | ||
this.searchDistance = configurationValue(configuration, "bounds.size", | ||
SEARCH_DISTANCE_DEFAULT, Distance::meters); | ||
} | ||
|
||
/** | ||
* This function will validate if the supplied atlas object is valid for the check. | ||
* | ||
* @param object | ||
* the atlas object supplied by the Atlas-Checks framework for evaluation | ||
* @return {@code true} if this object should be checked | ||
*/ | ||
@Override | ||
public boolean validCheckForObject(final AtlasObject object) | ||
{ | ||
return object instanceof Point && Validators.hasValuesFor(object, AddressStreetTag.class); | ||
} | ||
|
||
/** | ||
* This is the actual function that will check to see whether the object needs to be flagged. | ||
* | ||
* @param object | ||
* the atlas object supplied by the Atlas-Checks framework for evaluation | ||
* @return an optional {@link CheckFlag} object that | ||
*/ | ||
@Override | ||
protected Optional<CheckFlag> flag(final AtlasObject object) | ||
{ | ||
// Gather the values of all name tags of all edges that are within the search distance | ||
final Set<String> streetNameValues = Iterables | ||
.stream(object.getAtlas().edgesIntersecting( | ||
((Point) object).getLocation().boxAround(this.searchDistance), | ||
Edge::isMasterEdge)) | ||
.flatMap(edge -> edge.getTags(tag -> tag.startsWith(NameTag.KEY)).values()) | ||
.collectToSet(); | ||
|
||
// Flag the object if there are edges within the search distance and the addr:street values | ||
// is not present in the set of Edge name tag values | ||
return !streetNameValues.isEmpty() | ||
&& !streetNameValues.contains(object.tag(AddressStreetTag.KEY)) | ||
? Optional | ||
.of(this.createFlag(object, | ||
this.getLocalizedInstruction(0, object.getOsmIdentifier(), | ||
this.searchDistance.asMeters()))) | ||
: Optional.empty(); | ||
} | ||
|
||
@Override | ||
protected List<String> getFallbackInstructions() | ||
{ | ||
return FALLBACK_INSTRUCTIONS; | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
...est/java/org/openstreetmap/atlas/checks/validation/points/AddressStreetNameCheckTest.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,55 @@ | ||
package org.openstreetmap.atlas.checks.validation.points; | ||
|
||
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; | ||
|
||
/** | ||
* Unit test for {@link AddressStreetNameCheck} | ||
* | ||
* @author bbreithaupt | ||
*/ | ||
public class AddressStreetNameCheckTest | ||
{ | ||
@Rule | ||
public AddressStreetNameCheckTestRule setup = new AddressStreetNameCheckTestRule(); | ||
|
||
@Rule | ||
public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier(); | ||
|
||
@Test | ||
public void validAddressStreetTagTest() | ||
{ | ||
this.verifier.actual(this.setup.validAddressStreetTagAtlas(), | ||
new AddressStreetNameCheck(ConfigurationResolver.emptyConfiguration())); | ||
this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); | ||
} | ||
|
||
@Test | ||
public void validAddressStreetLocalizedTagTest() | ||
{ | ||
this.verifier.actual(this.setup.validAddressStreetLocalizedTagAtlas(), | ||
new AddressStreetNameCheck(ConfigurationResolver.emptyConfiguration())); | ||
this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); | ||
} | ||
|
||
@Test | ||
public void invalidAddressStreetTagTest() | ||
{ | ||
this.verifier.actual(this.setup.invalidAddressStreetTagAtlas(), | ||
new AddressStreetNameCheck(ConfigurationResolver.emptyConfiguration())); | ||
this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); | ||
} | ||
|
||
@Test | ||
public void validAddressStreetTagConfigNoEdgeInRangeTest() | ||
{ | ||
this.verifier.actual(this.setup.validAddressStreetTagAtlas(), | ||
new AddressStreetNameCheck(ConfigurationResolver | ||
.inlineConfiguration("{\"AddressStreetNameCheck.bounds.size\":1.0}"))); | ||
this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); | ||
} | ||
|
||
} |
81 changes: 81 additions & 0 deletions
81
...java/org/openstreetmap/atlas/checks/validation/points/AddressStreetNameCheckTestRule.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,81 @@ | ||
package org.openstreetmap.atlas.checks.validation.points; | ||
|
||
import org.openstreetmap.atlas.geography.atlas.Atlas; | ||
import org.openstreetmap.atlas.utilities.testing.CoreTestRule; | ||
import org.openstreetmap.atlas.utilities.testing.TestAtlas; | ||
import org.openstreetmap.atlas.utilities.testing.TestAtlas.Edge; | ||
import org.openstreetmap.atlas.utilities.testing.TestAtlas.Loc; | ||
import org.openstreetmap.atlas.utilities.testing.TestAtlas.Node; | ||
import org.openstreetmap.atlas.utilities.testing.TestAtlas.Point; | ||
|
||
/** | ||
* Test rule for {@link AddressStreetNameCheckTest} | ||
* | ||
* @author bbreithaupt | ||
*/ | ||
public class AddressStreetNameCheckTestRule extends CoreTestRule | ||
{ | ||
private static final String TEST_1 = "48.1780944662566,-122.645324334797"; | ||
private static final String TEST_2 = "48.1784193930508,-122.644707774486"; | ||
private static final String TEST_3 = "48.1789233570657,-122.645035943684"; | ||
private static final String TEST_4 = "48.1785221755876,-122.645165222459"; | ||
|
||
@TestAtlas( | ||
// points | ||
points = { | ||
@Point(coordinates = @Loc(value = TEST_4), tags = { "addr:street=1st st" }) }, | ||
// nodes | ||
nodes = { @Node(coordinates = @Loc(value = TEST_1)), | ||
@Node(coordinates = @Loc(value = TEST_2)), | ||
@Node(coordinates = @Loc(value = TEST_3)) }, | ||
// edges | ||
edges = { | ||
@Edge(coordinates = { @Loc(value = TEST_1), @Loc(value = TEST_2) }, tags = { | ||
"highway=residential", "name=1st st" }), | ||
@Edge(coordinates = { @Loc(value = TEST_2), @Loc(value = TEST_3) }, tags = { | ||
"highway=residential", "name=2nd st" }) }) | ||
private Atlas validAddressStreetTagAtlas; | ||
|
||
@TestAtlas( | ||
// points | ||
points = { @Point(coordinates = @Loc(value = TEST_4), tags = { | ||
"addr:street=Rue de adresse" }) }, | ||
// nodes | ||
nodes = { @Node(coordinates = @Loc(value = TEST_1)), | ||
@Node(coordinates = @Loc(value = TEST_2)) }, | ||
// edges | ||
edges = { @Edge(coordinates = { @Loc(value = TEST_1), @Loc(value = TEST_2) }, tags = { | ||
"highway=residential", "name=1st st", "name:fr=Rue de adresse" }) }) | ||
private Atlas validAddressStreetLocalizedTagAtlas; | ||
|
||
@TestAtlas( | ||
// points | ||
points = { | ||
@Point(coordinates = @Loc(value = TEST_4), tags = { "addr:street=3rd st" }) }, | ||
// nodes | ||
nodes = { @Node(coordinates = @Loc(value = TEST_1)), | ||
@Node(coordinates = @Loc(value = TEST_2)), | ||
@Node(coordinates = @Loc(value = TEST_3)) }, | ||
// edges | ||
edges = { | ||
@Edge(coordinates = { @Loc(value = TEST_1), @Loc(value = TEST_2) }, tags = { | ||
"highway=residential", "name=1st st", "name:fr=Rue de adresse" }), | ||
@Edge(coordinates = { @Loc(value = TEST_2), @Loc(value = TEST_3) }, tags = { | ||
"highway=residential", "name=2nd st" }) }) | ||
private Atlas invalidAddressStreetTagAtlas; | ||
|
||
public Atlas validAddressStreetTagAtlas() | ||
{ | ||
return this.validAddressStreetTagAtlas; | ||
} | ||
|
||
public Atlas validAddressStreetLocalizedTagAtlas() | ||
{ | ||
return this.validAddressStreetLocalizedTagAtlas; | ||
} | ||
|
||
public Atlas invalidAddressStreetTagAtlas() | ||
{ | ||
return this.invalidAddressStreetTagAtlas; | ||
} | ||
} |