Skip to content

Commit

Permalink
UnknownHighwayTagCheck completed (osmlab#465)
Browse files Browse the repository at this point in the history
* unit tests passed and 0% fpr

* updated comment

* awaiting the atlas PR for new highway tag methods and values.

* new logic for nodes and ways with tests passed.

* uncaught formatting?

* gather complete way for flag

* addressed comments to remove extra calculations

* removed "UnknownHighwayTagCheck" reference from variable call.
  • Loading branch information
reichg authored Feb 10, 2021
1 parent bfd9601 commit 5625945
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,14 @@
"instruction": "Please see instructions per feature for actions to take."
}
},
"UnknownHighwayTagCheck": {
"challenge": {
"description": "highway tag is unknown and needs to be fixed.",
"blurb": "unknown highway tags.",
"instruction": "please change the highway tag to a known tag.",
"difficulty": "EASY"
}
},
"UnusualLayerTagsCheck": {
"challenge": {
"description": "Tunnels (negative), junctions (zero) and bridges (zero or positive) should have meaningful layer tags attached to them. A missing layer tag implies layer value 0. If there is an explicit layer tag, then it must be between -5 and 5.",
Expand Down
1 change: 1 addition & 0 deletions docs/available_checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ This document is a list of tables with a description and link to documentation f
| [StreetNameIntegersOnlyCheck](checks/streetNameIntegersOnlyCheck.md) | The purpose of this check is to identify streets whose names contain integers only. |
| [TollValidationCheck](checks/tollValidationCheck) | The purpose of this check is to identify ways that need to have their toll tags investigated/added/removed.
| [TunnelBridgeHeightLimitCheck](checks/tunnelBridgeHeightLimitCheck.md) | The purpose of this check is to identify roads with limited vertical clearance which do not have a maxheight tag. |
| [UnknownHighwayTagCheck](checks/unknownHighwayTagCheck.md) | This check attempts to flag all highway tags that are unknown to the [osm wiki page](https://wiki.openstreetmap.org/wiki/Key:highway). |
| [UnusualLayerTagsCheck](checks/unusualLayerTagsCheck.md) | The purpose of this check is to identify layer tag values when accompanied by invalid tunnel and bridge tags. |
| [ConditionalRestrictionCheck](checks/conditionalRestrictionCheck.md) | The purpose of this check is to identify elements that have a :conditional tag that does not respect the established format. |
| [SourceMaxspeedCheck](checks/sourceMaxspeedCheck.md) | The purpose of this check is to identify elements that have a source:maxspeed tag that does not follow the tagging rules. |
Expand Down
14 changes: 14 additions & 0 deletions docs/checks/unknownHighwayTagCheck.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# UnknownHighwayTagCheck

#### Description
This check attempts to flag all highway tags that are unknown to the [osm wiki page](https://wiki.openstreetmap.org/wiki/Key:highway).

#### Live Examples

Highway tag does not exist on the OSM Wiki page.
1. [Node:313559095](https://www.openstreetmap.org/node/313559095) has a highway tag that is unknown (“highway=priority”)

#### Code Review
This check evaluates [Nodes](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Node.java) and
[Edges](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Edge.java), and [HighwayTags](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/tags/HighwayTag.java),
it attempts to find items that contain unknown highway tags.
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package org.openstreetmap.atlas.checks.validation.tag;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

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.Node;
import org.openstreetmap.atlas.geography.atlas.walker.OsmWayWalker;
import org.openstreetmap.atlas.tags.HighwayTag;
import org.openstreetmap.atlas.utilities.configuration.Configuration;

/**
* This check flags Edges and Nodes that have highway tag values that are not contained within the
* set of known highway tags on the OSM Wiki page - https://wiki.openstreetmap.org/wiki/Key:highway
*
* @author v-garei
*/

public class UnknownHighwayTagCheck extends BaseCheck<Long>
{
private static final long serialVersionUID = -7273798399961675550L;
private static final String NODE_WITH_WAY_TAG_INSTRUCTIONS = "This Node's highway tag only belongs on a Way, please update this Node's tag with only Node related tags. List of tags can be found at https://wiki.openstreetmap.org/wiki/Key:highway";
private static final String WAY_WITH_NODE_TAG_INSTRUCTIONS = "This Way's highway tag only belongs on a Node, please update this Way's tag with only Way related tags. List of tags can be found at https://wiki.openstreetmap.org/wiki/Key:highway";
private static final String UNKNOWN_HIGHWAY_TAG_INSTRUCTIONS = "Please update highway tag to a known value.";
private static final List<String> FALLBACK_INSTRUCTIONS = Arrays.asList(
NODE_WITH_WAY_TAG_INSTRUCTIONS, WAY_WITH_NODE_TAG_INSTRUCTIONS,
UNKNOWN_HIGHWAY_TAG_INSTRUCTIONS);
private static final Set<String> allHighwayTags = Arrays.stream(HighwayTag.values())
.map(Enum::toString).collect(Collectors.toSet());

/**
* 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 UnknownHighwayTagCheck(final Configuration configuration)
{
super(configuration);
}

/**
* 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 Edge && ((Edge) object).isMainEdge()) || object instanceof Node)
&& !isFlagged(object.getOsmIdentifier());
}

/**
* 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)
{
markAsFlagged(object.getOsmIdentifier());
final Optional<String> objectHighwayTag = object.getTag(HighwayTag.KEY);

if (object instanceof Node && HighwayTag.isWayOnlyTag(object))
{
return Optional.of(this.createFlag(object,
this.getLocalizedInstruction(0, object.getOsmIdentifier())));
}

if (object instanceof Edge && HighwayTag.isNodeOnlyTag(object))
{
final Edge edgeInQuestion = ((Edge) object).getMainEdge();
return Optional.of(this.createFlag(new OsmWayWalker(edgeInQuestion).collectEdges(),
this.getLocalizedInstruction(1, object.getOsmIdentifier())));
}

if (objectHighwayTag.isPresent()
&& !this.isKnownHighwayTag(objectHighwayTag.get().toUpperCase()))
{
if (object instanceof Edge)
{
final Edge edgeInQuestion = ((Edge) object).getMainEdge();
return Optional.of(this.createFlag(new OsmWayWalker(edgeInQuestion).collectEdges(),
this.getLocalizedInstruction(2, object.getOsmIdentifier())));
}
return Optional.of(this.createFlag(object,
this.getLocalizedInstruction(2, object.getOsmIdentifier())));
}
return Optional.empty();
}

@Override
protected List<String> getFallbackInstructions()
{
return FALLBACK_INSTRUCTIONS;
}

/**
* @param highwayTag
* object highway tag
* @return boolean for if the object's highway tag is contained within the known set of OSM
* highway tags.
*/
private boolean isKnownHighwayTag(final String highwayTag)
{
return allHighwayTags.contains(highwayTag);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.openstreetmap.atlas.checks.validation.tag;

import org.junit.Rule;
import org.junit.Test;
import org.openstreetmap.atlas.checks.configuration.ConfigurationResolver;
import org.openstreetmap.atlas.checks.validation.verifier.ConsumerBasedExpectedCheckVerifier;

/**
* Tests for {@link UnknownHighwayTagCheck}
*
* @author v-garei
*/
public class UnknownHighwayTagCheckTest
{
@Rule
public UnknownHighwayTagCheckTestRule setup = new UnknownHighwayTagCheckTestRule();

@Rule
public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier();

private final UnknownHighwayTagCheck check = new UnknownHighwayTagCheck(ConfigurationResolver
.inlineConfiguration("{\"UnknownHighwayTagCheck\": " + "{" + "}}"));

@Test
public void falsePositiveKnownHighwayTagOnEdge()
{
this.verifier.actual(this.setup.falsePositiveKnownHighwayTagOnEdge(), this.check);
this.verifier.verifyEmpty();
}

@Test
public void falsePositiveKnownHighwayTagOnNode()
{
this.verifier.actual(this.setup.falsePositiveKnownHighwayTagOnNode(), this.check);
this.verifier.verifyEmpty();
}

@Test
public void truePositiveEdgeTagOnNode()
{
this.verifier.actual(this.setup.truePositiveEdgeTagOnNode(), this.check);
this.verifier.verifyExpectedSize(1);
}

@Test
public void truePositiveNodeTagOnEdge()
{
this.verifier.actual(this.setup.truePositiveNodeTagOnEdge(), this.check);
this.verifier.verifyExpectedSize(1);
}

@Test
public void truePositiveUnknownHighwayTagOnEdge()
{
this.verifier.actual(this.setup.truePositiveUnknownHighwayTagOnEdge(), this.check);
this.verifier.verifyExpectedSize(1);
}

@Test
public void truePositiveUnknownHighwayTagOnNode()
{
this.verifier.actual(this.setup.truePositiveUnknownHighwayTagOnNode(), this.check);
this.verifier.verifyExpectedSize(1);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.openstreetmap.atlas.checks.validation.tag;

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;

/**
* Tests for {@link UnknownHighwayTagCheck}
*
* @author v-garei
*/
public class UnknownHighwayTagCheckTestRule extends CoreTestRule
{

private static final String WAY1_NODE1 = "40.9130354, 29.4700719";
private static final String WAY1_NODE2 = "40.9123887, 29.4698597";

@TestAtlas(nodes = { @Node(coordinates = @Loc(value = WAY1_NODE1)),
@Node(coordinates = @Loc(value = WAY1_NODE2)) }, edges = {
@Edge(id = "1000001", coordinates = { @Loc(value = WAY1_NODE1),
@Loc(value = WAY1_NODE2) }, tags = { "highway=trunk" }) })
private Atlas falsePositiveKnownHighwayTagOnEdge;

@TestAtlas(nodes = {
@Node(coordinates = @Loc(value = WAY1_NODE1), tags = { "highway=bus_stop" }),
@Node(coordinates = @Loc(value = WAY1_NODE2)) }, edges = {
@Edge(id = "2000001", coordinates = { @Loc(value = WAY1_NODE1),
@Loc(value = WAY1_NODE2) }) })
private Atlas falsePositiveKnownHighwayTagOnNode;

@TestAtlas(nodes = { @Node(id = "2000001", coordinates = @Loc(value = WAY1_NODE1)),
@Node(id = "3000001", coordinates = @Loc(value = WAY1_NODE2), tags = {
"highway=trunk" }) }, edges = {
@Edge(id = "4000001", coordinates = { @Loc(value = WAY1_NODE1),
@Loc(value = WAY1_NODE2) }) })
private Atlas truePositiveEdgeTagOnNode;

@TestAtlas(nodes = { @Node(coordinates = @Loc(value = WAY1_NODE1)),
@Node(coordinates = @Loc(value = WAY1_NODE2)) }, edges = {
@Edge(id = "5000001", coordinates = { @Loc(value = WAY1_NODE1),
@Loc(value = WAY1_NODE2) }, tags = { "highway=bus_stop" }) })
private Atlas truePositiveNodeTagOnEdge;

@TestAtlas(nodes = { @Node(coordinates = @Loc(value = WAY1_NODE1)),
@Node(coordinates = @Loc(value = WAY1_NODE2)) }, edges = {
@Edge(id = "3000001", coordinates = { @Loc(value = WAY1_NODE1),
@Loc(value = WAY1_NODE2) }, tags = { "highway=unknown" }) })
private Atlas truePositiveUnknownHighwayTagOnEdge;

@TestAtlas(nodes = {
@Node(coordinates = @Loc(value = WAY1_NODE1), tags = { "highway=unknown" }),
@Node(coordinates = @Loc(value = WAY1_NODE2)) }, edges = {
@Edge(id = "6000001", coordinates = { @Loc(value = WAY1_NODE1),
@Loc(value = WAY1_NODE2) }) })
private Atlas truePositiveUnknownHighwayTagOnNode;

public Atlas falsePositiveKnownHighwayTagOnEdge()
{
return this.falsePositiveKnownHighwayTagOnEdge;
}

public Atlas falsePositiveKnownHighwayTagOnNode()
{
return this.falsePositiveKnownHighwayTagOnNode;
}

public Atlas truePositiveEdgeTagOnNode()
{
return this.truePositiveEdgeTagOnNode;
}

public Atlas truePositiveNodeTagOnEdge()
{
return this.truePositiveNodeTagOnEdge;
}

public Atlas truePositiveUnknownHighwayTagOnEdge()
{
return this.truePositiveUnknownHighwayTagOnEdge;
}

public Atlas truePositiveUnknownHighwayTagOnNode()
{
return this.truePositiveUnknownHighwayTagOnNode;
}
}

0 comments on commit 5625945

Please sign in to comment.