From 05112bdeaadff621f6aa6073ce27cea976514da2 Mon Sep 17 00:00:00 2001 From: Gabe Reichenberger Date: Fri, 23 Oct 2020 13:42:02 -0700 Subject: [PATCH] Suddenhighwaytypechange (#381) * new suddenhighwaytypechangecheck with simplified logic and more inline with osmose issue 1090. * Updated check and required documents * Fixed test issues * Replacing strings with HighwayType. * removing config default value * updating documentation regarding the suddenhighwaytypechangecheck * spotless apply * fixing sonar cloud errors and spotless * Update SuddenHighwayTypeChangeCheck.java * Update SuddenHighwayTypeChangeCheck.java * Update SuddenHighwayTypeChangeCheck.java * Update SuddenHighwayTypeChangeCheck.java * Update SuddenHighwayTypeChangeCheck.java * consolidated conditionals to simplify final method * Update SuddenHighwayTypeChangeCheck.java * Update SuddenHighwayTypeChangeCheck.java * Update SuddenHighwayTypeChangeCheck.java * Update SuddenHighwayTypeChangeCheck.java * Update SuddenHighwayTypeChangeCheck.java * removing marking connected edges as flagged to maximize detections. * Update SuddenHighwayTypeChangeCheck.java * fixing change requests from pull request. * updated test checks for cases and addressed comments * fixed config * fixing code smells * hopefully last spotless apply * fixed config * siplified the main functions with return true or false --- config/configuration.json | 30 +- docs/available_checks.md | 1 + docs/checks/suddenHighwayTypeChangeCheck.md | 40 ++ .../edges/SuddenHighwayTypeChangeCheck.java | 359 ++++++++++++++++++ .../SuddenHighwayTypeChangeCheckTest.java | 60 +++ .../SuddenHighwayTypeChangeCheckTestRule.java | 91 +++++ 6 files changed, 576 insertions(+), 5 deletions(-) create mode 100644 docs/checks/suddenHighwayTypeChangeCheck.md create mode 100644 src/main/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheck.java create mode 100644 src/test/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheckTest.java create mode 100644 src/test/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheckTestRule.java diff --git a/config/configuration.json b/config/configuration.json index 1985c565f..912708ac6 100644 --- a/config/configuration.json +++ b/config/configuration.json @@ -920,16 +920,36 @@ "difficulty": "MEDIUM", "defaultPriority": "LOW", "highPriorityRule": { - "condition":"OR", - "rules":["highway=motorway","highway=motorway_link","highway=trunk","highway=trunk_link"] + "condition": "OR", + "rules": [ + "highway=motorway", + "highway=motorway_link", + "highway=trunk", + "highway=trunk_link" + ] }, "mediumPriorityRule": { - "condition":"OR", - "rules":["highway=primary","highway=primary_link","highway=secondary","highway=secondary_link"] + "condition": "OR", + "rules": [ + "highway=primary", + "highway=primary_link", + "highway=secondary", + "highway=secondary_link" + ] }, - "tags":"highway" + "tags": "highway" } }, + "SuddenHighwayTypeChangeCheck":{ + "challenge": { + "description": "Identifies ways that have suspicious highway tag jumps.", + "blurb": "Sudden Highway Type Change", + "instruction": "Check if way has suspicious highway jump and make necessary adjust to tag.", + "difficulty": "MEDIUM", + "defaultPriority": "LOW" + }, + "minHighwayType": "tertiary" + }, "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.", diff --git a/docs/available_checks.md b/docs/available_checks.md index 80f25c4a3..a93ba5165 100644 --- a/docs/available_checks.md +++ b/docs/available_checks.md @@ -36,6 +36,7 @@ This document is a list of tables with a description and link to documentation f | [SingleSegmentMotorwayCheck](checks/singleSegmentMotorwayCheck.md) | The purpose of this check is to identify ways tagged with highway=motorway that are not connected to any ways tagged the same. | | [SinkIslandCheck](tutorials/tutorial3-SinkIslandCheck.md) | The purpose of this check is to identify whether a network of car-navigable Edges can be exited. | | [SnakeRoadCheck](checks/snakeRoadCheck.md) | The purpose of the SnakeRoad check is to identify roads that should be split into two or more roads. | +| [SuddenHighwayTypeChangeCheck](checks/suddenHighwayTypeChangeCheck.md) | The purpose of this check is to identify roads that jump to much different highway classifications. | | UnwalkableWaysCheck | The purpose of this check is to identify any non-motorway single carriageway edges with no foot tags that cross any high-priority roads that are dual carriageways. | | ValenceOneImportantRoadCheck | This check identifies important roads that either start or end with valance-1 nodes. | diff --git a/docs/checks/suddenHighwayTypeChangeCheck.md b/docs/checks/suddenHighwayTypeChangeCheck.md new file mode 100644 index 000000000..71de584b3 --- /dev/null +++ b/docs/checks/suddenHighwayTypeChangeCheck.md @@ -0,0 +1,40 @@ +# SuddenHighwayTypeChangeCheck + +#### Description + +The purpose of this check is to identify ways that have sudden highway tag jumps based on 3 different classes. + +#### Live Examples +Sudden Highway Type Changes +1. The way [id:698449634](https://www.openstreetmap.org/way/698449634) jumps from primary road to tertiary road. Flagged edge even needs to be a link. + +#### Code Review + +This check evaluates [Edges](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Edge.java) +, it attempts to find large jumps in highway classifications. + +##### Validating the Object +We first validate that the incoming object is: +* An Edge +* A Main edge +* The Edge is Car Navigable +* The Edge is of a specified minimum highway type (tertiary) +* The Edge is not a roundabout or circular + +##### Flagging the Edge +Gather the ways' in and out edges. Iterate over these edges and determining if they fit within the 3 classifications of this check. + +##### Three classifications of Sudden Highway Tag Changes +###### Class 1 +* Way with following classification: **Motorway, Trunk, or Primary** +* Above way terminates and connects to following classification: **Tertiary, Unclassified, Residential, or Service** +###### Class 2 +* Way with following classification: **Motorway_Link, Trunk_Link, Primary_Link, Secondary_Link, or Secondary** +* Above way terminates and connects to following classification: **Unclassified, Residential, or Service** +###### Class 3 +* Way with following classification: **Tertiary or Tertiary_Link** +* Above way terminates and connects to following classification: **Living_Street, Service, or Track** + + +To learn more about the code, please look at the comments in the source code for the check. +[SuddenHighwayTypeChangeCheck.java](../../src/main/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheck.java) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheck.java new file mode 100644 index 000000000..9d5593a7a --- /dev/null +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheck.java @@ -0,0 +1,359 @@ +package org.openstreetmap.atlas.checks.validation.linear.edges; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.openstreetmap.atlas.checks.atlas.predicates.TypePredicates; +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.tags.JunctionTag; +import org.openstreetmap.atlas.utilities.configuration.Configuration; + +/** + * This check identifies ways that make suspiciously large jumps in highway classification + * + * @author v-garei + */ +public class SuddenHighwayTypeChangeCheck extends BaseCheck +{ + private static final String SUDDEN_HIGHWAY_TYPE_CHANGE_INSTRUCTION = "Way {0,number,#} has a connected edge which jumps significantly in highway classification. Please make sure the highway tag is not suspicious."; + private static final List FALLBACK_INSTRUCTIONS = Collections + .singletonList(SUDDEN_HIGHWAY_TYPE_CHANGE_INSTRUCTION); + private static final String HIGHWAY_MINIMUM_DEFAULT = HighwayTag.RESIDENTIAL.toString(); + private final HighwayTag minHighwayType; + + /** + * 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 SuddenHighwayTypeChangeCheck(final Configuration configuration) + { + super(configuration); + final String highwayType = this.configurationValue(configuration, "minHighwayType", + HIGHWAY_MINIMUM_DEFAULT); + this.minHighwayType = Enum.valueOf(HighwayTag.class, highwayType.toUpperCase()); + } + + /** + * 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) + { + if (TypePredicates.IS_EDGE.test(object) && ((Edge) object).isMainEdge() + && !isFlagged(object.getOsmIdentifier())) + { + final Edge edge = (Edge) object; + return HighwayTag.isCarNavigableHighway(edge) + && edge.highwayTag().isMoreImportantThanOrEqualTo(this.minHighwayType) + && !JunctionTag.isRoundabout(edge) && !JunctionTag.isCircular(edge); + } + return false; + } + + /** + * 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 flag(final AtlasObject object) + { + final Edge edgeBeingVerified = (Edge) object; + + final List completeWayEdges = new ArrayList<>( + new OsmWayWalker(edgeBeingVerified).collectEdges()); + + final Node firstEdgeStartNode = completeWayEdges.get(0).start(); + final Node lastEdgeEndNode = completeWayEdges.get(completeWayEdges.size() - 1).end(); + + final Set firstEdgeStartNodeEdges = firstEdgeStartNode.connectedEdges(); + firstEdgeStartNodeEdges + .removeIf(edge -> edge.getOsmIdentifier() == edgeBeingVerified.getOsmIdentifier()); + final Set lastEdgeEndNodeEdges = lastEdgeEndNode.connectedEdges(); + lastEdgeEndNodeEdges + .removeIf(edge -> edge.getOsmIdentifier() == edgeBeingVerified.getOsmIdentifier()); + + final HighwayTag edgeBeingVerifiedHighwayTag = HighwayTag.highwayTag(edgeBeingVerified) + .orElse(HighwayTag.NO); + + final Set firstEdgeStartNodeEdgesHighwayTags = this + .getHighwayTags(firstEdgeStartNodeEdges); + final Set lastEdgeEndNodeEdgesHighwayTags = this + .getHighwayTags(lastEdgeEndNodeEdges); + + // Check ways' first and last edge's connected edges for suspiciously large highway tag + // jumps. + if (this.firstEdgeStartNodeEdgesHighwayTags(edgeBeingVerifiedHighwayTag, + firstEdgeStartNodeEdges, firstEdgeStartNodeEdgesHighwayTags) + || this.lastEdgeEndNodeEdgesHighwayTage(edgeBeingVerifiedHighwayTag, + lastEdgeEndNodeEdges, lastEdgeEndNodeEdgesHighwayTags)) + { + markAsFlagged(object.getOsmIdentifier()); + return Optional.of( + createFlag(object, this.getLocalizedInstruction(0, object.getOsmIdentifier()))); + } + + markAsFlagged(edgeBeingVerified.getOsmIdentifier()); + return Optional.empty(); + } + + @Override + protected List getFallbackInstructions() + { + return FALLBACK_INSTRUCTIONS; + } + + /** + * Case one: edge being verified is motorway, primary, trunk + * + * @param edgeHighwayTag + * tag for edge being verified + * @return boolean + */ + private boolean edgeBeingVerifiedCaseOne(final HighwayTag edgeHighwayTag) + { + return HighwayTag.MOTORWAY.equals(edgeHighwayTag) + || HighwayTag.PRIMARY.equals(edgeHighwayTag) + || HighwayTag.TRUNK.equals(edgeHighwayTag); + } + + /** + * Case three: edge being verified is tertiary or tertiary_link + * + * @param edgeHighwayTag + * tag for edge being verified + * @return boolean + */ + private boolean edgeBeingVerifiedCaseThree(final HighwayTag edgeHighwayTag) + { + return HighwayTag.TERTIARY.equals(edgeHighwayTag) + || HighwayTag.TERTIARY_LINK.equals(edgeHighwayTag); + } + + /** + * case two: edge being verified is any link but tertiary. + * + * @param edgeHighwayTag + * tag for edge being verified + * @return boolean + */ + private boolean edgeBeingVerifiedCaseTwo(final HighwayTag edgeHighwayTag) + { + return HighwayTag.MOTORWAY_LINK.equals(edgeHighwayTag) + || HighwayTag.PRIMARY_LINK.equals(edgeHighwayTag) + || HighwayTag.TRUNK_LINK.equals(edgeHighwayTag) + || HighwayTag.SECONDARY.equals(edgeHighwayTag) + || HighwayTag.SECONDARY_LINK.equals(edgeHighwayTag); + } + + /** + * case one: edge checked against is tertiary, residential, service, or unclassified + * + * @param edgeHighwayTag + * connected edge highway tag + * @return boolean + */ + private boolean edgeCheckedAgainstCaseOne(final HighwayTag edgeHighwayTag) + { + return HighwayTag.TERTIARY.equals(edgeHighwayTag) + || HighwayTag.UNCLASSIFIED.equals(edgeHighwayTag) + || HighwayTag.RESIDENTIAL.equals(edgeHighwayTag) + || HighwayTag.SERVICE.equals(edgeHighwayTag); + } + + /** + * case three: edge checked against is living_Street, service, or track + * + * @param edgeHighwayTag + * connected edge highway tag + * @return boolean + */ + private boolean edgeCheckedAgainstCaseThree(final HighwayTag edgeHighwayTag) + { + return HighwayTag.LIVING_STREET.equals(edgeHighwayTag) + || HighwayTag.TRACK.equals(edgeHighwayTag) + || HighwayTag.SERVICE.equals(edgeHighwayTag); + } + + /** + * case two: edge checked against is residential, service, or unclassified + * + * @param edgeHighwayTag + * connected edge highway tag + * @return boolean + */ + private boolean edgeCheckedAgainstCaseTwo(final HighwayTag edgeHighwayTag) + { + return HighwayTag.UNCLASSIFIED.equals(edgeHighwayTag) + || HighwayTag.RESIDENTIAL.equals(edgeHighwayTag) + || HighwayTag.SERVICE.equals(edgeHighwayTag); + } + + /** + * checks if edge is roundabout or circular + * + * @param edge + * edge to check if roundabout or circular + * @return boolean + */ + private boolean edgeIsRoundaboutOrCircular(final Edge edge) + { + return JunctionTag.isCircular(edge) || JunctionTag.isRoundabout(edge); + } + + /** + * checks if edge being verified's first edge start node connected edges make suspicious jumps + * + * @param edgeBeingVerifiedHighwayTag + * edge being verified highway tag + * @param firstEdgeStartNodeEdges + * first edge start node edges + * @param firstEdgeStartNodeEdgesHighwayTags + * first edge start node edge highway tags + * @return boolean + */ + private boolean firstEdgeStartNodeEdgesHighwayTags(final HighwayTag edgeBeingVerifiedHighwayTag, + final Set firstEdgeStartNodeEdges, + final Set firstEdgeStartNodeEdgesHighwayTags) + { + for (final Edge firstEdgeEdge : firstEdgeStartNodeEdges) + { + final HighwayTag firstEdgeEdgeHighwayTag = HighwayTag.highwayTag(firstEdgeEdge) + .orElse(HighwayTag.NO); + if ((!edgeBeingVerifiedHighwayTag.equals(HighwayTag.NO) + && !firstEdgeEdgeHighwayTag.equals(HighwayTag.NO) + && !firstEdgeStartNodeEdgesHighwayTags.contains(edgeBeingVerifiedHighwayTag) + && !this.edgeIsRoundaboutOrCircular(firstEdgeEdge)) + && (this.isCaseOne(edgeBeingVerifiedHighwayTag, firstEdgeEdgeHighwayTag) + || this.isCaseTwo(edgeBeingVerifiedHighwayTag, firstEdgeEdgeHighwayTag) + || this.isCaseThree(edgeBeingVerifiedHighwayTag, + firstEdgeEdgeHighwayTag))) + { + return true; + } + } + return false; + } + + /** + * gets set of highway tags + * + * @param edges + * set of edges + * @return set of highway tags + */ + private Set getHighwayTags(final Set edges) + { + final Set highwayTags = new HashSet<>(); + for (final Edge edge : edges) + { + final Optional highwayTagOptional = HighwayTag.highwayTag(edge); + if (highwayTagOptional.isPresent()) + { + final HighwayTag highwayTag = highwayTagOptional.get(); + highwayTags.add(highwayTag); + } + } + return highwayTags; + } + + /** + * checks if case one for edge being verified and edge checked against is true + * + * @param edgeHighwayTag1 + * some edge tag + * @param edgeHighwayTag2 + * some edge tag + * @return boolean + */ + private boolean isCaseOne(final HighwayTag edgeHighwayTag1, final HighwayTag edgeHighwayTag2) + { + return this.edgeBeingVerifiedCaseOne(edgeHighwayTag1) + && this.edgeCheckedAgainstCaseOne(edgeHighwayTag2); + } + + /** + * checks if case three for edge being verified and edge checked against is true + * + * @param edgeHighwayTag1 + * some edge tag + * @param edgeHighwayTag2 + * some edge tag + * @return boolean + */ + private boolean isCaseThree(final HighwayTag edgeHighwayTag1, final HighwayTag edgeHighwayTag2) + { + return this.edgeBeingVerifiedCaseThree(edgeHighwayTag1) + && this.edgeCheckedAgainstCaseThree(edgeHighwayTag2); + } + + /** + * checks if case two for edge being verified and edge checked against is true + * + * @param edgeHighwayTag1 + * some edge tag + * @param edgeHighwayTag2 + * some edge tag + * @return boolean + */ + private boolean isCaseTwo(final HighwayTag edgeHighwayTag1, final HighwayTag edgeHighwayTag2) + { + return this.edgeBeingVerifiedCaseTwo(edgeHighwayTag1) + && this.edgeCheckedAgainstCaseTwo(edgeHighwayTag2); + } + + /** + * checks if edge being verified last edge's end node connected edges make suspicious jumps + * + * @param edgeBeingVerifiedHighwayTag + * edge being verified highway tags + * @param lastEdgeEndNodeEdges + * last edge end node edges + * @param lastEdgeEndNodeEdgesHighwayTags + * last edge end node edge highway tags + * @return boolean + */ + private boolean lastEdgeEndNodeEdgesHighwayTage(final HighwayTag edgeBeingVerifiedHighwayTag, + final Set lastEdgeEndNodeEdges, + final Set lastEdgeEndNodeEdgesHighwayTags) + { + for (final Edge lastEdgeEdge : lastEdgeEndNodeEdges) + { + final HighwayTag lastEdgeEdgeHighwayTag = HighwayTag.highwayTag(lastEdgeEdge) + .orElse(HighwayTag.NO); + if ((!lastEdgeEdgeHighwayTag.equals(HighwayTag.NO) + && !edgeBeingVerifiedHighwayTag.equals(HighwayTag.NO) + && !lastEdgeEndNodeEdgesHighwayTags.contains(edgeBeingVerifiedHighwayTag) + && !this.edgeIsRoundaboutOrCircular(lastEdgeEdge)) + && (this.isCaseOne(edgeBeingVerifiedHighwayTag, lastEdgeEdgeHighwayTag) + || this.isCaseTwo(edgeBeingVerifiedHighwayTag, lastEdgeEdgeHighwayTag) + || this.isCaseThree(edgeBeingVerifiedHighwayTag, + lastEdgeEdgeHighwayTag))) + { + return true; + } + } + return false; + } + +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheckTest.java new file mode 100644 index 000000000..c696bb12a --- /dev/null +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheckTest.java @@ -0,0 +1,60 @@ +package org.openstreetmap.atlas.checks.validation.linear.edges; + +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 SuddenHighwayTypeChangeCheck} + * + * @author v-garei + */ +public class SuddenHighwayTypeChangeCheckTest +{ + + @Rule + public SuddenHighwayTypeChangeCheckTestRule setup = new SuddenHighwayTypeChangeCheckTestRule(); + + @Rule + public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier(); + + private final SuddenHighwayTypeChangeCheck check = new SuddenHighwayTypeChangeCheck( + ConfigurationResolver.inlineConfiguration( + "{\"SuddenHighwayTypeChangeCheck\": {\"minHighwayType\": \"tertiary\"}}")); + + @Test + public void testFalsePositiveSuddenHighwayTypeChangeCheck() + { + this.verifier.actual(this.setup.falsePositiveSuddenHighwayTypeChangeCheck(), this.check); + this.verifier.verifyEmpty(); + } + + @Test + public void testTruePositiveSuddenHighwayTypeChangeCheck() + { + this.verifier.actual(this.setup.truePositiveSuddenHighwayTypeChangeCheck(), this.check); + this.verifier.verifyExpectedSize(1); + } + + @Test + public void truePositiveCase1() + { + this.verifier.actual(this.setup.truePositiveCase1(), this.check); + this.verifier.verifyExpectedSize(1); + } + + @Test + public void truePositiveCase2() + { + this.verifier.actual(this.setup.truePositiveCase2(), this.check); + this.verifier.verifyExpectedSize(1); + } + + @Test + public void truePositiveCase3() + { + this.verifier.actual(this.setup.truePositiveCase3(), this.check); + this.verifier.verifyExpectedSize(1); + } +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheckTestRule.java new file mode 100644 index 000000000..ac0970a51 --- /dev/null +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/linear/edges/SuddenHighwayTypeChangeCheckTestRule.java @@ -0,0 +1,91 @@ +package org.openstreetmap.atlas.checks.validation.linear.edges; + +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 SuddenHighwayTypeChangeCheck} + * + * @author v-garei + */ +public class SuddenHighwayTypeChangeCheckTestRule extends CoreTestRule +{ + + private static final String WAY1_NODE1 = "47.6317191, -122.1961930"; + private static final String WAY1_WAY2_INTERSECTION = "47.6316431, -122.1962111"; + private static final String WAY2_NODE2 = "47.6315832, -122.1961171"; + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = WAY1_NODE1)), + @Node(coordinates = @Loc(value = WAY1_WAY2_INTERSECTION)), + @Node(coordinates = @Loc(value = WAY2_NODE2)) }, edges = { + @Edge(id = "1000001", coordinates = { @Loc(value = WAY1_NODE1), + @Loc(value = WAY1_WAY2_INTERSECTION) }, tags = "highway=service"), + @Edge(id = "2000001", coordinates = { @Loc(value = WAY1_WAY2_INTERSECTION), + @Loc(value = WAY2_NODE2) }, tags = "highway=primary") }) + private Atlas truePositiveSuddenHighwayTypeChangeCheck; + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = WAY1_NODE1)), + @Node(coordinates = @Loc(value = WAY1_WAY2_INTERSECTION)), + @Node(coordinates = @Loc(value = WAY2_NODE2)) }, edges = { + @Edge(id = "3000001", coordinates = { @Loc(value = WAY1_NODE1), + @Loc(value = WAY1_WAY2_INTERSECTION) }, tags = "highway=tertiary"), + @Edge(id = "4000001", coordinates = { @Loc(value = WAY1_WAY2_INTERSECTION), + @Loc(value = WAY2_NODE2) }, tags = "highway=secondary") }) + private Atlas falsePositiveSuddenHighwayTypeChangeCheck; + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = WAY1_NODE1)), + @Node(coordinates = @Loc(value = WAY1_WAY2_INTERSECTION)), + @Node(coordinates = @Loc(value = WAY2_NODE2)) }, edges = { + @Edge(id = "5000001", coordinates = { @Loc(value = WAY1_NODE1), + @Loc(value = WAY1_WAY2_INTERSECTION) }, tags = "highway=motorway"), + @Edge(id = "6000001", coordinates = { @Loc(value = WAY1_WAY2_INTERSECTION), + @Loc(value = WAY2_NODE2) }, tags = "highway=tertiary") }) + private Atlas truePositiveCase1; + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = WAY1_NODE1)), + @Node(coordinates = @Loc(value = WAY1_WAY2_INTERSECTION)), + @Node(coordinates = @Loc(value = WAY2_NODE2)) }, edges = { + @Edge(id = "7000001", coordinates = { @Loc(value = WAY1_NODE1), + @Loc(value = WAY1_WAY2_INTERSECTION) }, tags = "highway=primary_link"), + @Edge(id = "8000001", coordinates = { @Loc(value = WAY1_WAY2_INTERSECTION), + @Loc(value = WAY2_NODE2) }, tags = "highway=residential") }) + private Atlas truePositiveCase2; + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = WAY1_NODE1)), + @Node(coordinates = @Loc(value = WAY1_WAY2_INTERSECTION)), + @Node(coordinates = @Loc(value = WAY2_NODE2)) }, edges = { + @Edge(id = "9000001", coordinates = { @Loc(value = WAY1_NODE1), + @Loc(value = WAY1_WAY2_INTERSECTION) }, tags = "highway=tertiary"), + @Edge(id = "10000001", coordinates = { @Loc(value = WAY1_WAY2_INTERSECTION), + @Loc(value = WAY2_NODE2) }, tags = "highway=service") }) + private Atlas truePositiveCase3; + + public Atlas falsePositiveSuddenHighwayTypeChangeCheck() + { + return this.falsePositiveSuddenHighwayTypeChangeCheck; + } + + public Atlas truePositiveCase1() + { + return this.truePositiveCase1; + } + + public Atlas truePositiveCase2() + { + return this.truePositiveCase2; + } + + public Atlas truePositiveCase3() + { + return this.truePositiveCase3; + } + + public Atlas truePositiveSuddenHighwayTypeChangeCheck() + { + return this.truePositiveSuddenHighwayTypeChangeCheck; + } +}