From e038bbd9224f97403f9ba279625380ab83bfdbc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Mon, 28 Sep 2020 17:06:30 +0200 Subject: [PATCH 01/36] Implementation of Boundary Intersection Check. --- .../BoundaryIntersectionsCheck.java | 135 +++++++++++ .../BoundaryIntersectionsCheckTest.java | 59 +++++ .../BoundaryIntersectionsCheckTestRule.java | 229 ++++++++++++++++++ 3 files changed, 423 insertions(+) create mode 100644 src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java create mode 100644 src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTest.java create mode 100644 src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java new file mode 100644 index 000000000..5edb4e0e5 --- /dev/null +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java @@ -0,0 +1,135 @@ +package org.openstreetmap.atlas.checks.validation.intersections; + +import org.openstreetmap.atlas.checks.base.BaseCheck; +import org.openstreetmap.atlas.checks.flag.CheckFlag; +import org.openstreetmap.atlas.geography.Location; +import org.openstreetmap.atlas.geography.atlas.Atlas; +import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; +import org.openstreetmap.atlas.geography.atlas.items.Edge; +import org.openstreetmap.atlas.geography.atlas.items.ItemType; +import org.openstreetmap.atlas.geography.atlas.items.Relation; +import org.openstreetmap.atlas.geography.atlas.items.RelationMember; +import org.openstreetmap.atlas.geography.atlas.items.RelationMemberList; +import org.openstreetmap.atlas.tags.BoundaryTag; +import org.openstreetmap.atlas.tags.RelationTypeTag; +import org.openstreetmap.atlas.tags.annotations.validation.Validators; +import org.openstreetmap.atlas.utilities.configuration.Configuration; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * @author srachanski + */ +public class BoundaryIntersectionsCheck extends BaseCheck { + + private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0,number,#} with edge {1} is crossing invalidly with boundary(ies) {3} with edge {2}."; + private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; + private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, INVALID_BOUNDARY_FORMAT); + + private static final Predicate EDGE_AS_BOUNDARY = edge -> edge.relations() + .stream() + .anyMatch(BoundaryIntersectionsCheck::isTypeBoundaryWithBoundaryTag); + public static final String DELIMITER = ", "; + public static final int INDEX = 0; + + public BoundaryIntersectionsCheck(final Configuration configuration) { + super(configuration); + } + + private static boolean isTypeBoundaryWithBoundaryTag(AtlasObject object) { + return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && + Validators.hasValuesFor(object, BoundaryTag.class); + } + + @Override + public boolean validCheckForObject(final AtlasObject object) { + return object instanceof Relation && + isTypeBoundaryWithBoundaryTag(object); + } + + @Override + protected Optional flag(final AtlasObject object) { + Relation relation = (Relation) object; + RelationMemberList relationMembersEdges = relation.membersOfType(ItemType.EDGE); + List edges = getEdges(relationMembersEdges); + CheckFlag checkFlag = prepareCheckFlag(object, relation, edges); + if (checkFlag.getFlaggedObjects().isEmpty()) { + return Optional.empty(); + } + return Optional.of(checkFlag); + } + + private List getEdges(RelationMemberList relationMembersEdges) { + return relationMembersEdges + .stream() + .map(this::castToEdge) + .collect(Collectors.toList()); + } + + private Edge castToEdge(RelationMember relationMember) { + return (Edge) relationMember.getEntity(); + } + + private CheckFlag prepareCheckFlag(AtlasObject object, Relation relation, List edges) { + CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); + edges.forEach(edge -> analyzeIntersections(object.getAtlas(), relation, checkFlag, edges, edge)); + return checkFlag; + } + + private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag checkFlag, List edges, Edge edge) { + Set knownIntersections = new HashSet<>(); + Iterable intersections = atlas.edgesIntersecting(edge.bounds(), getPredicateForEdgesSelection(edges)); + for (Edge currentEdge : intersections) { + if (!knownIntersections.contains(currentEdge)) { + Set intersectingBoundaries = getBoundary(currentEdge); + addInformationToFlag(relation, checkFlag, edge, currentEdge, intersectingBoundaries); + knownIntersections.add(currentEdge); + } + } + } + + private void addInformationToFlag(Relation relation, CheckFlag checkFlag, Edge edge, Edge currentEdge, Set intersectingBoundaries) { + checkFlag.addPoints(getIntersectingPoints(edge, currentEdge)); + checkFlag.addObject(currentEdge); + checkFlag.addObjects(intersectingBoundaries); + checkFlag.addInstruction(this.getLocalizedInstruction(INDEX, + relation.getOsmIdentifier(), + edge.getOsmIdentifier(), + currentEdge.getOsmIdentifier(), + asList(intersectingBoundaries))); + } + + private Predicate getPredicateForEdgesSelection(List edges) { + return edgeToCheck -> EDGE_AS_BOUNDARY.test(edgeToCheck) && !edges.contains(edgeToCheck); + } + + private String asList(Set intersectingBoundaries) { + return intersectingBoundaries + .stream() + .map(relation -> Long.toString(relation.getOsmIdentifier())) + .collect(Collectors.joining(DELIMITER)); + } + + private Set getBoundary(Edge currentEdge) { + return currentEdge.relations() + .stream() + .filter(BoundaryIntersectionsCheck::isTypeBoundaryWithBoundaryTag) + .collect(Collectors.toSet()); + } + + private Set getIntersectingPoints(Edge edge, Edge currentEdge) { + return currentEdge.asPolyLine().intersections(edge.asPolyLine()); + } + + @Override + protected List getFallbackInstructions() { + return FALLBACK_INSTRUCTIONS; + } + +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTest.java new file mode 100644 index 000000000..e4c715898 --- /dev/null +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTest.java @@ -0,0 +1,59 @@ +package org.openstreetmap.atlas.checks.validation.intersections; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.openstreetmap.atlas.checks.configuration.ConfigurationResolver; +import org.openstreetmap.atlas.checks.flag.CheckFlag; +import org.openstreetmap.atlas.checks.validation.verifier.ConsumerBasedExpectedCheckVerifier; +import org.openstreetmap.atlas.geography.atlas.Atlas; +import org.openstreetmap.atlas.geography.atlas.items.complex.bignode.BigNode; +import org.openstreetmap.atlas.geography.atlas.items.complex.bignode.BigNodeFinder; +import org.openstreetmap.atlas.geography.atlas.items.complex.boundaries.ComplexBoundaryFinder; +import org.openstreetmap.atlas.utilities.configuration.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * @author srachanski + */ +public class BoundaryIntersectionsCheckTest { + + +// private static final Logger logger = LoggerFactory.getLogger(BoundaryIntersectionsCheckTest.class); + + @Rule + public BoundaryIntersectionsCheckTestRule setup = new BoundaryIntersectionsCheckTestRule(); + + @Rule + public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier(); + + private final Configuration configuration = ConfigurationResolver.emptyConfiguration(); + + @Test + public void testInvalidTwoCrossingItemsAtlas() { + this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), + new BoundaryIntersectionsCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); + this.verifier.verify(flag -> Assert.assertEquals(5, flag.getFlaggedObjects().size())); + } + + @Test + public void testInvalidThreeCrossingItemsAtlas() { + this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectOneOther(), + new BoundaryIntersectionsCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(3, flags.size())); + } + + @Test + public void testValidNonCrossingObjects() { + this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparate(), + new BoundaryIntersectionsCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); + } + +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java new file mode 100644 index 000000000..78c53d847 --- /dev/null +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java @@ -0,0 +1,229 @@ +package org.openstreetmap.atlas.checks.validation.intersections; + +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.Relation; +import org.openstreetmap.atlas.utilities.testing.TestAtlas.Edge; +import org.openstreetmap.atlas.utilities.testing.TestAtlas.Loc; +import org.openstreetmap.atlas.utilities.testing.TestAtlas.Node; + +/** + * {@link BoundaryIntersectionsCheckTest} data generator + * + * @author srachanski + */ +public class BoundaryIntersectionsCheckTestRule extends CoreTestRule { + private static final String COORD_1 = "0, 0"; + private static final String COORD_2 = "0, 2"; + private static final String COORD_3 = "2, 2"; + private static final String COORD_4 = "2, 0"; + private static final String COORD_5 = "0, 3"; + private static final String COORD_6 = "3, 3"; + private static final String COORD_7 = "0, 0"; + private static final String COORD_8 = "0, 1"; + private static final String COORD_9 = "0, 2"; + private static final String COORD_10 = "2, 2"; + private static final String COORD_11 = "2, 1"; + private static final String COORD_12 = "3, 1"; + private static final String COORD_13 = "3, 2"; + private static final String COORD_14 = "5, 2"; + private static final String COORD_15 = "5, 1"; + private static final String COORD_16 = "1, 0"; + private static final String COORD_17 = "1, 3"; + private static final String COORD_18 = "4, 3"; + private static final String COORD_19 = "4, 0"; + + + private static final String EDGE_ONE = "1000001"; + private static final String EDGE_TWO = "2000001"; + private static final String EDGE_THREE = "3000001"; + private static final String EDGE_FOUR = "4000001"; + private static final String EDGE_FIVE = "5000001"; + private static final String EDGE_SIX = "6000001"; + private static final String EDGE_SEVEN = "7000001"; + private static final String EDGE_EIGHT = "8000001"; + private static final String EDGE_NINE = "9000001"; + + private static final String RELATION_ONE = "1000011"; + private static final String RELATION_TWO = "2000011"; + private static final String RELATION_THREE = "3000011"; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), + @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), + @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) + }, + edges = { + @Edge(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_2), + @Loc(value = COORD_3), + @Loc(value = COORD_4), + @Loc(value = COORD_1)}, + tags = {"highway=motorway"}, + id = EDGE_ONE), + @Edge(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_5), + @Loc(value = COORD_6), + @Loc(value = COORD_7), + @Loc(value = COORD_1)}, + tags = {"highway=motorway"}, + id = EDGE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = EDGE_ONE, role = "outer", type = "EDGE")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = EDGE_TWO, role = "outer", type = "EDGE")}, tags = { + "type=boundary", + "boundary=administrative"})}) + private Atlas crossingBoundariesTwoAreasIntersectEachOther; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_8)), + @Node(coordinates = @Loc(value = COORD_9)), + @Node(coordinates = @Loc(value = COORD_10)), + @Node(coordinates = @Loc(value = COORD_11)), + @Node(coordinates = @Loc(value = COORD_12)), + @Node(coordinates = @Loc(value = COORD_13)), + @Node(coordinates = @Loc(value = COORD_14)), + @Node(coordinates = @Loc(value = COORD_15)) + }, + edges = { + @Edge(coordinates = { + @Loc(value = COORD_8), + @Loc(value = COORD_9), + @Loc(value = COORD_10), + @Loc(value = COORD_11), + @Loc(value = COORD_8)}, + tags = {"highway=motorway"}, + id = EDGE_ONE), + @Edge(coordinates = { + @Loc(value = COORD_12), + @Loc(value = COORD_13), + @Loc(value = COORD_14), + @Loc(value = COORD_15), + @Loc(value = COORD_12)}, + tags = {"highway=motorway"}, + id = EDGE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = EDGE_ONE, role = "outer", type = "EDGE")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = EDGE_TWO, role = "outer", type = "EDGE")}, tags = { + "type=boundary", + "boundary=administrative"})}) + private Atlas nonCrossingBoundariesTwoSeparate; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_8)), + @Node(coordinates = @Loc(value = COORD_9)), + @Node(coordinates = @Loc(value = COORD_10)), + @Node(coordinates = @Loc(value = COORD_11)), + @Node(coordinates = @Loc(value = COORD_12)), + @Node(coordinates = @Loc(value = COORD_13)), + @Node(coordinates = @Loc(value = COORD_14)), + @Node(coordinates = @Loc(value = COORD_15)), + @Node(coordinates = @Loc(value = COORD_16)), + @Node(coordinates = @Loc(value = COORD_17)), + @Node(coordinates = @Loc(value = COORD_18)), + @Node(coordinates = @Loc(value = COORD_19)) + }, + edges = { + @Edge(coordinates = { + @Loc(value = COORD_8), + @Loc(value = COORD_9)}, + id = EDGE_ONE), + @Edge(coordinates = { + @Loc(value = COORD_9), + @Loc(value = COORD_10)}, + id = EDGE_TWO), + @Edge(coordinates = { + @Loc(value = COORD_10), + @Loc(value = COORD_11)}, + id = EDGE_THREE), + @Edge(coordinates = { + @Loc(value = COORD_11), + @Loc(value = COORD_8)}, + id = EDGE_FOUR), + @Edge(coordinates = { + @Loc(value = COORD_12), + @Loc(value = COORD_13), + @Loc(value = COORD_14), + @Loc(value = COORD_15), + @Loc(value = COORD_12)}, + id = EDGE_FIVE), + @Edge(coordinates = { + @Loc(value = COORD_16), + @Loc(value = COORD_17)}, + id = EDGE_SIX), + @Edge(coordinates = { + @Loc(value = COORD_17), + @Loc(value = COORD_18)}, + id = EDGE_SEVEN), + @Edge(coordinates = { + @Loc(value = COORD_18), + @Loc(value = COORD_19)}, + id = EDGE_EIGHT), + @Edge(coordinates = { + @Loc(value = COORD_19), + @Loc(value = COORD_16)}, + id = EDGE_NINE)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = EDGE_ONE, role = "outer", type = "EDGE"), + @Relation.Member(id = EDGE_TWO, role = "outer", type = "EDGE"), + @Relation.Member(id = EDGE_THREE, role = "outer", type = "EDGE"), + @Relation.Member(id = EDGE_FOUR, role = "outer", type = "EDGE") + }, + tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = EDGE_FIVE, role = "outer", type = "EDGE")}, + tags = { + "type=boundary", + "boundary=maritime"}), + @Relation(id = RELATION_THREE, + members = { + @Relation.Member(id = EDGE_SIX, role = "outer", type = "EDGE"), + @Relation.Member(id = EDGE_SEVEN, role = "outer", type = "EDGE"), + @Relation.Member(id = EDGE_EIGHT, role = "outer", type = "EDGE"), + @Relation.Member(id = EDGE_NINE, role = "outer", type = "EDGE") + }, + tags = { + "type=boundary", + "boundary=political"})}) + private Atlas crossingBoundariesTwoAreasIntersectOneOther; + + public Atlas crossingBoundariesTwoAreasIntersectEachOther() { + return this.crossingBoundariesTwoAreasIntersectEachOther; + } + + public Atlas nonCrossingBoundariesTwoSeparate() { + return this.nonCrossingBoundariesTwoSeparate; + } + + public Atlas crossingBoundariesTwoAreasIntersectOneOther() { + return this.crossingBoundariesTwoAreasIntersectOneOther; + } + +} From e8691ff3e4279f50239feb54a8d6e9f66cdeb641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Tue, 29 Sep 2020 15:11:11 +0200 Subject: [PATCH 02/36] Edge changed to LineItem. --- config/configuration.json | 8 ++ .../BoundaryIntersectionsCheck.java | 61 +++++----- .../BoundaryIntersectionsCheckTestRule.java | 108 +++++++++--------- 3 files changed, 91 insertions(+), 86 deletions(-) diff --git a/config/configuration.json b/config/configuration.json index f2ce447af..52e6096e3 100644 --- a/config/configuration.json +++ b/config/configuration.json @@ -114,6 +114,14 @@ } } }, + "BoundaryIntersectionCheck": { + "challenge": { + "description": "Task contains Boundaries information describing their intersection", + "blurb": "Boundaries Intersecting", + "instruction": "Open your favorite editor, check the instruction and modify the points/ways that are causing boundaries to intersect.", + "difficulty": "NORMAL" + } + }, "BuildingRoadIntersectionCheck": { "car.navigable": true, "challenge": { diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java index 5edb4e0e5..f24075dd8 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java @@ -5,8 +5,8 @@ import org.openstreetmap.atlas.geography.Location; import org.openstreetmap.atlas.geography.atlas.Atlas; import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; -import org.openstreetmap.atlas.geography.atlas.items.Edge; import org.openstreetmap.atlas.geography.atlas.items.ItemType; +import org.openstreetmap.atlas.geography.atlas.items.LineItem; import org.openstreetmap.atlas.geography.atlas.items.Relation; import org.openstreetmap.atlas.geography.atlas.items.RelationMember; import org.openstreetmap.atlas.geography.atlas.items.RelationMemberList; @@ -32,7 +32,7 @@ public class BoundaryIntersectionsCheck extends BaseCheck { private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, INVALID_BOUNDARY_FORMAT); - private static final Predicate EDGE_AS_BOUNDARY = edge -> edge.relations() + private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem.relations() .stream() .anyMatch(BoundaryIntersectionsCheck::isTypeBoundaryWithBoundaryTag); public static final String DELIMITER = ", "; @@ -56,57 +56,58 @@ public boolean validCheckForObject(final AtlasObject object) { @Override protected Optional flag(final AtlasObject object) { Relation relation = (Relation) object; - RelationMemberList relationMembersEdges = relation.membersOfType(ItemType.EDGE); - List edges = getEdges(relationMembersEdges); - CheckFlag checkFlag = prepareCheckFlag(object, relation, edges); + RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); + relationMemberLineItems.addAll(relation.membersOfType(ItemType.LINE)); + List lineItems = getLineItems(relationMemberLineItems); + CheckFlag checkFlag = prepareCheckFlag(object, relation, lineItems); if (checkFlag.getFlaggedObjects().isEmpty()) { return Optional.empty(); } return Optional.of(checkFlag); } - private List getEdges(RelationMemberList relationMembersEdges) { + private List getLineItems(RelationMemberList relationMembersEdges) { return relationMembersEdges .stream() - .map(this::castToEdge) + .map(this::castToLineItem) .collect(Collectors.toList()); } - private Edge castToEdge(RelationMember relationMember) { - return (Edge) relationMember.getEntity(); + private LineItem castToLineItem(RelationMember relationMember) { + return (LineItem) relationMember.getEntity(); } - private CheckFlag prepareCheckFlag(AtlasObject object, Relation relation, List edges) { + private CheckFlag prepareCheckFlag(AtlasObject object, Relation relation, List lineItems) { CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); - edges.forEach(edge -> analyzeIntersections(object.getAtlas(), relation, checkFlag, edges, edge)); + lineItems.forEach(lineItem -> analyzeIntersections(object.getAtlas(), relation, checkFlag, lineItems, lineItem)); return checkFlag; } - private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag checkFlag, List edges, Edge edge) { - Set knownIntersections = new HashSet<>(); - Iterable intersections = atlas.edgesIntersecting(edge.bounds(), getPredicateForEdgesSelection(edges)); - for (Edge currentEdge : intersections) { - if (!knownIntersections.contains(currentEdge)) { - Set intersectingBoundaries = getBoundary(currentEdge); - addInformationToFlag(relation, checkFlag, edge, currentEdge, intersectingBoundaries); - knownIntersections.add(currentEdge); + private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag checkFlag, List lineItems, LineItem lineItem) { + Set knownIntersections = new HashSet<>(); + Iterable intersections = atlas.lineItemsIntersecting(lineItem.bounds(), getPredicateForLineItemsSelection(lineItems)); + for (LineItem currentLineItem : intersections) { + if (!knownIntersections.contains(currentLineItem)) { + Set intersectingBoundaries = getBoundary(currentLineItem); + addInformationToFlag(relation, checkFlag, lineItem, currentLineItem, intersectingBoundaries); + knownIntersections.add(currentLineItem); } } } - private void addInformationToFlag(Relation relation, CheckFlag checkFlag, Edge edge, Edge currentEdge, Set intersectingBoundaries) { - checkFlag.addPoints(getIntersectingPoints(edge, currentEdge)); - checkFlag.addObject(currentEdge); + private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineItem lineItem, LineItem currentLineItem, Set intersectingBoundaries) { + checkFlag.addPoints(getIntersectingPoints(lineItem, currentLineItem)); + checkFlag.addObject(currentLineItem); checkFlag.addObjects(intersectingBoundaries); checkFlag.addInstruction(this.getLocalizedInstruction(INDEX, relation.getOsmIdentifier(), - edge.getOsmIdentifier(), - currentEdge.getOsmIdentifier(), + lineItem.getOsmIdentifier(), + currentLineItem.getOsmIdentifier(), asList(intersectingBoundaries))); } - private Predicate getPredicateForEdgesSelection(List edges) { - return edgeToCheck -> EDGE_AS_BOUNDARY.test(edgeToCheck) && !edges.contains(edgeToCheck); + private Predicate getPredicateForLineItemsSelection(List lineItems) { + return lineItemToCheck -> LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && !lineItems.contains(lineItemToCheck); } private String asList(Set intersectingBoundaries) { @@ -116,15 +117,15 @@ private String asList(Set intersectingBoundaries) { .collect(Collectors.joining(DELIMITER)); } - private Set getBoundary(Edge currentEdge) { - return currentEdge.relations() + private Set getBoundary(LineItem currentLineItem) { + return currentLineItem.relations() .stream() .filter(BoundaryIntersectionsCheck::isTypeBoundaryWithBoundaryTag) .collect(Collectors.toSet()); } - private Set getIntersectingPoints(Edge edge, Edge currentEdge) { - return currentEdge.asPolyLine().intersections(edge.asPolyLine()); + private Set getIntersectingPoints(LineItem lineItem, LineItem currentLineItem) { + return currentLineItem.asPolyLine().intersections(lineItem.asPolyLine()); } @Override diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java index 78c53d847..a49e2316d 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java @@ -4,7 +4,7 @@ import org.openstreetmap.atlas.utilities.testing.CoreTestRule; import org.openstreetmap.atlas.utilities.testing.TestAtlas; import org.openstreetmap.atlas.utilities.testing.TestAtlas.Relation; -import org.openstreetmap.atlas.utilities.testing.TestAtlas.Edge; +import org.openstreetmap.atlas.utilities.testing.TestAtlas.Line; import org.openstreetmap.atlas.utilities.testing.TestAtlas.Loc; import org.openstreetmap.atlas.utilities.testing.TestAtlas.Node; @@ -35,15 +35,15 @@ public class BoundaryIntersectionsCheckTestRule extends CoreTestRule { private static final String COORD_19 = "4, 0"; - private static final String EDGE_ONE = "1000001"; - private static final String EDGE_TWO = "2000001"; - private static final String EDGE_THREE = "3000001"; - private static final String EDGE_FOUR = "4000001"; - private static final String EDGE_FIVE = "5000001"; - private static final String EDGE_SIX = "6000001"; - private static final String EDGE_SEVEN = "7000001"; - private static final String EDGE_EIGHT = "8000001"; - private static final String EDGE_NINE = "9000001"; + private static final String LINE_ONE = "1000001"; + private static final String LINE_TWO = "2000001"; + private static final String LINE_THREE = "3000001"; + private static final String LINE_FOUR = "4000001"; + private static final String LINE_FIVE = "5000001"; + private static final String LINE_SIX = "6000001"; + private static final String LINE_SEVEN = "7000001"; + private static final String LINE_EIGHT = "8000001"; + private static final String LINE_NINE = "9000001"; private static final String RELATION_ONE = "1000011"; private static final String RELATION_TWO = "2000011"; @@ -59,32 +59,30 @@ public class BoundaryIntersectionsCheckTestRule extends CoreTestRule { @Node(coordinates = @Loc(value = COORD_6)), @Node(coordinates = @Loc(value = COORD_7)) }, - edges = { - @Edge(coordinates = { + lines = { + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_2), @Loc(value = COORD_3), @Loc(value = COORD_4), @Loc(value = COORD_1)}, - tags = {"highway=motorway"}, - id = EDGE_ONE), - @Edge(coordinates = { + id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), @Loc(value = COORD_6), @Loc(value = COORD_7), @Loc(value = COORD_1)}, - tags = {"highway=motorway"}, - id = EDGE_TWO)}, + id = LINE_TWO)}, relations = { @Relation(id = RELATION_ONE, members = { - @Relation.Member(id = EDGE_ONE, role = "outer", type = "EDGE")}, tags = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { "type=boundary", "boundary=administrative"}), @Relation(id = RELATION_TWO, members = { - @Relation.Member(id = EDGE_TWO, role = "outer", type = "EDGE")}, tags = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { "type=boundary", "boundary=administrative"})}) private Atlas crossingBoundariesTwoAreasIntersectEachOther; @@ -100,32 +98,30 @@ public class BoundaryIntersectionsCheckTestRule extends CoreTestRule { @Node(coordinates = @Loc(value = COORD_14)), @Node(coordinates = @Loc(value = COORD_15)) }, - edges = { - @Edge(coordinates = { + lines = { + @Line(coordinates = { @Loc(value = COORD_8), @Loc(value = COORD_9), @Loc(value = COORD_10), @Loc(value = COORD_11), @Loc(value = COORD_8)}, - tags = {"highway=motorway"}, - id = EDGE_ONE), - @Edge(coordinates = { + id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_12), @Loc(value = COORD_13), @Loc(value = COORD_14), @Loc(value = COORD_15), @Loc(value = COORD_12)}, - tags = {"highway=motorway"}, - id = EDGE_TWO)}, + id = LINE_TWO)}, relations = { @Relation(id = RELATION_ONE, members = { - @Relation.Member(id = EDGE_ONE, role = "outer", type = "EDGE")}, tags = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { "type=boundary", "boundary=administrative"}), @Relation(id = RELATION_TWO, members = { - @Relation.Member(id = EDGE_TWO, role = "outer", type = "EDGE")}, tags = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { "type=boundary", "boundary=administrative"})}) private Atlas nonCrossingBoundariesTwoSeparate; @@ -145,69 +141,69 @@ public class BoundaryIntersectionsCheckTestRule extends CoreTestRule { @Node(coordinates = @Loc(value = COORD_18)), @Node(coordinates = @Loc(value = COORD_19)) }, - edges = { - @Edge(coordinates = { + lines = { + @Line(coordinates = { @Loc(value = COORD_8), @Loc(value = COORD_9)}, - id = EDGE_ONE), - @Edge(coordinates = { + id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_9), @Loc(value = COORD_10)}, - id = EDGE_TWO), - @Edge(coordinates = { + id = LINE_TWO), + @Line(coordinates = { @Loc(value = COORD_10), @Loc(value = COORD_11)}, - id = EDGE_THREE), - @Edge(coordinates = { + id = LINE_THREE), + @Line(coordinates = { @Loc(value = COORD_11), @Loc(value = COORD_8)}, - id = EDGE_FOUR), - @Edge(coordinates = { + id = LINE_FOUR), + @Line(coordinates = { @Loc(value = COORD_12), @Loc(value = COORD_13), @Loc(value = COORD_14), @Loc(value = COORD_15), @Loc(value = COORD_12)}, - id = EDGE_FIVE), - @Edge(coordinates = { + id = LINE_FIVE), + @Line(coordinates = { @Loc(value = COORD_16), @Loc(value = COORD_17)}, - id = EDGE_SIX), - @Edge(coordinates = { + id = LINE_SIX), + @Line(coordinates = { @Loc(value = COORD_17), @Loc(value = COORD_18)}, - id = EDGE_SEVEN), - @Edge(coordinates = { + id = LINE_SEVEN), + @Line(coordinates = { @Loc(value = COORD_18), @Loc(value = COORD_19)}, - id = EDGE_EIGHT), - @Edge(coordinates = { + id = LINE_EIGHT), + @Line(coordinates = { @Loc(value = COORD_19), @Loc(value = COORD_16)}, - id = EDGE_NINE)}, + id = LINE_NINE)}, relations = { @Relation(id = RELATION_ONE, members = { - @Relation.Member(id = EDGE_ONE, role = "outer", type = "EDGE"), - @Relation.Member(id = EDGE_TWO, role = "outer", type = "EDGE"), - @Relation.Member(id = EDGE_THREE, role = "outer", type = "EDGE"), - @Relation.Member(id = EDGE_FOUR, role = "outer", type = "EDGE") + @Relation.Member(id = LINE_ONE, role = "outer", type = "line"), + @Relation.Member(id = LINE_TWO, role = "outer", type = "line"), + @Relation.Member(id = LINE_THREE, role = "outer", type = "line"), + @Relation.Member(id = LINE_FOUR, role = "outer", type = "line") }, tags = { "type=boundary", "boundary=administrative"}), @Relation(id = RELATION_TWO, members = { - @Relation.Member(id = EDGE_FIVE, role = "outer", type = "EDGE")}, + @Relation.Member(id = LINE_FIVE, role = "outer", type = "line")}, tags = { "type=boundary", "boundary=maritime"}), @Relation(id = RELATION_THREE, members = { - @Relation.Member(id = EDGE_SIX, role = "outer", type = "EDGE"), - @Relation.Member(id = EDGE_SEVEN, role = "outer", type = "EDGE"), - @Relation.Member(id = EDGE_EIGHT, role = "outer", type = "EDGE"), - @Relation.Member(id = EDGE_NINE, role = "outer", type = "EDGE") + @Relation.Member(id = LINE_SIX, role = "outer", type = "line"), + @Relation.Member(id = LINE_SEVEN, role = "outer", type = "line"), + @Relation.Member(id = LINE_EIGHT, role = "outer", type = "line"), + @Relation.Member(id = LINE_NINE, role = "outer", type = "line") }, tags = { "type=boundary", From 256be1b9953ad321205422df6d93a06887657267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 30 Sep 2020 16:10:27 +0200 Subject: [PATCH 03/36] Renamed, finding intersections improved, test cases added. --- ...ck.java => BoundaryIntersectionCheck.java} | 56 ++- .../BoundaryIntersectionCheckTest.java | 84 ++++ .../BoundaryIntersectionCheckTestRule.java | 441 ++++++++++++++++++ .../BoundaryIntersectionsCheckTest.java | 59 --- .../BoundaryIntersectionsCheckTestRule.java | 225 --------- 5 files changed, 569 insertions(+), 296 deletions(-) rename src/main/java/org/openstreetmap/atlas/checks/validation/intersections/{BoundaryIntersectionsCheck.java => BoundaryIntersectionCheck.java} (70%) create mode 100644 src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java create mode 100644 src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java delete mode 100644 src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTest.java delete mode 100644 src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java similarity index 70% rename from src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java rename to src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index f24075dd8..b3101b1c0 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -1,8 +1,10 @@ package org.openstreetmap.atlas.checks.validation.intersections; +import io.netty.util.internal.StringUtil; import org.openstreetmap.atlas.checks.base.BaseCheck; import org.openstreetmap.atlas.checks.flag.CheckFlag; import org.openstreetmap.atlas.geography.Location; +import org.openstreetmap.atlas.geography.PolyLine; import org.openstreetmap.atlas.geography.atlas.Atlas; import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; import org.openstreetmap.atlas.geography.atlas.items.ItemType; @@ -15,30 +17,33 @@ import org.openstreetmap.atlas.tags.annotations.validation.Validators; import org.openstreetmap.atlas.utilities.configuration.Configuration; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; /** * @author srachanski */ -public class BoundaryIntersectionsCheck extends BaseCheck { +public class BoundaryIntersectionCheck extends BaseCheck { - private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0,number,#} with edge {1} is crossing invalidly with boundary(ies) {3} with edge {2}."; + private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0,number,#} with way {1} is crossing invalidly with boundary(ies) {3} with way {2}."; private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, INVALID_BOUNDARY_FORMAT); private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem.relations() .stream() - .anyMatch(BoundaryIntersectionsCheck::isTypeBoundaryWithBoundaryTag); + .anyMatch(BoundaryIntersectionCheck::isTypeBoundaryWithBoundaryTag); public static final String DELIMITER = ", "; public static final int INDEX = 0; - public BoundaryIntersectionsCheck(final Configuration configuration) { + public BoundaryIntersectionCheck(final Configuration configuration) { super(configuration); } @@ -85,7 +90,12 @@ private CheckFlag prepareCheckFlag(AtlasObject object, Relation relation, List lineItems, LineItem lineItem) { Set knownIntersections = new HashSet<>(); - Iterable intersections = atlas.lineItemsIntersecting(lineItem.bounds(), getPredicateForLineItemsSelection(lineItems)); + List polyLines = getPolyLines(lineItem); + Set intersections = polyLines + .stream() + .map(polyLine -> atlas.lineItemsIntersecting(polyLine.bounds(), getPredicateForLineItemsSelection(lineItems))) + .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) + .collect(Collectors.toSet()); for (LineItem currentLineItem : intersections) { if (!knownIntersections.contains(currentLineItem)) { Set intersectingBoundaries = getBoundary(currentLineItem); @@ -95,19 +105,41 @@ private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag chec } } + private List getPolyLines(LineItem lineItem) { + List polyLines = new ArrayList<>(); + Iterator iterator = lineItem.asPolyLine().iterator(); + if(iterator.hasNext()) { + Location lastLocation = iterator.next(); + for (int i = 0; i < lineItem.asPolyLine().size() - 1; i++) { + Location location1 = lastLocation; + Location location2 = iterator.next(); + polyLines.add(PolyLine.wkt(String.format("LINESTRING(%s %s, %s %s)", + location1.getLatitude(), + location1.getLongitude(), + location2.getLatitude(), + location2.getLongitude()))); + lastLocation = location2; + } + } + return polyLines; + } + private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineItem lineItem, LineItem currentLineItem, Set intersectingBoundaries) { checkFlag.addPoints(getIntersectingPoints(lineItem, currentLineItem)); checkFlag.addObject(currentLineItem); checkFlag.addObjects(intersectingBoundaries); - checkFlag.addInstruction(this.getLocalizedInstruction(INDEX, - relation.getOsmIdentifier(), - lineItem.getOsmIdentifier(), - currentLineItem.getOsmIdentifier(), - asList(intersectingBoundaries))); + if(StringUtil.isNullOrEmpty(checkFlag.getInstructions())) { + checkFlag.addInstruction(this.getLocalizedInstruction(INDEX, + relation.getOsmIdentifier(), + lineItem.getOsmIdentifier(), + currentLineItem.getOsmIdentifier(), + asList(intersectingBoundaries))); + } } private Predicate getPredicateForLineItemsSelection(List lineItems) { - return lineItemToCheck -> LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && !lineItems.contains(lineItemToCheck); + return lineItemToCheck -> LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && + !lineItems.contains(lineItemToCheck); } private String asList(Set intersectingBoundaries) { @@ -120,7 +152,7 @@ private String asList(Set intersectingBoundaries) { private Set getBoundary(LineItem currentLineItem) { return currentLineItem.relations() .stream() - .filter(BoundaryIntersectionsCheck::isTypeBoundaryWithBoundaryTag) + .filter(BoundaryIntersectionCheck::isTypeBoundaryWithBoundaryTag) .collect(Collectors.toSet()); } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java new file mode 100644 index 000000000..078913259 --- /dev/null +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -0,0 +1,84 @@ +package org.openstreetmap.atlas.checks.validation.intersections; + +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; + +/** + * @author srachanski + */ +public class BoundaryIntersectionCheckTest { + + +// private static final Logger logger = LoggerFactory.getLogger(BoundaryIntersectionsCheckTest.class); + + @Rule + public BoundaryIntersectionCheckTestRule setup = new BoundaryIntersectionCheckTestRule(); + + @Rule + public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier(); + + private final Configuration configuration = ConfigurationResolver.emptyConfiguration(); + + @Test + public void testInvalidTwoCrossingItemsAtlas() { + this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); + this.verifier.verify(flag -> Assert.assertEquals(5, flag.getFlaggedObjects().size())); + } + + @Test + public void testInvalidThreeCrossingItemsAtlas() { + this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectOneOther(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(3, flags.size())); + } + + @Test + public void testInvalidTwoCrossingItemsWithEdgesAtlas() { + this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOtherWithEdges(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); + this.verifier.verify(flag -> Assert.assertEquals(5, flag.getFlaggedObjects().size())); + } + + @Test + public void testValidNonCrossingObjects() { + this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparate(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); + } + + @Test + public void testValidNonCrossingObjectsOneContainOther() { + this.verifier.actual(this.setup.nonCrossingOneContainOther(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); + } + + @Test + public void testValidNonCrossingObjectsWithEdges() { + this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparateWithEdges(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); + } + + @Test + public void testValidCrossingObjectsOneMissingType() { + this.verifier.actual(this.setup.crossingOneWithWrongType(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); + } + + @Test + public void testValidCrossingObjectsOneMissingBoundarySpecificTag() { + this.verifier.actual(this.setup.crossingOneMissingBoundarySpecificTag(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); + } + +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java new file mode 100644 index 000000000..29fe0857c --- /dev/null +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -0,0 +1,441 @@ +package org.openstreetmap.atlas.checks.validation.intersections; + +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.Line; +import org.openstreetmap.atlas.utilities.testing.TestAtlas.Loc; +import org.openstreetmap.atlas.utilities.testing.TestAtlas.Node; +import org.openstreetmap.atlas.utilities.testing.TestAtlas.Relation; + +/** + * {@link BoundaryIntersectionCheckTest} data generator + * + * @author srachanski + */ +public class BoundaryIntersectionCheckTestRule extends CoreTestRule { + private static final String COORD_1 = "0, 0"; + private static final String COORD_2 = "0, 2"; + private static final String COORD_3 = "2, 2"; + private static final String COORD_4 = "2, 0"; + private static final String COORD_5 = "0, 3"; + private static final String COORD_6 = "3, 3"; + private static final String COORD_7 = "0, 0"; + private static final String COORD_8 = "0, 1"; + private static final String COORD_9 = "0, 2"; + private static final String COORD_10 = "2, 2"; + private static final String COORD_11 = "2, 1"; + private static final String COORD_12 = "3, 1"; + private static final String COORD_13 = "3, 2"; + private static final String COORD_14 = "5, 2"; + private static final String COORD_15 = "5, 1"; + private static final String COORD_16 = "1, 0"; + private static final String COORD_17 = "1, 3"; + private static final String COORD_18 = "4, 3"; + private static final String COORD_19 = "4, 0"; + private static final String COORD_20 = "1, 1"; + private static final String COORD_21 = "1, 2"; + + + private static final String LINE_ONE = "123456781000001"; + private static final String LINE_TWO = "2000001"; + private static final String LINE_THREE = "3000001"; + private static final String LINE_FOUR = "4000001"; + private static final String LINE_FIVE = "5000001"; + private static final String LINE_SIX = "6000001"; + private static final String LINE_SEVEN = "7000001"; + private static final String LINE_EIGHT = "8000001"; + private static final String LINE_NINE = "9000001"; + + private static final String EDGE_ONE = "11000001"; + private static final String EDGE_TWO = "12000001"; + + private static final String RELATION_ONE = "1021000011"; + private static final String RELATION_TWO = "22000011"; + private static final String RELATION_THREE = "23000011"; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), + @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), + @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) + }, + lines = { + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_2), + @Loc(value = COORD_3), + @Loc(value = COORD_4), + @Loc(value = COORD_1)}, + id = LINE_ONE), + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_5), + @Loc(value = COORD_6), + @Loc(value = COORD_7), + @Loc(value = COORD_1)}, + id = LINE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"})}) + private Atlas crossingBoundariesTwoAreasIntersectEachOther; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), + @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), + @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) + }, + edges = { + @Edge(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_2), + @Loc(value = COORD_3), + @Loc(value = COORD_4), + @Loc(value = COORD_1)}, + id = EDGE_ONE), + @Edge(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_5), + @Loc(value = COORD_6), + @Loc(value = COORD_7), + @Loc(value = COORD_1)}, + id = EDGE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = EDGE_ONE, role = "outer", type = "edge")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = EDGE_TWO, role = "outer", type = "edge")}, tags = { + "type=boundary", + "boundary=administrative"})}) + private Atlas crossingBoundariesTwoAreasIntersectEachOtherWithEdges; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_8)), + @Node(coordinates = @Loc(value = COORD_9)), + @Node(coordinates = @Loc(value = COORD_10)), + @Node(coordinates = @Loc(value = COORD_11)), + @Node(coordinates = @Loc(value = COORD_12)), + @Node(coordinates = @Loc(value = COORD_13)), + @Node(coordinates = @Loc(value = COORD_14)), + @Node(coordinates = @Loc(value = COORD_15)) + }, + lines = { + @Line(coordinates = { + @Loc(value = COORD_8), + @Loc(value = COORD_9), + @Loc(value = COORD_10), + @Loc(value = COORD_11), + @Loc(value = COORD_8)}, + id = LINE_ONE), + @Line(coordinates = { + @Loc(value = COORD_12), + @Loc(value = COORD_13), + @Loc(value = COORD_14), + @Loc(value = COORD_15), + @Loc(value = COORD_12)}, + id = LINE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"})}) + private Atlas nonCrossingBoundariesTwoSeparate; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_8)), + @Node(coordinates = @Loc(value = COORD_9)), + @Node(coordinates = @Loc(value = COORD_10)), + @Node(coordinates = @Loc(value = COORD_11)), + @Node(coordinates = @Loc(value = COORD_12)), + @Node(coordinates = @Loc(value = COORD_13)), + @Node(coordinates = @Loc(value = COORD_14)), + @Node(coordinates = @Loc(value = COORD_15)) + }, + edges = { + @Edge(coordinates = { + @Loc(value = COORD_8), + @Loc(value = COORD_9), + @Loc(value = COORD_10), + @Loc(value = COORD_11), + @Loc(value = COORD_8)}, + id = EDGE_ONE), + @Edge(coordinates = { + @Loc(value = COORD_12), + @Loc(value = COORD_13), + @Loc(value = COORD_14), + @Loc(value = COORD_15), + @Loc(value = COORD_12)}, + id = EDGE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = EDGE_ONE, role = "outer", type = "edge")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = EDGE_TWO, role = "outer", type = "edge")}, tags = { + "type=boundary", + "boundary=administrative"})}) + private Atlas nonCrossingBoundariesTwoSeparateWithEdges; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_8)), + @Node(coordinates = @Loc(value = COORD_9)), + @Node(coordinates = @Loc(value = COORD_10)), + @Node(coordinates = @Loc(value = COORD_11)), + @Node(coordinates = @Loc(value = COORD_12)), + @Node(coordinates = @Loc(value = COORD_13)), + @Node(coordinates = @Loc(value = COORD_14)), + @Node(coordinates = @Loc(value = COORD_15)), + @Node(coordinates = @Loc(value = COORD_16)), + @Node(coordinates = @Loc(value = COORD_17)), + @Node(coordinates = @Loc(value = COORD_18)), + @Node(coordinates = @Loc(value = COORD_19)) + }, + lines = { + @Line(coordinates = { + @Loc(value = COORD_8), + @Loc(value = COORD_9)}, + id = LINE_ONE), + @Line(coordinates = { + @Loc(value = COORD_9), + @Loc(value = COORD_10)}, + id = LINE_TWO), + @Line(coordinates = { + @Loc(value = COORD_10), + @Loc(value = COORD_11)}, + id = LINE_THREE), + @Line(coordinates = { + @Loc(value = COORD_11), + @Loc(value = COORD_8)}, + id = LINE_FOUR), + @Line(coordinates = { + @Loc(value = COORD_12), + @Loc(value = COORD_13), + @Loc(value = COORD_14), + @Loc(value = COORD_15), + @Loc(value = COORD_12)}, + id = LINE_FIVE), + @Line(coordinates = { + @Loc(value = COORD_16), + @Loc(value = COORD_17)}, + id = LINE_SIX), + @Line(coordinates = { + @Loc(value = COORD_17), + @Loc(value = COORD_18)}, + id = LINE_SEVEN), + @Line(coordinates = { + @Loc(value = COORD_18), + @Loc(value = COORD_19)}, + id = LINE_EIGHT), + @Line(coordinates = { + @Loc(value = COORD_19), + @Loc(value = COORD_16)}, + id = LINE_NINE)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line"), + @Relation.Member(id = LINE_TWO, role = "outer", type = "line"), + @Relation.Member(id = LINE_THREE, role = "outer", type = "line"), + @Relation.Member(id = LINE_FOUR, role = "outer", type = "line") + }, + tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = LINE_FIVE, role = "outer", type = "line")}, + tags = { + "type=boundary", + "boundary=maritime"}), + @Relation(id = RELATION_THREE, + members = { + @Relation.Member(id = LINE_SIX, role = "outer", type = "line"), + @Relation.Member(id = LINE_SEVEN, role = "outer", type = "line"), + @Relation.Member(id = LINE_EIGHT, role = "outer", type = "line"), + @Relation.Member(id = LINE_NINE, role = "outer", type = "line") + }, + tags = { + "type=boundary", + "boundary=political"})}) + private Atlas crossingBoundariesTwoAreasIntersectOneOther; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), + @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), + @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) + }, + lines = { + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_19), + @Loc(value = COORD_6), + @Loc(value = COORD_5), + @Loc(value = COORD_1)}, + id = LINE_ONE), + @Line(coordinates = { + @Loc(value = COORD_20), + @Loc(value = COORD_11), + @Loc(value = COORD_3), + @Loc(value = COORD_21), + @Loc(value = COORD_20)}, + id = LINE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"})}) + private Atlas nonCrossingOneContainOther; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), + @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), + @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) + }, + lines = { + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_2), + @Loc(value = COORD_3), + @Loc(value = COORD_4), + @Loc(value = COORD_1)}, + id = LINE_ONE), + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_5), + @Loc(value = COORD_6), + @Loc(value = COORD_7), + @Loc(value = COORD_1)}, + id = LINE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { + "type=nonBoundary", + "boundary=administrative"})}) + private Atlas crossingOneWithWrongType; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), + @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), + @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) + }, + lines = { + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_2), + @Loc(value = COORD_3), + @Loc(value = COORD_4), + @Loc(value = COORD_1)}, + id = LINE_ONE), + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_5), + @Loc(value = COORD_6), + @Loc(value = COORD_7), + @Loc(value = COORD_1)}, + id = LINE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { + "type=nonBoundary"})}) + private Atlas crossingOneMissingBoundarySpecificTag; + + public Atlas crossingBoundariesTwoAreasIntersectEachOther() { + return this.crossingBoundariesTwoAreasIntersectEachOther; + } + + public Atlas crossingBoundariesTwoAreasIntersectEachOtherWithEdges() { + return this.crossingBoundariesTwoAreasIntersectEachOtherWithEdges; + } + + public Atlas nonCrossingBoundariesTwoSeparate() { + return this.nonCrossingBoundariesTwoSeparate; + } + + public Atlas nonCrossingOneContainOther() { + return this.nonCrossingOneContainOther; + } + + public Atlas crossingOneWithWrongType() { + return this.crossingOneWithWrongType; + } + + public Atlas crossingOneMissingBoundarySpecificTag() { + return this.crossingOneMissingBoundarySpecificTag; + } + + public Atlas nonCrossingBoundariesTwoSeparateWithEdges() { + return this.nonCrossingBoundariesTwoSeparateWithEdges; + } + + public Atlas crossingBoundariesTwoAreasIntersectOneOther() { + return this.crossingBoundariesTwoAreasIntersectOneOther; + } + +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTest.java deleted file mode 100644 index e4c715898..000000000 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.openstreetmap.atlas.checks.validation.intersections; - -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.openstreetmap.atlas.checks.configuration.ConfigurationResolver; -import org.openstreetmap.atlas.checks.flag.CheckFlag; -import org.openstreetmap.atlas.checks.validation.verifier.ConsumerBasedExpectedCheckVerifier; -import org.openstreetmap.atlas.geography.atlas.Atlas; -import org.openstreetmap.atlas.geography.atlas.items.complex.bignode.BigNode; -import org.openstreetmap.atlas.geography.atlas.items.complex.bignode.BigNodeFinder; -import org.openstreetmap.atlas.geography.atlas.items.complex.boundaries.ComplexBoundaryFinder; -import org.openstreetmap.atlas.utilities.configuration.Configuration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -/** - * @author srachanski - */ -public class BoundaryIntersectionsCheckTest { - - -// private static final Logger logger = LoggerFactory.getLogger(BoundaryIntersectionsCheckTest.class); - - @Rule - public BoundaryIntersectionsCheckTestRule setup = new BoundaryIntersectionsCheckTestRule(); - - @Rule - public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier(); - - private final Configuration configuration = ConfigurationResolver.emptyConfiguration(); - - @Test - public void testInvalidTwoCrossingItemsAtlas() { - this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), - new BoundaryIntersectionsCheck(this.configuration)); - this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); - this.verifier.verify(flag -> Assert.assertEquals(5, flag.getFlaggedObjects().size())); - } - - @Test - public void testInvalidThreeCrossingItemsAtlas() { - this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectOneOther(), - new BoundaryIntersectionsCheck(this.configuration)); - this.verifier.globallyVerify(flags -> Assert.assertEquals(3, flags.size())); - } - - @Test - public void testValidNonCrossingObjects() { - this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparate(), - new BoundaryIntersectionsCheck(this.configuration)); - this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); - } - -} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java deleted file mode 100644 index a49e2316d..000000000 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionsCheckTestRule.java +++ /dev/null @@ -1,225 +0,0 @@ -package org.openstreetmap.atlas.checks.validation.intersections; - -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.Relation; -import org.openstreetmap.atlas.utilities.testing.TestAtlas.Line; -import org.openstreetmap.atlas.utilities.testing.TestAtlas.Loc; -import org.openstreetmap.atlas.utilities.testing.TestAtlas.Node; - -/** - * {@link BoundaryIntersectionsCheckTest} data generator - * - * @author srachanski - */ -public class BoundaryIntersectionsCheckTestRule extends CoreTestRule { - private static final String COORD_1 = "0, 0"; - private static final String COORD_2 = "0, 2"; - private static final String COORD_3 = "2, 2"; - private static final String COORD_4 = "2, 0"; - private static final String COORD_5 = "0, 3"; - private static final String COORD_6 = "3, 3"; - private static final String COORD_7 = "0, 0"; - private static final String COORD_8 = "0, 1"; - private static final String COORD_9 = "0, 2"; - private static final String COORD_10 = "2, 2"; - private static final String COORD_11 = "2, 1"; - private static final String COORD_12 = "3, 1"; - private static final String COORD_13 = "3, 2"; - private static final String COORD_14 = "5, 2"; - private static final String COORD_15 = "5, 1"; - private static final String COORD_16 = "1, 0"; - private static final String COORD_17 = "1, 3"; - private static final String COORD_18 = "4, 3"; - private static final String COORD_19 = "4, 0"; - - - private static final String LINE_ONE = "1000001"; - private static final String LINE_TWO = "2000001"; - private static final String LINE_THREE = "3000001"; - private static final String LINE_FOUR = "4000001"; - private static final String LINE_FIVE = "5000001"; - private static final String LINE_SIX = "6000001"; - private static final String LINE_SEVEN = "7000001"; - private static final String LINE_EIGHT = "8000001"; - private static final String LINE_NINE = "9000001"; - - private static final String RELATION_ONE = "1000011"; - private static final String RELATION_TWO = "2000011"; - private static final String RELATION_THREE = "3000011"; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_1)), - @Node(coordinates = @Loc(value = COORD_2)), - @Node(coordinates = @Loc(value = COORD_3)), - @Node(coordinates = @Loc(value = COORD_4)), - @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), - @Node(coordinates = @Loc(value = COORD_7)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_2), - @Loc(value = COORD_3), - @Loc(value = COORD_4), - @Loc(value = COORD_1)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_5), - @Loc(value = COORD_6), - @Loc(value = COORD_7), - @Loc(value = COORD_1)}, - id = LINE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"})}) - private Atlas crossingBoundariesTwoAreasIntersectEachOther; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_8)), - @Node(coordinates = @Loc(value = COORD_9)), - @Node(coordinates = @Loc(value = COORD_10)), - @Node(coordinates = @Loc(value = COORD_11)), - @Node(coordinates = @Loc(value = COORD_12)), - @Node(coordinates = @Loc(value = COORD_13)), - @Node(coordinates = @Loc(value = COORD_14)), - @Node(coordinates = @Loc(value = COORD_15)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_8), - @Loc(value = COORD_9), - @Loc(value = COORD_10), - @Loc(value = COORD_11), - @Loc(value = COORD_8)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_12), - @Loc(value = COORD_13), - @Loc(value = COORD_14), - @Loc(value = COORD_15), - @Loc(value = COORD_12)}, - id = LINE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"})}) - private Atlas nonCrossingBoundariesTwoSeparate; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_8)), - @Node(coordinates = @Loc(value = COORD_9)), - @Node(coordinates = @Loc(value = COORD_10)), - @Node(coordinates = @Loc(value = COORD_11)), - @Node(coordinates = @Loc(value = COORD_12)), - @Node(coordinates = @Loc(value = COORD_13)), - @Node(coordinates = @Loc(value = COORD_14)), - @Node(coordinates = @Loc(value = COORD_15)), - @Node(coordinates = @Loc(value = COORD_16)), - @Node(coordinates = @Loc(value = COORD_17)), - @Node(coordinates = @Loc(value = COORD_18)), - @Node(coordinates = @Loc(value = COORD_19)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_8), - @Loc(value = COORD_9)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_9), - @Loc(value = COORD_10)}, - id = LINE_TWO), - @Line(coordinates = { - @Loc(value = COORD_10), - @Loc(value = COORD_11)}, - id = LINE_THREE), - @Line(coordinates = { - @Loc(value = COORD_11), - @Loc(value = COORD_8)}, - id = LINE_FOUR), - @Line(coordinates = { - @Loc(value = COORD_12), - @Loc(value = COORD_13), - @Loc(value = COORD_14), - @Loc(value = COORD_15), - @Loc(value = COORD_12)}, - id = LINE_FIVE), - @Line(coordinates = { - @Loc(value = COORD_16), - @Loc(value = COORD_17)}, - id = LINE_SIX), - @Line(coordinates = { - @Loc(value = COORD_17), - @Loc(value = COORD_18)}, - id = LINE_SEVEN), - @Line(coordinates = { - @Loc(value = COORD_18), - @Loc(value = COORD_19)}, - id = LINE_EIGHT), - @Line(coordinates = { - @Loc(value = COORD_19), - @Loc(value = COORD_16)}, - id = LINE_NINE)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line"), - @Relation.Member(id = LINE_TWO, role = "outer", type = "line"), - @Relation.Member(id = LINE_THREE, role = "outer", type = "line"), - @Relation.Member(id = LINE_FOUR, role = "outer", type = "line") - }, - tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_FIVE, role = "outer", type = "line")}, - tags = { - "type=boundary", - "boundary=maritime"}), - @Relation(id = RELATION_THREE, - members = { - @Relation.Member(id = LINE_SIX, role = "outer", type = "line"), - @Relation.Member(id = LINE_SEVEN, role = "outer", type = "line"), - @Relation.Member(id = LINE_EIGHT, role = "outer", type = "line"), - @Relation.Member(id = LINE_NINE, role = "outer", type = "line") - }, - tags = { - "type=boundary", - "boundary=political"})}) - private Atlas crossingBoundariesTwoAreasIntersectOneOther; - - public Atlas crossingBoundariesTwoAreasIntersectEachOther() { - return this.crossingBoundariesTwoAreasIntersectEachOther; - } - - public Atlas nonCrossingBoundariesTwoSeparate() { - return this.nonCrossingBoundariesTwoSeparate; - } - - public Atlas crossingBoundariesTwoAreasIntersectOneOther() { - return this.crossingBoundariesTwoAreasIntersectOneOther; - } - -} From 264c480efe68fd1e5d6aa52ff73c0b5d4a20ad19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 30 Sep 2020 16:49:04 +0200 Subject: [PATCH 04/36] Logic simplified. --- .../BoundaryIntersectionCheck.java | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index b3101b1c0..d3de67b88 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -4,7 +4,6 @@ import org.openstreetmap.atlas.checks.base.BaseCheck; import org.openstreetmap.atlas.checks.flag.CheckFlag; import org.openstreetmap.atlas.geography.Location; -import org.openstreetmap.atlas.geography.PolyLine; import org.openstreetmap.atlas.geography.atlas.Atlas; import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; import org.openstreetmap.atlas.geography.atlas.items.ItemType; @@ -17,10 +16,8 @@ import org.openstreetmap.atlas.tags.annotations.validation.Validators; import org.openstreetmap.atlas.utilities.configuration.Configuration; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.Set; @@ -90,10 +87,9 @@ private CheckFlag prepareCheckFlag(AtlasObject object, Relation relation, List lineItems, LineItem lineItem) { Set knownIntersections = new HashSet<>(); - List polyLines = getPolyLines(lineItem); - Set intersections = polyLines + Set intersections = lineItems .stream() - .map(polyLine -> atlas.lineItemsIntersecting(polyLine.bounds(), getPredicateForLineItemsSelection(lineItems))) + .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), getPredicateForLineItemsSelection(lineItems, currentLineItem))) .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) .collect(Collectors.toSet()); for (LineItem currentLineItem : intersections) { @@ -105,25 +101,6 @@ private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag chec } } - private List getPolyLines(LineItem lineItem) { - List polyLines = new ArrayList<>(); - Iterator iterator = lineItem.asPolyLine().iterator(); - if(iterator.hasNext()) { - Location lastLocation = iterator.next(); - for (int i = 0; i < lineItem.asPolyLine().size() - 1; i++) { - Location location1 = lastLocation; - Location location2 = iterator.next(); - polyLines.add(PolyLine.wkt(String.format("LINESTRING(%s %s, %s %s)", - location1.getLatitude(), - location1.getLongitude(), - location2.getLatitude(), - location2.getLongitude()))); - lastLocation = location2; - } - } - return polyLines; - } - private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineItem lineItem, LineItem currentLineItem, Set intersectingBoundaries) { checkFlag.addPoints(getIntersectingPoints(lineItem, currentLineItem)); checkFlag.addObject(currentLineItem); @@ -137,9 +114,10 @@ private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineIt } } - private Predicate getPredicateForLineItemsSelection(List lineItems) { + private Predicate getPredicateForLineItemsSelection(List lineItems, LineItem currentLineItem) { return lineItemToCheck -> LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && - !lineItems.contains(lineItemToCheck); + !lineItems.contains(lineItemToCheck) && + lineItemToCheck.asPolyLine().intersects(currentLineItem.asPolyLine()); } private String asList(Set intersectingBoundaries) { From 6d9f3680a0a8c41b6c26b03def2f43ea41cb6212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 30 Sep 2020 17:13:43 +0200 Subject: [PATCH 05/36] Both lines intersecting are added. --- .../validation/intersections/BoundaryIntersectionCheck.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index d3de67b88..16456b70c 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -104,6 +104,7 @@ private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag chec private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineItem lineItem, LineItem currentLineItem, Set intersectingBoundaries) { checkFlag.addPoints(getIntersectingPoints(lineItem, currentLineItem)); checkFlag.addObject(currentLineItem); + checkFlag.addObject(lineItem); checkFlag.addObjects(intersectingBoundaries); if(StringUtil.isNullOrEmpty(checkFlag.getInstructions())) { checkFlag.addInstruction(this.getLocalizedInstruction(INDEX, From a04097ecad19b91f9fea2500eea3638d687aca6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 30 Sep 2020 17:22:48 +0200 Subject: [PATCH 06/36] Tests updated. --- .../intersections/BoundaryIntersectionCheckTest.java | 7 ++----- .../intersections/BoundaryIntersectionCheckTestRule.java | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index 078913259..786c18089 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -12,9 +12,6 @@ */ public class BoundaryIntersectionCheckTest { - -// private static final Logger logger = LoggerFactory.getLogger(BoundaryIntersectionsCheckTest.class); - @Rule public BoundaryIntersectionCheckTestRule setup = new BoundaryIntersectionCheckTestRule(); @@ -28,7 +25,7 @@ public void testInvalidTwoCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); - this.verifier.verify(flag -> Assert.assertEquals(5, flag.getFlaggedObjects().size())); + this.verifier.verify(flag -> Assert.assertEquals(6, flag.getFlaggedObjects().size())); } @Test @@ -43,7 +40,7 @@ public void testInvalidTwoCrossingItemsWithEdgesAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOtherWithEdges(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); - this.verifier.verify(flag -> Assert.assertEquals(5, flag.getFlaggedObjects().size())); + this.verifier.verify(flag -> Assert.assertEquals(6, flag.getFlaggedObjects().size())); } @Test diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java index 29fe0857c..759b47a97 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -38,7 +38,7 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { private static final String COORD_21 = "1, 2"; - private static final String LINE_ONE = "123456781000001"; + private static final String LINE_ONE = "1000001"; private static final String LINE_TWO = "2000001"; private static final String LINE_THREE = "3000001"; private static final String LINE_FOUR = "4000001"; From 2e397ee39cc6260d9a19b7fdb9d8e68325d4dffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Thu, 1 Oct 2020 08:19:46 +0200 Subject: [PATCH 07/36] Source relation added to flag. --- .../validation/intersections/BoundaryIntersectionCheck.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 16456b70c..b3a68f0a2 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -107,6 +107,7 @@ private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineIt checkFlag.addObject(lineItem); checkFlag.addObjects(intersectingBoundaries); if(StringUtil.isNullOrEmpty(checkFlag.getInstructions())) { + checkFlag.addObject(relation); checkFlag.addInstruction(this.getLocalizedInstruction(INDEX, relation.getOsmIdentifier(), lineItem.getOsmIdentifier(), From b2ea161d9b3fe7fd5aae23a3e2eb48d2000cd8bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Thu, 1 Oct 2020 08:39:55 +0200 Subject: [PATCH 08/36] Instruction check improved. --- .../intersections/BoundaryIntersectionCheck.java | 15 ++++++++------- .../BoundaryIntersectionCheckTest.java | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index b3a68f0a2..59e2d0af4 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -104,15 +104,16 @@ private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag chec private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineItem lineItem, LineItem currentLineItem, Set intersectingBoundaries) { checkFlag.addPoints(getIntersectingPoints(lineItem, currentLineItem)); checkFlag.addObject(currentLineItem); - checkFlag.addObject(lineItem); checkFlag.addObjects(intersectingBoundaries); - if(StringUtil.isNullOrEmpty(checkFlag.getInstructions())) { + String instruction = this.getLocalizedInstruction(INDEX, + relation.getOsmIdentifier(), + lineItem.getOsmIdentifier(), + currentLineItem.getOsmIdentifier(), + asList(intersectingBoundaries)); + if(StringUtil.isNullOrEmpty(checkFlag.getInstructions()) || !checkFlag.getInstructions().contains(instruction)) { + checkFlag.addObject(lineItem); checkFlag.addObject(relation); - checkFlag.addInstruction(this.getLocalizedInstruction(INDEX, - relation.getOsmIdentifier(), - lineItem.getOsmIdentifier(), - currentLineItem.getOsmIdentifier(), - asList(intersectingBoundaries))); + checkFlag.addInstruction(instruction); } } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index 786c18089..fccedb03a 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -25,7 +25,7 @@ public void testInvalidTwoCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); - this.verifier.verify(flag -> Assert.assertEquals(6, flag.getFlaggedObjects().size())); + this.verifier.verify(flag -> Assert.assertEquals(7, flag.getFlaggedObjects().size())); } @Test @@ -40,7 +40,7 @@ public void testInvalidTwoCrossingItemsWithEdgesAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOtherWithEdges(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); - this.verifier.verify(flag -> Assert.assertEquals(6, flag.getFlaggedObjects().size())); + this.verifier.verify(flag -> Assert.assertEquals(7, flag.getFlaggedObjects().size())); } @Test From 9e58a84721fa99915da46b17db89feaa58d8f6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Thu, 1 Oct 2020 14:51:34 +0200 Subject: [PATCH 09/36] Intersection point added to instruction, regression causing duplicates removed. --- .../BoundaryIntersectionCheck.java | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 59e2d0af4..326384bc0 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -30,7 +30,7 @@ */ public class BoundaryIntersectionCheck extends BaseCheck { - private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0,number,#} with way {1} is crossing invalidly with boundary(ies) {3} with way {2}."; + private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary(ies) {3} with way {2} at coordinates {4}."; private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, INVALID_BOUNDARY_FORMAT); @@ -89,7 +89,7 @@ private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag chec Set knownIntersections = new HashSet<>(); Set intersections = lineItems .stream() - .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), getPredicateForLineItemsSelection(lineItems, currentLineItem))) + .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), getPredicateForLineItemsSelection(lineItems, lineItem))) .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) .collect(Collectors.toSet()); for (LineItem currentLineItem : intersections) { @@ -102,15 +102,17 @@ private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag chec } private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineItem lineItem, LineItem currentLineItem, Set intersectingBoundaries) { - checkFlag.addPoints(getIntersectingPoints(lineItem, currentLineItem)); + Set intersectingPoints = getIntersectingPoints(lineItem, currentLineItem); + checkFlag.addPoints(intersectingPoints); checkFlag.addObject(currentLineItem); checkFlag.addObjects(intersectingBoundaries); String instruction = this.getLocalizedInstruction(INDEX, - relation.getOsmIdentifier(), - lineItem.getOsmIdentifier(), - currentLineItem.getOsmIdentifier(), - asList(intersectingBoundaries)); - if(StringUtil.isNullOrEmpty(checkFlag.getInstructions()) || !checkFlag.getInstructions().contains(instruction)) { + Long.toString(relation.getOsmIdentifier()), + Long.toString(lineItem.getOsmIdentifier()), + Long.toString(currentLineItem.getOsmIdentifier()), + relationsToList(intersectingBoundaries), + locationsToList(intersectingPoints)); + if (StringUtil.isNullOrEmpty(checkFlag.getInstructions()) || !checkFlag.getInstructions().contains(instruction)) { checkFlag.addObject(lineItem); checkFlag.addObject(relation); checkFlag.addInstruction(instruction); @@ -123,13 +125,20 @@ private Predicate getPredicateForLineItemsSelection(List lin lineItemToCheck.asPolyLine().intersects(currentLineItem.asPolyLine()); } - private String asList(Set intersectingBoundaries) { - return intersectingBoundaries + private String relationsToList(Set relations) { + return relations .stream() .map(relation -> Long.toString(relation.getOsmIdentifier())) .collect(Collectors.joining(DELIMITER)); } + private String locationsToList(Set locations) { + return locations + .stream() + .map(location -> String.format("(%s, %s)", location.getLatitude(), location.getLongitude())) + .collect(Collectors.joining(DELIMITER)); + } + private Set getBoundary(LineItem currentLineItem) { return currentLineItem.relations() .stream() From c9c09d45f07dae46f4810f64f9e8cee13241301a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Fri, 2 Oct 2020 16:41:50 +0200 Subject: [PATCH 10/36] Checkstyle cleanup. Logic change to flag only once per relation pair. Intersection changed to crosses not touches. --- .../BoundaryIntersectionCheck.java | 101 +++++++++++------- .../BoundaryIntersectionCheckTest.java | 17 ++- .../BoundaryIntersectionCheckTestRule.java | 48 ++++++++- 3 files changed, 118 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 326384bc0..c225a8a62 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -1,6 +1,17 @@ package org.openstreetmap.atlas.checks.validation.intersections; -import io.netty.util.internal.StringUtil; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.io.ParseException; +import org.locationtech.jts.io.WKTReader; import org.openstreetmap.atlas.checks.base.BaseCheck; import org.openstreetmap.atlas.checks.flag.CheckFlag; import org.openstreetmap.atlas.geography.Location; @@ -16,14 +27,7 @@ import org.openstreetmap.atlas.tags.annotations.validation.Validators; import org.openstreetmap.atlas.utilities.configuration.Configuration; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; +import io.netty.util.internal.StringUtil; /** * @author srachanski @@ -44,7 +48,7 @@ public BoundaryIntersectionCheck(final Configuration configuration) { super(configuration); } - private static boolean isTypeBoundaryWithBoundaryTag(AtlasObject object) { + private static boolean isTypeBoundaryWithBoundaryTag(final AtlasObject object) { return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && Validators.hasValuesFor(object, BoundaryTag.class); } @@ -57,61 +61,66 @@ public boolean validCheckForObject(final AtlasObject object) { @Override protected Optional flag(final AtlasObject object) { - Relation relation = (Relation) object; - RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); + final Relation relation = (Relation) object; + final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); relationMemberLineItems.addAll(relation.membersOfType(ItemType.LINE)); - List lineItems = getLineItems(relationMemberLineItems); - CheckFlag checkFlag = prepareCheckFlag(object, relation, lineItems); + final List lineItems = this.getLineItems(relationMemberLineItems); + final CheckFlag checkFlag = this.prepareCheckFlag(object, relation, lineItems); if (checkFlag.getFlaggedObjects().isEmpty()) { return Optional.empty(); } return Optional.of(checkFlag); } - private List getLineItems(RelationMemberList relationMembersEdges) { + private List getLineItems(final RelationMemberList relationMembersEdges) { return relationMembersEdges .stream() .map(this::castToLineItem) .collect(Collectors.toList()); } - private LineItem castToLineItem(RelationMember relationMember) { + private LineItem castToLineItem(final RelationMember relationMember) { return (LineItem) relationMember.getEntity(); } - private CheckFlag prepareCheckFlag(AtlasObject object, Relation relation, List lineItems) { - CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); - lineItems.forEach(lineItem -> analyzeIntersections(object.getAtlas(), relation, checkFlag, lineItems, lineItem)); + private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, final List lineItems) { + final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); + lineItems.forEach(lineItem -> this.analyzeIntersections(object.getAtlas(), relation, checkFlag, lineItems, lineItem)); return checkFlag; } - private void analyzeIntersections(Atlas atlas, Relation relation, CheckFlag checkFlag, List lineItems, LineItem lineItem) { - Set knownIntersections = new HashSet<>(); - Set intersections = lineItems + private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final List lineItems, final LineItem lineItem) { + final Set knownIntersections = new HashSet<>(); + final Set intersections = lineItems .stream() - .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), getPredicateForLineItemsSelection(lineItems, lineItem))) + .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), this.getPredicateForLineItemsSelection(lineItems, lineItem))) .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) .collect(Collectors.toSet()); - for (LineItem currentLineItem : intersections) { + for (final LineItem currentLineItem : intersections) { if (!knownIntersections.contains(currentLineItem)) { - Set intersectingBoundaries = getBoundary(currentLineItem); - addInformationToFlag(relation, checkFlag, lineItem, currentLineItem, intersectingBoundaries); - knownIntersections.add(currentLineItem); + final Set intersectingBoundaries = this.getBoundary(currentLineItem) + .stream() + .filter(boundary -> boundary.getOsmIdentifier() < relation.getOsmIdentifier()) + .collect(Collectors.toSet()); + if (!intersectingBoundaries.isEmpty()) { + this.addInformationToFlag(relation, checkFlag, lineItem, currentLineItem, intersectingBoundaries); + knownIntersections.add(currentLineItem); + } } } } - private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineItem lineItem, LineItem currentLineItem, Set intersectingBoundaries) { - Set intersectingPoints = getIntersectingPoints(lineItem, currentLineItem); + private void addInformationToFlag(final Relation relation, final CheckFlag checkFlag, final LineItem lineItem, final LineItem currentLineItem, final Set intersectingBoundaries) { + final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItem); checkFlag.addPoints(intersectingPoints); checkFlag.addObject(currentLineItem); checkFlag.addObjects(intersectingBoundaries); - String instruction = this.getLocalizedInstruction(INDEX, + final String instruction = this.getLocalizedInstruction(INDEX, Long.toString(relation.getOsmIdentifier()), Long.toString(lineItem.getOsmIdentifier()), Long.toString(currentLineItem.getOsmIdentifier()), - relationsToList(intersectingBoundaries), - locationsToList(intersectingPoints)); + this.relationsToList(intersectingBoundaries), + this.locationsToList(intersectingPoints)); if (StringUtil.isNullOrEmpty(checkFlag.getInstructions()) || !checkFlag.getInstructions().contains(instruction)) { checkFlag.addObject(lineItem); checkFlag.addObject(relation); @@ -119,34 +128,46 @@ private void addInformationToFlag(Relation relation, CheckFlag checkFlag, LineIt } } - private Predicate getPredicateForLineItemsSelection(List lineItems, LineItem currentLineItem) { - return lineItemToCheck -> LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && - !lineItems.contains(lineItemToCheck) && - lineItemToCheck.asPolyLine().intersects(currentLineItem.asPolyLine()); + private Predicate getPredicateForLineItemsSelection(final List lineItems, final LineItem currentLineItem) { + return lineItemToCheck -> + { + WKTReader wktReader = new WKTReader(); + if (LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && !lineItems.contains(lineItemToCheck)) { + try { + Geometry line1 = wktReader.read(lineItemToCheck.asPolyLine().toWkt()); + Geometry line2 = wktReader.read(currentLineItem.asPolyLine().toWkt()); + return line1.crosses(line2) && + !line1.touches(line2); + } catch (ParseException e) { + return false; + } + } + return false; + }; } - private String relationsToList(Set relations) { + private String relationsToList(final Set relations) { return relations .stream() .map(relation -> Long.toString(relation.getOsmIdentifier())) .collect(Collectors.joining(DELIMITER)); } - private String locationsToList(Set locations) { + private String locationsToList(final Set locations) { return locations .stream() .map(location -> String.format("(%s, %s)", location.getLatitude(), location.getLongitude())) .collect(Collectors.joining(DELIMITER)); } - private Set getBoundary(LineItem currentLineItem) { + private Set getBoundary(final LineItem currentLineItem) { return currentLineItem.relations() .stream() .filter(BoundaryIntersectionCheck::isTypeBoundaryWithBoundaryTag) .collect(Collectors.toSet()); } - private Set getIntersectingPoints(LineItem lineItem, LineItem currentLineItem) { + private Set getIntersectingPoints(final LineItem lineItem, final LineItem currentLineItem) { return currentLineItem.asPolyLine().intersections(lineItem.asPolyLine()); } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index fccedb03a..3f95a344a 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -24,23 +24,23 @@ public class BoundaryIntersectionCheckTest { public void testInvalidTwoCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), new BoundaryIntersectionCheck(this.configuration)); - this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); - this.verifier.verify(flag -> Assert.assertEquals(7, flag.getFlaggedObjects().size())); + this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); + this.verifier.verify(flag -> Assert.assertEquals(6, flag.getFlaggedObjects().size())); } @Test public void testInvalidThreeCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectOneOther(), new BoundaryIntersectionCheck(this.configuration)); - this.verifier.globallyVerify(flags -> Assert.assertEquals(3, flags.size())); + this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); } @Test public void testInvalidTwoCrossingItemsWithEdgesAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOtherWithEdges(), new BoundaryIntersectionCheck(this.configuration)); - this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); - this.verifier.verify(flag -> Assert.assertEquals(7, flag.getFlaggedObjects().size())); + this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); + this.verifier.verify(flag -> Assert.assertEquals(6, flag.getFlaggedObjects().size())); } @Test @@ -50,6 +50,13 @@ public void testValidNonCrossingObjects() { this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } + @Test + public void testTouchingObjects() { + this.verifier.actual(this.setup.boundariesTouchEachOther(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); + } + @Test public void testValidNonCrossingObjectsOneContainOther() { this.verifier.actual(this.setup.nonCrossingOneContainOther(), diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java index 759b47a97..1311dce45 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -51,8 +51,8 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { private static final String EDGE_ONE = "11000001"; private static final String EDGE_TWO = "12000001"; - private static final String RELATION_ONE = "1021000011"; - private static final String RELATION_TWO = "22000011"; + private static final String RELATION_ONE = "2001021000011"; + private static final String RELATION_TWO = "3242222000011"; private static final String RELATION_THREE = "23000011"; @TestAtlas( @@ -91,6 +91,44 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { "type=boundary", "boundary=administrative"})}) + private Atlas crossingBoundariesTwoAreasTouchEachOther; + + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), + @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), + @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) + }, + lines = { + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_15), + @Loc(value = COORD_3), + @Loc(value = COORD_4), + @Loc(value = COORD_1)}, + id = LINE_ONE), + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_5), + @Loc(value = COORD_6), + @Loc(value = COORD_7), + @Loc(value = COORD_1)}, + id = LINE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"})}) private Atlas crossingBoundariesTwoAreasIntersectEachOther; @TestAtlas( @@ -106,7 +144,7 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { edges = { @Edge(coordinates = { @Loc(value = COORD_1), - @Loc(value = COORD_2), + @Loc(value = COORD_15), @Loc(value = COORD_3), @Loc(value = COORD_4), @Loc(value = COORD_1)}, @@ -438,4 +476,8 @@ public Atlas crossingBoundariesTwoAreasIntersectOneOther() { return this.crossingBoundariesTwoAreasIntersectOneOther; } + public Atlas boundariesTouchEachOther() { + return this.crossingBoundariesTwoAreasTouchEachOther; + } + } From 36e1909f5bcd83e79a0e4f3b99e266c626ed9220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Mon, 5 Oct 2020 22:34:47 +0200 Subject: [PATCH 11/36] Checkstyle cleanup. Splitted way are now logged together. Way tags are also analyzed. --- .../BoundaryIntersectionCheck.java | 169 +++++++++++++----- .../BoundaryIntersectionCheckTest.java | 7 + .../BoundaryIntersectionCheckTestRule.java | 41 +++++ 3 files changed, 172 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index c225a8a62..a773fa477 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -1,10 +1,13 @@ package org.openstreetmap.atlas.checks.validation.intersections; +import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.BinaryOperator; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -32,7 +35,8 @@ /** * @author srachanski */ -public class BoundaryIntersectionCheck extends BaseCheck { +public class BoundaryIntersectionCheck extends BaseCheck +{ private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary(ies) {3} with way {2} at coordinates {4}."; private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; @@ -40,105 +44,171 @@ public class BoundaryIntersectionCheck extends BaseCheck { private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem.relations() .stream() - .anyMatch(BoundaryIntersectionCheck::isTypeBoundaryWithBoundaryTag); + .anyMatch(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag); public static final String DELIMITER = ", "; public static final int INDEX = 0; + public static final String TYPE = "type"; + public static final String BOUNDARY = "boundary"; - public BoundaryIntersectionCheck(final Configuration configuration) { + public BoundaryIntersectionCheck(final Configuration configuration) + { super(configuration); } - private static boolean isTypeBoundaryWithBoundaryTag(final AtlasObject object) { + private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) + { return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && Validators.hasValuesFor(object, BoundaryTag.class); } @Override - public boolean validCheckForObject(final AtlasObject object) { + public boolean validCheckForObject(final AtlasObject object) + { return object instanceof Relation && - isTypeBoundaryWithBoundaryTag(object); + isRelationTypeBoundaryWithBoundaryTag(object); } @Override - protected Optional flag(final AtlasObject object) { + protected Optional flag(final AtlasObject object) + { final Relation relation = (Relation) object; final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); relationMemberLineItems.addAll(relation.membersOfType(ItemType.LINE)); final List lineItems = this.getLineItems(relationMemberLineItems); final CheckFlag checkFlag = this.prepareCheckFlag(object, relation, lineItems); - if (checkFlag.getFlaggedObjects().isEmpty()) { + if (checkFlag.getFlaggedObjects().isEmpty()) + { return Optional.empty(); } return Optional.of(checkFlag); } - private List getLineItems(final RelationMemberList relationMembersEdges) { + private List getLineItems(final RelationMemberList relationMembersEdges) + { return relationMembersEdges .stream() .map(this::castToLineItem) .collect(Collectors.toList()); } - private LineItem castToLineItem(final RelationMember relationMember) { + private LineItem castToLineItem(final RelationMember relationMember) + { return (LineItem) relationMember.getEntity(); } - private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, final List lineItems) { + private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, final List lineItems) + { final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); lineItems.forEach(lineItem -> this.analyzeIntersections(object.getAtlas(), relation, checkFlag, lineItems, lineItem)); return checkFlag; } - private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final List lineItems, final LineItem lineItem) { - final Set knownIntersections = new HashSet<>(); - final Set intersections = lineItems + private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final List lineItems, final LineItem lineItem) + { + final Map> intersections = lineItems .stream() .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), this.getPredicateForLineItemsSelection(lineItems, lineItem))) .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) - .collect(Collectors.toSet()); - for (final LineItem currentLineItem : intersections) { - if (!knownIntersections.contains(currentLineItem)) { - final Set intersectingBoundaries = this.getBoundary(currentLineItem) - .stream() - .filter(boundary -> boundary.getOsmIdentifier() < relation.getOsmIdentifier()) - .collect(Collectors.toSet()); - if (!intersectingBoundaries.isEmpty()) { - this.addInformationToFlag(relation, checkFlag, lineItem, currentLineItem, intersectingBoundaries); - knownIntersections.add(currentLineItem); - } + .collect(Collectors.toMap(LineItem::getOsmIdentifier, Arrays::asList, this.mergeLists())); + for (final Map.Entry> lineItemsEntry : intersections.entrySet()) + { + final List intersectingWayParts = lineItemsEntry.getValue(); + final Set intersectingBoundaries = intersectingWayParts + .stream() + .map(this::getBoundary) + .flatMap(Set::stream) + .filter(boundary -> boundary.getOsmIdentifier() < relation.getOsmIdentifier() && boundary.getType().equals(relation.getType())) + .collect(Collectors.toSet()); + final Optional boundaryTag = this.getWayBoundaryTag(intersectingWayParts.get(0)); + if (boundaryTag.isPresent()) + { + final Set intersectingBoundariesByWayTags = this.getIntersectingBoundariesByWayTags(intersections, lineItemsEntry.getKey(), boundaryTag.get()); + intersectingBoundaries.addAll(intersectingBoundariesByWayTags); + } + if (!intersectingBoundaries.isEmpty()) + { + this.addInformationToFlag(relation, checkFlag, lineItem, intersectingWayParts, intersectingBoundaries); } } } - private void addInformationToFlag(final Relation relation, final CheckFlag checkFlag, final LineItem lineItem, final LineItem currentLineItem, final Set intersectingBoundaries) { - final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItem); + private Set getIntersectingBoundariesByWayTags(final Map> intersections, final Long osmIdentifier, final String boundaryTag) + { + return intersections.get(osmIdentifier) + .stream() + .filter(this.lineItemFilter(boundaryTag)) + .map(this::getBoundary) + .flatMap(Set::stream) + .collect(Collectors.toSet()); + } + + private Predicate lineItemFilter(final String boundaryTag) + { + return currentLineItem -> + { + final Optional wayBoundaryTag = this.getWayBoundaryTag(currentLineItem); + return wayBoundaryTag.map(s -> s.equals(boundaryTag)).orElse(false); + }; + } + + private Optional getWayBoundaryTag(final LineItem lineItem) + { + final Optional type = lineItem.getTag(TYPE); + if (type.isPresent() && !type.get().equals(BOUNDARY)) + { + return Optional.empty(); + } + return lineItem.getTag(BOUNDARY); + } + + private BinaryOperator> mergeLists() + { + return (list1, list2) -> + { + final List result = new ArrayList<>(); + result.addAll(list1); + result.addAll(list2); + return result; + }; + } + + private void addInformationToFlag(final Relation relation, final CheckFlag checkFlag, final LineItem lineItem, final List currentLineItems, final Set intersectingBoundaries) + { + final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItems); checkFlag.addPoints(intersectingPoints); - checkFlag.addObject(currentLineItem); + checkFlag.addObjects(currentLineItems); checkFlag.addObjects(intersectingBoundaries); final String instruction = this.getLocalizedInstruction(INDEX, Long.toString(relation.getOsmIdentifier()), Long.toString(lineItem.getOsmIdentifier()), - Long.toString(currentLineItem.getOsmIdentifier()), + Long.toString(currentLineItems.get(0).getOsmIdentifier()), this.relationsToList(intersectingBoundaries), this.locationsToList(intersectingPoints)); - if (StringUtil.isNullOrEmpty(checkFlag.getInstructions()) || !checkFlag.getInstructions().contains(instruction)) { + if (StringUtil.isNullOrEmpty(checkFlag.getInstructions()) || !checkFlag.getInstructions().contains(instruction)) + { checkFlag.addObject(lineItem); checkFlag.addObject(relation); checkFlag.addInstruction(instruction); } } - private Predicate getPredicateForLineItemsSelection(final List lineItems, final LineItem currentLineItem) { + private Predicate getPredicateForLineItemsSelection(final List lineItems, final LineItem currentLineItem) + { return lineItemToCheck -> { - WKTReader wktReader = new WKTReader(); - if (LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && !lineItems.contains(lineItemToCheck)) { - try { - Geometry line1 = wktReader.read(lineItemToCheck.asPolyLine().toWkt()); - Geometry line2 = wktReader.read(currentLineItem.asPolyLine().toWkt()); + final WKTReader wktReader = new WKTReader(); + if (LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && + !lineItems.contains(lineItemToCheck)) + { + try + { + final Geometry line1 = wktReader.read(lineItemToCheck.asPolyLine().toWkt()); + final Geometry line2 = wktReader.read(currentLineItem.asPolyLine().toWkt()); return line1.crosses(line2) && !line1.touches(line2); - } catch (ParseException e) { + } + catch (final ParseException e) + { return false; } } @@ -146,33 +216,42 @@ private Predicate getPredicateForLineItemsSelection(final List relations) { + private String relationsToList(final Set relations) + { return relations .stream() .map(relation -> Long.toString(relation.getOsmIdentifier())) .collect(Collectors.joining(DELIMITER)); } - private String locationsToList(final Set locations) { + private String locationsToList(final Set locations) + { return locations .stream() .map(location -> String.format("(%s, %s)", location.getLatitude(), location.getLongitude())) .collect(Collectors.joining(DELIMITER)); } - private Set getBoundary(final LineItem currentLineItem) { + private Set getBoundary(final LineItem currentLineItem) + { return currentLineItem.relations() .stream() - .filter(BoundaryIntersectionCheck::isTypeBoundaryWithBoundaryTag) + .filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) .collect(Collectors.toSet()); } - private Set getIntersectingPoints(final LineItem lineItem, final LineItem currentLineItem) { - return currentLineItem.asPolyLine().intersections(lineItem.asPolyLine()); + private Set getIntersectingPoints(final LineItem lineItem, final List currentLineItems) + { + return currentLineItems + .stream() + .map(currentLineItem -> currentLineItem.asPolyLine().intersections(lineItem.asPolyLine())) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); } @Override - protected List getFallbackInstructions() { + protected List getFallbackInstructions() + { return FALLBACK_INSTRUCTIONS; } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index 3f95a344a..dcda64e7d 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -85,4 +85,11 @@ public void testValidCrossingObjectsOneMissingBoundarySpecificTag() { this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } + @Test + public void testValidCrossingObjectsWithDifferentTypes() { + this.verifier.actual(this.setup.crossingBoundariesWithDifferentTypes(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); + } + } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java index 1311dce45..49cf731e0 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -93,6 +93,44 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { "boundary=administrative"})}) private Atlas crossingBoundariesTwoAreasTouchEachOther; + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), + @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), + @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) + }, + lines = { + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_2), + @Loc(value = COORD_3), + @Loc(value = COORD_4), + @Loc(value = COORD_1)}, + id = LINE_ONE), + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_5), + @Loc(value = COORD_6), + @Loc(value = COORD_7), + @Loc(value = COORD_1)}, + id = LINE_TWO)}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=political"}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { + "type=boundary", + "boundary=administrative"})}) + private Atlas crossingBoundariesWithDifferentTypes; + @TestAtlas( nodes = { @Node(coordinates = @Loc(value = COORD_1)), @@ -479,5 +517,8 @@ public Atlas crossingBoundariesTwoAreasIntersectOneOther() { public Atlas boundariesTouchEachOther() { return this.crossingBoundariesTwoAreasTouchEachOther; } + public Atlas crossingBoundariesWithDifferentTypes() { + return this.crossingBoundariesTwoAreasTouchEachOther; + } } From 8c9a8a4091e47dafffbb700087f893eeb2566364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Tue, 6 Oct 2020 15:27:23 +0200 Subject: [PATCH 12/36] Further grouping rework. --- .../BoundaryIntersectionCheck.java | 172 ++++++++---------- .../BoundaryIntersectionCheckTestRule.java | 14 +- 2 files changed, 84 insertions(+), 102 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index a773fa477..15aa3167b 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -1,13 +1,13 @@ package org.openstreetmap.atlas.checks.validation.intersections; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.function.BinaryOperator; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -38,18 +38,21 @@ public class BoundaryIntersectionCheck extends BaseCheck { - private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary(ies) {3} with way {2} at coordinates {4}."; + private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary {3} with way {2} at coordinates {4}."; private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, INVALID_BOUNDARY_FORMAT); - - private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem.relations() - .stream() - .anyMatch(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag); public static final String DELIMITER = ", "; public static final int INDEX = 0; public static final String TYPE = "type"; public static final String BOUNDARY = "boundary"; + public static final String EMPTY = ""; + private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem.relations() + .stream() + .anyMatch(lineToCheck -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag(lineToCheck) || + (BOUNDARY.equals(lineToCheck.getTag(TYPE).orElse(EMPTY)) && + lineToCheck.getTag(BOUNDARY).isPresent())); + public BoundaryIntersectionCheck(final Configuration configuration) { super(configuration); @@ -105,90 +108,47 @@ private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation rela private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final List lineItems, final LineItem lineItem) { - final Map> intersections = lineItems - .stream() - .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), this.getPredicateForLineItemsSelection(lineItems, lineItem))) - .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) - .collect(Collectors.toMap(LineItem::getOsmIdentifier, Arrays::asList, this.mergeLists())); - for (final Map.Entry> lineItemsEntry : intersections.entrySet()) - { - final List intersectingWayParts = lineItemsEntry.getValue(); - final Set intersectingBoundaries = intersectingWayParts - .stream() - .map(this::getBoundary) - .flatMap(Set::stream) - .filter(boundary -> boundary.getOsmIdentifier() < relation.getOsmIdentifier() && boundary.getType().equals(relation.getType())) - .collect(Collectors.toSet()); - final Optional boundaryTag = this.getWayBoundaryTag(intersectingWayParts.get(0)); - if (boundaryTag.isPresent()) + final Intersections intersections = new Intersections(); + + lineItems + .stream() + .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), this.getPredicateForLineItemsSelection(lineItems, lineItem))) + .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) + .forEach(currentLineItem -> { - final Set intersectingBoundariesByWayTags = this.getIntersectingBoundariesByWayTags(intersections, lineItemsEntry.getKey(), boundaryTag.get()); - intersectingBoundaries.addAll(intersectingBoundariesByWayTags); - } - if (!intersectingBoundaries.isEmpty()) + final Set boundaries = this.getBoundary(currentLineItem); + boundaries.forEach(boundary -> intersections.add(boundary, currentLineItem)); + }); + for(final Relation currentRelation : intersections.getRelations()) + { + if(currentRelation.getOsmIdentifier() < relation.getOsmIdentifier()) { - this.addInformationToFlag(relation, checkFlag, lineItem, intersectingWayParts, intersectingBoundaries); + this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, intersections.getLineItemsMap(currentRelation)); } } } - private Set getIntersectingBoundariesByWayTags(final Map> intersections, final Long osmIdentifier, final String boundaryTag) - { - return intersections.get(osmIdentifier) - .stream() - .filter(this.lineItemFilter(boundaryTag)) - .map(this::getBoundary) - .flatMap(Set::stream) - .collect(Collectors.toSet()); - } - - private Predicate lineItemFilter(final String boundaryTag) - { - return currentLineItem -> - { - final Optional wayBoundaryTag = this.getWayBoundaryTag(currentLineItem); - return wayBoundaryTag.map(s -> s.equals(boundaryTag)).orElse(false); - }; - } - - private Optional getWayBoundaryTag(final LineItem lineItem) - { - final Optional type = lineItem.getTag(TYPE); - if (type.isPresent() && !type.get().equals(BOUNDARY)) - { - return Optional.empty(); - } - return lineItem.getTag(BOUNDARY); - } - - private BinaryOperator> mergeLists() + private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, final LineItem lineItem, final Relation intersectingBoundary, final Map> lineItems) { - return (list1, list2) -> + for(final Long osmId : lineItems.keySet()) { - final List result = new ArrayList<>(); - result.addAll(list1); - result.addAll(list2); - return result; - }; - } - - private void addInformationToFlag(final Relation relation, final CheckFlag checkFlag, final LineItem lineItem, final List currentLineItems, final Set intersectingBoundaries) - { - final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItems); - checkFlag.addPoints(intersectingPoints); - checkFlag.addObjects(currentLineItems); - checkFlag.addObjects(intersectingBoundaries); - final String instruction = this.getLocalizedInstruction(INDEX, - Long.toString(relation.getOsmIdentifier()), - Long.toString(lineItem.getOsmIdentifier()), - Long.toString(currentLineItems.get(0).getOsmIdentifier()), - this.relationsToList(intersectingBoundaries), - this.locationsToList(intersectingPoints)); - if (StringUtil.isNullOrEmpty(checkFlag.getInstructions()) || !checkFlag.getInstructions().contains(instruction)) - { - checkFlag.addObject(lineItem); - checkFlag.addObject(relation); - checkFlag.addInstruction(instruction); + final Set currentLineItems = lineItems.get(osmId); + final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItems); + checkFlag.addPoints(intersectingPoints); + checkFlag.addObjects(currentLineItems); + checkFlag.addObject(intersectingBoundary); + final String instruction = this.getLocalizedInstruction(INDEX, + Long.toString(relation.getOsmIdentifier()), + Long.toString(lineItem.getOsmIdentifier()), + Long.toString(osmId), + Long.toString(intersectingBoundary.getOsmIdentifier()), + this.locationsToList(intersectingPoints)); + if (StringUtil.isNullOrEmpty(checkFlag.getInstructions()) || !checkFlag.getInstructions().contains(instruction)) + { + checkFlag.addObject(lineItem); + checkFlag.addObject(relation); + checkFlag.addInstruction(instruction); + } } } @@ -215,15 +175,7 @@ private Predicate getPredicateForLineItemsSelection(final List relations) - { - return relations - .stream() - .map(relation -> Long.toString(relation.getOsmIdentifier())) - .collect(Collectors.joining(DELIMITER)); - } - + private String locationsToList(final Set locations) { return locations @@ -240,7 +192,7 @@ private Set getBoundary(final LineItem currentLineItem) .collect(Collectors.toSet()); } - private Set getIntersectingPoints(final LineItem lineItem, final List currentLineItems) + private Set getIntersectingPoints(final LineItem lineItem, final Set currentLineItems) { return currentLineItems .stream() @@ -256,3 +208,37 @@ protected List getFallbackInstructions() } } + +class Intersections +{ + private final Map>> relationIntersections = new HashMap<>(); + + void add(Relation relation, LineItem lineItem) + { + relationIntersections.computeIfAbsent(relation, k -> new HashMap<>()); + long osmIdentifier = lineItem.getOsmIdentifier(); + relationIntersections.get(relation).computeIfAbsent(osmIdentifier, k -> new HashSet<>()); + relationIntersections.get(relation).get(osmIdentifier).add(lineItem); + } + + Set getRelations() + { + return relationIntersections.keySet(); + } + + Set getWayIdsForRelation(Relation relation) + { + return relationIntersections.get(relation).keySet(); + } + + Set getLineItems(Relation relation, Long osmId) + { + return relationIntersections.get(relation).get(osmId); + } + + Map> getLineItemsMap(Relation relation) + { + return relationIntersections.get(relation); + } + +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java index 49cf731e0..a9f4bf224 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -21,7 +21,7 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { private static final String COORD_4 = "2, 0"; private static final String COORD_5 = "0, 3"; private static final String COORD_6 = "3, 3"; - private static final String COORD_7 = "0, 0"; + private static final String COORD_7 = "3, 0"; private static final String COORD_8 = "0, 1"; private static final String COORD_9 = "0, 2"; private static final String COORD_10 = "2, 2"; @@ -51,8 +51,8 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { private static final String EDGE_ONE = "11000001"; private static final String EDGE_TWO = "12000001"; - private static final String RELATION_ONE = "2001021000011"; - private static final String RELATION_TWO = "3242222000011"; + private static final String RELATION_ONE = "21000011"; + private static final String RELATION_TWO = "22000011"; private static final String RELATION_THREE = "23000011"; @TestAtlas( @@ -138,8 +138,7 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { @Node(coordinates = @Loc(value = COORD_3)), @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), - @Node(coordinates = @Loc(value = COORD_7)) + @Node(coordinates = @Loc(value = COORD_6)) }, lines = { @Line(coordinates = { @@ -153,7 +152,6 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { @Loc(value = COORD_1), @Loc(value = COORD_5), @Loc(value = COORD_6), - @Loc(value = COORD_7), @Loc(value = COORD_1)}, id = LINE_TWO)}, relations = { @@ -176,8 +174,7 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { @Node(coordinates = @Loc(value = COORD_3)), @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), - @Node(coordinates = @Loc(value = COORD_7)) + @Node(coordinates = @Loc(value = COORD_6)) }, edges = { @Edge(coordinates = { @@ -191,7 +188,6 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { @Loc(value = COORD_1), @Loc(value = COORD_5), @Loc(value = COORD_6), - @Loc(value = COORD_7), @Loc(value = COORD_1)}, id = EDGE_TWO)}, relations = { From 9fc6ff26c90b7b42e561a1cfa24268534a6d2e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Tue, 6 Oct 2020 16:54:23 +0200 Subject: [PATCH 13/36] Checkstyle fixes. --- .../BoundaryIntersectionCheck.java | 54 +++++-------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 15aa3167b..26db139e5 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -45,14 +45,16 @@ public class BoundaryIntersectionCheck extends BaseCheck public static final int INDEX = 0; public static final String TYPE = "type"; public static final String BOUNDARY = "boundary"; - public static final String EMPTY = ""; + private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem.relations() .stream() .anyMatch(lineToCheck -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag(lineToCheck) || (BOUNDARY.equals(lineToCheck.getTag(TYPE).orElse(EMPTY)) && lineToCheck.getTag(BOUNDARY).isPresent())); + private final Map>> relationIntersections = new HashMap<>(); + public BoundaryIntersectionCheck(final Configuration configuration) { super(configuration); @@ -108,8 +110,6 @@ private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation rela private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final List lineItems, final LineItem lineItem) { - final Intersections intersections = new Intersections(); - lineItems .stream() .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), this.getPredicateForLineItemsSelection(lineItems, lineItem))) @@ -117,20 +117,20 @@ private void analyzeIntersections(final Atlas atlas, final Relation relation, fi .forEach(currentLineItem -> { final Set boundaries = this.getBoundary(currentLineItem); - boundaries.forEach(boundary -> intersections.add(boundary, currentLineItem)); + boundaries.forEach(boundary -> this.addIntersection(boundary, currentLineItem)); }); - for(final Relation currentRelation : intersections.getRelations()) + this.relationIntersections.keySet().forEach(currentRelation -> { if(currentRelation.getOsmIdentifier() < relation.getOsmIdentifier()) { - this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, intersections.getLineItemsMap(currentRelation)); + this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, this.relationIntersections.get(currentRelation)); } - } + }); } private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, final LineItem lineItem, final Relation intersectingBoundary, final Map> lineItems) { - for(final Long osmId : lineItems.keySet()) + lineItems.keySet().forEach(osmId -> { final Set currentLineItems = lineItems.get(osmId); final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItems); @@ -149,7 +149,7 @@ private void addInformationToFlag(final CheckFlag checkFlag, final Relation rela checkFlag.addObject(relation); checkFlag.addInstruction(instruction); } - } + }); } private Predicate getPredicateForLineItemsSelection(final List lineItems, final LineItem currentLineItem) @@ -207,38 +207,12 @@ protected List getFallbackInstructions() return FALLBACK_INSTRUCTIONS; } -} - -class Intersections -{ - private final Map>> relationIntersections = new HashMap<>(); - - void add(Relation relation, LineItem lineItem) - { - relationIntersections.computeIfAbsent(relation, k -> new HashMap<>()); - long osmIdentifier = lineItem.getOsmIdentifier(); - relationIntersections.get(relation).computeIfAbsent(osmIdentifier, k -> new HashSet<>()); - relationIntersections.get(relation).get(osmIdentifier).add(lineItem); - } - - Set getRelations() - { - return relationIntersections.keySet(); - } - - Set getWayIdsForRelation(Relation relation) - { - return relationIntersections.get(relation).keySet(); - } - - Set getLineItems(Relation relation, Long osmId) - { - return relationIntersections.get(relation).get(osmId); - } - - Map> getLineItemsMap(Relation relation) + void addIntersection(final Relation relation, final LineItem lineItem) { - return relationIntersections.get(relation); + this.relationIntersections.computeIfAbsent(relation, k -> new HashMap<>()); + final long osmIdentifier = lineItem.getOsmIdentifier(); + this.relationIntersections.get(relation).computeIfAbsent(osmIdentifier, k -> new HashSet<>()); + this.relationIntersections.get(relation).get(osmIdentifier).add(lineItem); } } From 406df70179dd6964ad6550fe7cd11a154bbe3c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 7 Oct 2020 13:42:56 +0200 Subject: [PATCH 14/36] RelationIntersections moved to separate class. Edges are now logging full way. --- .../checks/utility/RelationIntersections.java | 37 +++++++++++++ .../BoundaryIntersectionCheck.java | 53 +++++++++++-------- .../BoundaryIntersectionCheckTest.java | 12 ++++- 3 files changed, 77 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java diff --git a/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java b/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java new file mode 100644 index 000000000..5f49e0042 --- /dev/null +++ b/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java @@ -0,0 +1,37 @@ +package org.openstreetmap.atlas.checks.utility; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.openstreetmap.atlas.geography.atlas.items.LineItem; +import org.openstreetmap.atlas.geography.atlas.items.Relation; + +/** + * @author srachanski + */ +public class RelationIntersections +{ + + private final Map>> intersections = new HashMap<>(); + + public Set getRelations() + { + return this.intersections.keySet(); + } + + public Map> getLineItemMap(final Relation relation) + { + return this.intersections.get(relation); + } + + public void addIntersection(final Relation relation, final LineItem lineItem) + { + this.intersections.computeIfAbsent(relation, k -> new HashMap<>()); + final long osmIdentifier = lineItem.getOsmIdentifier(); + this.intersections.get(relation).computeIfAbsent(osmIdentifier, k -> new HashSet<>()); + this.intersections.get(relation).get(osmIdentifier).add(lineItem); + } + +} diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 26db139e5..e59cba7da 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -2,8 +2,6 @@ import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -17,20 +15,22 @@ import org.locationtech.jts.io.WKTReader; import org.openstreetmap.atlas.checks.base.BaseCheck; import org.openstreetmap.atlas.checks.flag.CheckFlag; +import org.openstreetmap.atlas.checks.utility.RelationIntersections; import org.openstreetmap.atlas.geography.Location; import org.openstreetmap.atlas.geography.atlas.Atlas; import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; +import org.openstreetmap.atlas.geography.atlas.items.Edge; import org.openstreetmap.atlas.geography.atlas.items.ItemType; import org.openstreetmap.atlas.geography.atlas.items.LineItem; import org.openstreetmap.atlas.geography.atlas.items.Relation; import org.openstreetmap.atlas.geography.atlas.items.RelationMember; import org.openstreetmap.atlas.geography.atlas.items.RelationMemberList; +import org.openstreetmap.atlas.geography.atlas.walker.OsmWayWalker; import org.openstreetmap.atlas.tags.BoundaryTag; import org.openstreetmap.atlas.tags.RelationTypeTag; import org.openstreetmap.atlas.tags.annotations.validation.Validators; import org.openstreetmap.atlas.utilities.configuration.Configuration; -import io.netty.util.internal.StringUtil; /** * @author srachanski @@ -53,7 +53,6 @@ public class BoundaryIntersectionCheck extends BaseCheck (BOUNDARY.equals(lineToCheck.getTag(TYPE).orElse(EMPTY)) && lineToCheck.getTag(BOUNDARY).isPresent())); - private final Map>> relationIntersections = new HashMap<>(); public BoundaryIntersectionCheck(final Configuration configuration) { @@ -110,6 +109,7 @@ private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation rela private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final List lineItems, final LineItem lineItem) { + final RelationIntersections relationIntersections = new RelationIntersections(); lineItems .stream() .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), this.getPredicateForLineItemsSelection(lineItems, lineItem))) @@ -117,25 +117,27 @@ private void analyzeIntersections(final Atlas atlas, final Relation relation, fi .forEach(currentLineItem -> { final Set boundaries = this.getBoundary(currentLineItem); - boundaries.forEach(boundary -> this.addIntersection(boundary, currentLineItem)); + boundaries.forEach(boundary -> relationIntersections.addIntersection(boundary, currentLineItem)); }); - this.relationIntersections.keySet().forEach(currentRelation -> + relationIntersections.getRelations().forEach(currentRelation -> { - if(currentRelation.getOsmIdentifier() < relation.getOsmIdentifier()) + if(currentRelation.getOsmIdentifier() > relation.getOsmIdentifier()) { - this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, this.relationIntersections.get(currentRelation)); + this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, relationIntersections.getLineItemMap(currentRelation)); } }); } private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, final LineItem lineItem, final Relation intersectingBoundary, final Map> lineItems) { + this.addLineItem(checkFlag, lineItem); + checkFlag.addObject(relation); lineItems.keySet().forEach(osmId -> { final Set currentLineItems = lineItems.get(osmId); final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItems); checkFlag.addPoints(intersectingPoints); - checkFlag.addObjects(currentLineItems); + this.addLineItems(checkFlag, currentLineItems); checkFlag.addObject(intersectingBoundary); final String instruction = this.getLocalizedInstruction(INDEX, Long.toString(relation.getOsmIdentifier()), @@ -143,15 +145,28 @@ private void addInformationToFlag(final CheckFlag checkFlag, final Relation rela Long.toString(osmId), Long.toString(intersectingBoundary.getOsmIdentifier()), this.locationsToList(intersectingPoints)); - if (StringUtil.isNullOrEmpty(checkFlag.getInstructions()) || !checkFlag.getInstructions().contains(instruction)) - { - checkFlag.addObject(lineItem); - checkFlag.addObject(relation); - checkFlag.addInstruction(instruction); - } + checkFlag.addInstruction(instruction); }); } + + private void addLineItems(final CheckFlag checkFlag, final Set lineItems) + { + lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); + } + + private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) + { + if(lineItem instanceof Edge) + { + checkFlag.addObjects(new OsmWayWalker((Edge) lineItem).collectEdges()); + } + else + { + checkFlag.addObject(lineItem); + } + } + private Predicate getPredicateForLineItemsSelection(final List lineItems, final LineItem currentLineItem) { return lineItemToCheck -> @@ -207,12 +222,4 @@ protected List getFallbackInstructions() return FALLBACK_INSTRUCTIONS; } - void addIntersection(final Relation relation, final LineItem lineItem) - { - this.relationIntersections.computeIfAbsent(relation, k -> new HashMap<>()); - final long osmIdentifier = lineItem.getOsmIdentifier(); - this.relationIntersections.get(relation).computeIfAbsent(osmIdentifier, k -> new HashSet<>()); - this.relationIntersections.get(relation).get(osmIdentifier).add(lineItem); - } - } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index dcda64e7d..f70f4bbda 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -25,7 +25,11 @@ public void testInvalidTwoCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); - this.verifier.verify(flag -> Assert.assertEquals(6, flag.getFlaggedObjects().size())); + this.verifier.verify(flag -> + { + Assert.assertEquals(6, flag.getFlaggedObjects().size()); + Assert.assertEquals(1, flag.getInstructions().split("\n").length); + }); } @Test @@ -40,7 +44,11 @@ public void testInvalidTwoCrossingItemsWithEdgesAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOtherWithEdges(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); - this.verifier.verify(flag -> Assert.assertEquals(6, flag.getFlaggedObjects().size())); + this.verifier.verify(flag -> + { + Assert.assertEquals(6, flag.getFlaggedObjects().size()); + Assert.assertEquals(1, flag.getInstructions().split("\n").length); + }); } @Test From dd580cf30bf6257e234326fc1c7c904b86658557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 7 Oct 2020 19:32:43 +0200 Subject: [PATCH 15/36] Clean up. --- .../BoundaryIntersectionCheck.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index e59cba7da..2a29a949b 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -171,26 +171,31 @@ private Predicate getPredicateForLineItemsSelection(final List { - final WKTReader wktReader = new WKTReader(); if (LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && !lineItems.contains(lineItemToCheck)) { - try - { - final Geometry line1 = wktReader.read(lineItemToCheck.asPolyLine().toWkt()); - final Geometry line2 = wktReader.read(currentLineItem.asPolyLine().toWkt()); - return line1.crosses(line2) && - !line1.touches(line2); - } - catch (final ParseException e) - { - return false; - } + return this.isCrossingNotTouching(currentLineItem, lineItemToCheck); } return false; }; } - + + private boolean isCrossingNotTouching(final LineItem currentLineItem, final LineItem lineItemToCheck) + { + final WKTReader wktReader = new WKTReader(); + try + { + final Geometry line1 = wktReader.read(lineItemToCheck.asPolyLine().toWkt()); + final Geometry line2 = wktReader.read(currentLineItem.asPolyLine().toWkt()); + return line1.crosses(line2) && + !line1.touches(line2); + } + catch (final ParseException e) + { + return false; + } + } + private String locationsToList(final Set locations) { return locations From 351524ba5c7b7369d44ee1646f9f165bbb7e4c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Mon, 12 Oct 2020 13:54:05 +0200 Subject: [PATCH 16/36] Boundaries with the same type fixed. Same for ways. Tests fixed. Checkstyle fixed. --- .../checks/utility/RelationIntersections.java | 14 +- .../BoundaryIntersectionCheck.java | 193 +++++++++++------- .../BoundaryIntersectionCheckTest.java | 12 ++ .../BoundaryIntersectionCheckTestRule.java | 51 ++++- 4 files changed, 179 insertions(+), 91 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java b/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java index 5f49e0042..778fce77b 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java +++ b/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java @@ -16,9 +16,12 @@ public class RelationIntersections private final Map>> intersections = new HashMap<>(); - public Set getRelations() + public void addIntersection(final Relation relation, final LineItem lineItem) { - return this.intersections.keySet(); + this.intersections.computeIfAbsent(relation, k -> new HashMap<>()); + final long osmIdentifier = lineItem.getOsmIdentifier(); + this.intersections.get(relation).computeIfAbsent(osmIdentifier, k -> new HashSet<>()); + this.intersections.get(relation).get(osmIdentifier).add(lineItem); } public Map> getLineItemMap(final Relation relation) @@ -26,12 +29,9 @@ public Map> getLineItemMap(final Relation relation) return this.intersections.get(relation); } - public void addIntersection(final Relation relation, final LineItem lineItem) + public Set getRelations() { - this.intersections.computeIfAbsent(relation, k -> new HashMap<>()); - final long osmIdentifier = lineItem.getOsmIdentifier(); - this.intersections.get(relation).computeIfAbsent(osmIdentifier, k -> new HashSet<>()); - this.intersections.get(relation).get(osmIdentifier).add(lineItem); + return this.intersections.keySet(); } } diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 2a29a949b..2ac456257 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -47,29 +47,51 @@ public class BoundaryIntersectionCheck extends BaseCheck public static final String BOUNDARY = "boundary"; public static final String EMPTY = ""; + private static final Predicate LINE_ITEM_WITH_BOUNDARY_TAGS = lineItem -> BOUNDARY.equals(lineItem.getTag(TYPE).orElse(EMPTY)) && + lineItem.getTag(BOUNDARY).isPresent(); + private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem.relations() .stream() - .anyMatch(lineToCheck -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag(lineToCheck) || - (BOUNDARY.equals(lineToCheck.getTag(TYPE).orElse(EMPTY)) && - lineToCheck.getTag(BOUNDARY).isPresent())); + .anyMatch(relationToCheck -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag(relationToCheck) || + LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem)); - public BoundaryIntersectionCheck(final Configuration configuration) - { - super(configuration); - } - private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) { return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && Validators.hasValuesFor(object, BoundaryTag.class); } + private static Set getLineItems(final RelationMemberList relationMembers) + { + return relationMembers + .stream() + .map(BoundaryIntersectionCheck::castToLineItem) + .collect(Collectors.toSet()); + } + + private static boolean isRelationWithAnyLineItemWithBoundaryTags(final AtlasObject object) + { + final Relation relation = (Relation) object; + return BoundaryIntersectionCheck.getLineItems(relation.membersOfType(ItemType.EDGE)) + .stream() + .anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS) || + BoundaryIntersectionCheck.getLineItems(relation.membersOfType(ItemType.LINE)) + .stream() + .anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS); + } + + public BoundaryIntersectionCheck(final Configuration configuration) + { + super(configuration); + } + @Override public boolean validCheckForObject(final AtlasObject object) { return object instanceof Relation && - isRelationTypeBoundaryWithBoundaryTag(object); + (isRelationTypeBoundaryWithBoundaryTag(object) || + isRelationWithAnyLineItemWithBoundaryTags(object)); } @Override @@ -78,7 +100,7 @@ protected Optional flag(final AtlasObject object) final Relation relation = (Relation) object; final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); relationMemberLineItems.addAll(relation.membersOfType(ItemType.LINE)); - final List lineItems = this.getLineItems(relationMemberLineItems); + final Set lineItems = BoundaryIntersectionCheck.getLineItems(relationMemberLineItems); final CheckFlag checkFlag = this.prepareCheckFlag(object, relation, lineItems); if (checkFlag.getFlaggedObjects().isEmpty()) { @@ -87,38 +109,63 @@ protected Optional flag(final AtlasObject object) return Optional.of(checkFlag); } - private List getLineItems(final RelationMemberList relationMembersEdges) + private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, final LineItem lineItem, final Relation intersectingBoundary, final Map> lineItems) { - return relationMembersEdges - .stream() - .map(this::castToLineItem) - .collect(Collectors.toList()); + lineItems.keySet().forEach(osmId -> + { + final Set currentLineItems = lineItems.get(osmId); + if(this.isSameBoundaryType(relation, intersectingBoundary) || + this.isSameBoundaryType(lineItem, currentLineItems)) + { + final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItems); + checkFlag.addPoints(intersectingPoints); + this.addLineItems(checkFlag, currentLineItems); + checkFlag.addObject(intersectingBoundary); + final String instruction = this.getLocalizedInstruction(INDEX, + Long.toString(relation.getOsmIdentifier()), + Long.toString(lineItem.getOsmIdentifier()), + Long.toString(osmId), + Long.toString(intersectingBoundary.getOsmIdentifier()), + this.locationsToList(intersectingPoints)); + checkFlag.addInstruction(instruction); + } + }); + if(!checkFlag.getInstructions().isEmpty()) + { + this.addLineItem(checkFlag, lineItem); + checkFlag.addObject(relation); + } } - private LineItem castToLineItem(final RelationMember relationMember) + private void addLineItems(final CheckFlag checkFlag, final Set lineItems) { - return (LineItem) relationMember.getEntity(); + lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); } - private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, final List lineItems) + private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) { - final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); - lineItems.forEach(lineItem -> this.analyzeIntersections(object.getAtlas(), relation, checkFlag, lineItems, lineItem)); - return checkFlag; + if(lineItem instanceof Edge) + { + checkFlag.addObjects(new OsmWayWalker((Edge) lineItem).collectEdges()); + } + else + { + checkFlag.addObject(lineItem); + } } - private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final List lineItems, final LineItem lineItem) + private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final Set lineItems, final LineItem lineItem) { final RelationIntersections relationIntersections = new RelationIntersections(); lineItems - .stream() - .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), this.getPredicateForLineItemsSelection(lineItems, lineItem))) - .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) - .forEach(currentLineItem -> - { - final Set boundaries = this.getBoundary(currentLineItem); - boundaries.forEach(boundary -> relationIntersections.addIntersection(boundary, currentLineItem)); - }); + .stream() + .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), this.getPredicateForLineItemsSelection(lineItems, lineItem))) + .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) + .forEach(currentLineItem -> + { + final Set boundaries = this.getBoundary(currentLineItem); + boundaries.forEach(boundary -> relationIntersections.addIntersection(boundary, currentLineItem)); + }); relationIntersections.getRelations().forEach(currentRelation -> { if(currentRelation.getOsmIdentifier() > relation.getOsmIdentifier()) @@ -128,46 +175,36 @@ private void analyzeIntersections(final Atlas atlas, final Relation relation, fi }); } - private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, final LineItem lineItem, final Relation intersectingBoundary, final Map> lineItems) + private static LineItem castToLineItem(final RelationMember relationMember) { - this.addLineItem(checkFlag, lineItem); - checkFlag.addObject(relation); - lineItems.keySet().forEach(osmId -> - { - final Set currentLineItems = lineItems.get(osmId); - final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItems); - checkFlag.addPoints(intersectingPoints); - this.addLineItems(checkFlag, currentLineItems); - checkFlag.addObject(intersectingBoundary); - final String instruction = this.getLocalizedInstruction(INDEX, - Long.toString(relation.getOsmIdentifier()), - Long.toString(lineItem.getOsmIdentifier()), - Long.toString(osmId), - Long.toString(intersectingBoundary.getOsmIdentifier()), - this.locationsToList(intersectingPoints)); - checkFlag.addInstruction(instruction); - }); + return (LineItem) relationMember.getEntity(); } + private Set getBoundary(final LineItem currentLineItem) + { + return currentLineItem.relations() + .stream() + .filter(relation -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag(relation) || + LINE_ITEM_WITH_BOUNDARY_TAGS.test(currentLineItem)) + .collect(Collectors.toSet()); + } - private void addLineItems(final CheckFlag checkFlag, final Set lineItems) + @Override + protected List getFallbackInstructions() { - lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); + return FALLBACK_INSTRUCTIONS; } - private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) + private Set getIntersectingPoints(final LineItem lineItem, final Set currentLineItems) { - if(lineItem instanceof Edge) - { - checkFlag.addObjects(new OsmWayWalker((Edge) lineItem).collectEdges()); - } - else - { - checkFlag.addObject(lineItem); - } + return currentLineItems + .stream() + .map(currentLineItem -> currentLineItem.asPolyLine().intersections(lineItem.asPolyLine())) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); } - private Predicate getPredicateForLineItemsSelection(final List lineItems, final LineItem currentLineItem) + private Predicate getPredicateForLineItemsSelection(final Set lineItems, final LineItem currentLineItem) { return lineItemToCheck -> { @@ -196,35 +233,33 @@ private boolean isCrossingNotTouching(final LineItem currentLineItem, final Line } } - private String locationsToList(final Set locations) + private boolean isSameBoundaryType(final Relation relation, final Relation intersectingBoundary) { - return locations - .stream() - .map(location -> String.format("(%s, %s)", location.getLatitude(), location.getLongitude())) - .collect(Collectors.joining(DELIMITER)); + return intersectingBoundary.getTag(BOUNDARY).equals(relation.getTag(BOUNDARY)); } - private Set getBoundary(final LineItem currentLineItem) + private boolean isSameBoundaryType(final LineItem lineItem, final Set currentLineItems) { - return currentLineItem.relations() - .stream() - .filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) - .collect(Collectors.toSet()); + final LineItem intersectingLineItem = currentLineItems.iterator().next(); + return !currentLineItems.isEmpty() && + LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem) && + LINE_ITEM_WITH_BOUNDARY_TAGS.test(intersectingLineItem) && + lineItem.getTag(BOUNDARY).equals(intersectingLineItem.getTag(BOUNDARY)); } - private Set getIntersectingPoints(final LineItem lineItem, final Set currentLineItems) + private String locationsToList(final Set locations) { - return currentLineItems + return locations .stream() - .map(currentLineItem -> currentLineItem.asPolyLine().intersections(lineItem.asPolyLine())) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); + .map(location -> String.format("(%s, %s)", location.getLatitude(), location.getLongitude())) + .collect(Collectors.joining(DELIMITER)); } - @Override - protected List getFallbackInstructions() + + private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, final Set lineItems) { - return FALLBACK_INSTRUCTIONS; + final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); + lineItems.forEach(lineItem -> this.analyzeIntersections(object.getAtlas(), relation, checkFlag, lineItems, lineItem)); + return checkFlag; } - } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index f70f4bbda..f4ad7a647 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -32,6 +32,18 @@ public void testInvalidTwoCrossingItemsAtlas() { }); } + @Test + public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() { + this.verifier.actual(this.setup.crossingBoundariesWithOnlyTagsOnWays(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); + this.verifier.verify(flag -> + { + Assert.assertEquals(6, flag.getFlaggedObjects().size()); + Assert.assertEquals(1, flag.getInstructions().split("\n").length); + }); + } + @Test public void testInvalidThreeCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectOneOther(), diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java index a9f4bf224..47b361ceb 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -106,7 +106,7 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { lines = { @Line(coordinates = { @Loc(value = COORD_1), - @Loc(value = COORD_2), + @Loc(value = COORD_15), @Loc(value = COORD_3), @Loc(value = COORD_4), @Loc(value = COORD_1)}, @@ -115,7 +115,6 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { @Loc(value = COORD_1), @Loc(value = COORD_5), @Loc(value = COORD_6), - @Loc(value = COORD_7), @Loc(value = COORD_1)}, id = LINE_TWO)}, relations = { @@ -167,6 +166,44 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { "boundary=administrative"})}) private Atlas crossingBoundariesTwoAreasIntersectEachOther; + @TestAtlas( + nodes = { + @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), + @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), + @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)) + }, + lines = { + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_15), + @Loc(value = COORD_3), + @Loc(value = COORD_4), + @Loc(value = COORD_1)}, + id = LINE_ONE, + tags = { + "type=boundary", + "boundary=administrative"}), + @Line(coordinates = { + @Loc(value = COORD_1), + @Loc(value = COORD_5), + @Loc(value = COORD_6), + @Loc(value = COORD_1)}, + id = LINE_TWO, + tags = { + "type=boundary", + "boundary=administrative"})}, + relations = { + @Relation(id = RELATION_ONE, + members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}), + @Relation(id = RELATION_TWO, + members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line")})}) + private Atlas crossingBoundariesWithOnlyTagsOnWays; + @TestAtlas( nodes = { @Node(coordinates = @Loc(value = COORD_1)), @@ -352,7 +389,7 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { @Relation.Member(id = LINE_FIVE, role = "outer", type = "line")}, tags = { "type=boundary", - "boundary=maritime"}), + "boundary=administrative"}), @Relation(id = RELATION_THREE, members = { @Relation.Member(id = LINE_SIX, role = "outer", type = "line"), @@ -362,7 +399,7 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { }, tags = { "type=boundary", - "boundary=political"})}) + "boundary=administrative"})}) private Atlas crossingBoundariesTwoAreasIntersectOneOther; @TestAtlas( @@ -513,8 +550,12 @@ public Atlas crossingBoundariesTwoAreasIntersectOneOther() { public Atlas boundariesTouchEachOther() { return this.crossingBoundariesTwoAreasTouchEachOther; } + public Atlas crossingBoundariesWithDifferentTypes() { - return this.crossingBoundariesTwoAreasTouchEachOther; + return this.crossingBoundariesWithDifferentTypes; } + public Atlas crossingBoundariesWithOnlyTagsOnWays() { + return this.crossingBoundariesWithOnlyTagsOnWays; + } } From ef708cc879c4611f81f24eaefef295be3bc4b27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Tue, 13 Oct 2020 13:01:38 +0200 Subject: [PATCH 17/36] BoundaryIntersectionCheck added to available_checks.md Checkstyle ordering fixed --- docs/available_checks.md | 1 + .../BoundaryIntersectionCheck.java | 38 +++++------ .../BoundaryIntersectionCheckTest.java | 68 +++++++++++-------- .../BoundaryIntersectionCheckTestRule.java | 56 +++++++++------ 4 files changed, 94 insertions(+), 69 deletions(-) diff --git a/docs/available_checks.md b/docs/available_checks.md index 69d9b09dd..0ca45df35 100644 --- a/docs/available_checks.md +++ b/docs/available_checks.md @@ -63,6 +63,7 @@ This document is a list of tables with a description and link to documentation f ## Relations | Check Name | Check Description | | :--------- | :---------------- | +| BoundaryIntersectionCheck | This check is designed to scan relations marked as boundaries or with ways marked as boundaries and flag them for intersections with other boundaries of the same type. | | InvalidMultiPolygonRelationCheck | This check is designed to scan through MultiPolygon relations and flag them for invalid geometry. | | [InvalidTurnRestrictionCheck](checks/invalidTurnRestrictionCheck.md) | The purpose of this check is to identify invalid turn restrictions in OSM. Invalid turn restrictions occur in a variety of ways from invalid members, Edge geometry issues, not being routable, or wrong topology. | | [MissingRelationType](checks/missingRelationType.md) | The purpose of this check is to identify Relations without relation type. | diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 2ac456257..695b9090a 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -56,10 +56,9 @@ public class BoundaryIntersectionCheck extends BaseCheck LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem)); - private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) + private static LineItem castToLineItem(final RelationMember relationMember) { - return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && - Validators.hasValuesFor(object, BoundaryTag.class); + return (LineItem) relationMember.getEntity(); } private static Set getLineItems(final RelationMemberList relationMembers) @@ -70,6 +69,12 @@ private static Set getLineItems(final RelationMemberList relationMembe .collect(Collectors.toSet()); } + private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) + { + return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && + Validators.hasValuesFor(object, BoundaryTag.class); + } + private static boolean isRelationWithAnyLineItemWithBoundaryTags(final AtlasObject object) { final Relation relation = (Relation) object; @@ -109,6 +114,12 @@ protected Optional flag(final AtlasObject object) return Optional.of(checkFlag); } + @Override + protected List getFallbackInstructions() + { + return FALLBACK_INSTRUCTIONS; + } + private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, final LineItem lineItem, final Relation intersectingBoundary, final Map> lineItems) { lineItems.keySet().forEach(osmId -> @@ -137,11 +148,6 @@ private void addInformationToFlag(final CheckFlag checkFlag, final Relation rela } } - private void addLineItems(final CheckFlag checkFlag, final Set lineItems) - { - lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); - } - private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) { if(lineItem instanceof Edge) @@ -154,6 +160,11 @@ private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) } } + private void addLineItems(final CheckFlag checkFlag, final Set lineItems) + { + lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); + } + private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final Set lineItems, final LineItem lineItem) { final RelationIntersections relationIntersections = new RelationIntersections(); @@ -175,11 +186,6 @@ private void analyzeIntersections(final Atlas atlas, final Relation relation, fi }); } - private static LineItem castToLineItem(final RelationMember relationMember) - { - return (LineItem) relationMember.getEntity(); - } - private Set getBoundary(final LineItem currentLineItem) { return currentLineItem.relations() @@ -189,12 +195,6 @@ private Set getBoundary(final LineItem currentLineItem) .collect(Collectors.toSet()); } - @Override - protected List getFallbackInstructions() - { - return FALLBACK_INSTRUCTIONS; - } - private Set getIntersectingPoints(final LineItem lineItem, final Set currentLineItems) { return currentLineItems diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index f4ad7a647..bfe3df2d2 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -10,7 +10,8 @@ /** * @author srachanski */ -public class BoundaryIntersectionCheckTest { +public class BoundaryIntersectionCheckTest +{ @Rule public BoundaryIntersectionCheckTestRule setup = new BoundaryIntersectionCheckTestRule(); @@ -19,10 +20,19 @@ public class BoundaryIntersectionCheckTest { public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier(); private final Configuration configuration = ConfigurationResolver.emptyConfiguration(); - + @Test - public void testInvalidTwoCrossingItemsAtlas() { - this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), + public void testInvalidThreeCrossingItemsAtlas() + { + this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectOneOther(), + new BoundaryIntersectionCheck(this.configuration)); + this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); + } + + @Test + public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() + { + this.verifier.actual(this.setup.crossingBoundariesWithOnlyTagsOnWays(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); this.verifier.verify(flag -> @@ -33,8 +43,9 @@ public void testInvalidTwoCrossingItemsAtlas() { } @Test - public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() { - this.verifier.actual(this.setup.crossingBoundariesWithOnlyTagsOnWays(), + public void testInvalidTwoCrossingItemsAtlas() + { + this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); this.verifier.verify(flag -> @@ -45,14 +56,8 @@ public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() { } @Test - public void testInvalidThreeCrossingItemsAtlas() { - this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectOneOther(), - new BoundaryIntersectionCheck(this.configuration)); - this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); - } - - @Test - public void testInvalidTwoCrossingItemsWithEdgesAtlas() { + public void testInvalidTwoCrossingItemsWithEdgesAtlas() + { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOtherWithEdges(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); @@ -64,50 +69,57 @@ public void testInvalidTwoCrossingItemsWithEdgesAtlas() { } @Test - public void testValidNonCrossingObjects() { - this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparate(), + public void testTouchingObjects() + { + this.verifier.actual(this.setup.boundariesTouchEachOther(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @Test - public void testTouchingObjects() { - this.verifier.actual(this.setup.boundariesTouchEachOther(), + public void testValidCrossingObjectsOneMissingBoundarySpecificTag() + { + this.verifier.actual(this.setup.crossingOneMissingBoundarySpecificTag(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @Test - public void testValidNonCrossingObjectsOneContainOther() { - this.verifier.actual(this.setup.nonCrossingOneContainOther(), + public void testValidCrossingObjectsOneMissingType() + { + this.verifier.actual(this.setup.crossingOneWithWrongType(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @Test - public void testValidNonCrossingObjectsWithEdges() { - this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparateWithEdges(), + public void testValidCrossingObjectsWithDifferentTypes() + { + this.verifier.actual(this.setup.crossingBoundariesWithDifferentTypes(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @Test - public void testValidCrossingObjectsOneMissingType() { - this.verifier.actual(this.setup.crossingOneWithWrongType(), + public void testValidNonCrossingObjects() + { + this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparate(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @Test - public void testValidCrossingObjectsOneMissingBoundarySpecificTag() { - this.verifier.actual(this.setup.crossingOneMissingBoundarySpecificTag(), + public void testValidNonCrossingObjectsOneContainOther() + { + this.verifier.actual(this.setup.nonCrossingOneContainOther(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @Test - public void testValidCrossingObjectsWithDifferentTypes() { - this.verifier.actual(this.setup.crossingBoundariesWithDifferentTypes(), + public void testValidNonCrossingObjectsWithEdges() + { + this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparateWithEdges(), new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java index 47b361ceb..8e6325a4e 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -14,7 +14,8 @@ * * @author srachanski */ -public class BoundaryIntersectionCheckTestRule extends CoreTestRule { +public class BoundaryIntersectionCheckTestRule extends CoreTestRule +{ private static final String COORD_1 = "0, 0"; private static final String COORD_2 = "0, 2"; private static final String COORD_3 = "2, 2"; @@ -515,47 +516,58 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule { "type=nonBoundary"})}) private Atlas crossingOneMissingBoundarySpecificTag; - public Atlas crossingBoundariesTwoAreasIntersectEachOther() { + public Atlas boundariesTouchEachOther() + { + return this.crossingBoundariesTwoAreasTouchEachOther; + } + + public Atlas crossingBoundariesTwoAreasIntersectEachOther() + { return this.crossingBoundariesTwoAreasIntersectEachOther; } - public Atlas crossingBoundariesTwoAreasIntersectEachOtherWithEdges() { + public Atlas crossingBoundariesTwoAreasIntersectEachOtherWithEdges() + { return this.crossingBoundariesTwoAreasIntersectEachOtherWithEdges; } - public Atlas nonCrossingBoundariesTwoSeparate() { - return this.nonCrossingBoundariesTwoSeparate; + public Atlas crossingBoundariesTwoAreasIntersectOneOther() + { + return this.crossingBoundariesTwoAreasIntersectOneOther; } - public Atlas nonCrossingOneContainOther() { - return this.nonCrossingOneContainOther; + public Atlas crossingBoundariesWithDifferentTypes() + { + return this.crossingBoundariesWithDifferentTypes; } - public Atlas crossingOneWithWrongType() { - return this.crossingOneWithWrongType; + public Atlas crossingBoundariesWithOnlyTagsOnWays() + { + return this.crossingBoundariesWithOnlyTagsOnWays; } - public Atlas crossingOneMissingBoundarySpecificTag() { + public Atlas crossingOneMissingBoundarySpecificTag() + { return this.crossingOneMissingBoundarySpecificTag; } - public Atlas nonCrossingBoundariesTwoSeparateWithEdges() { - return this.nonCrossingBoundariesTwoSeparateWithEdges; - } - - public Atlas crossingBoundariesTwoAreasIntersectOneOther() { - return this.crossingBoundariesTwoAreasIntersectOneOther; + public Atlas crossingOneWithWrongType() + { + return this.crossingOneWithWrongType; } - public Atlas boundariesTouchEachOther() { - return this.crossingBoundariesTwoAreasTouchEachOther; + public Atlas nonCrossingBoundariesTwoSeparate() + { + return this.nonCrossingBoundariesTwoSeparate; } - public Atlas crossingBoundariesWithDifferentTypes() { - return this.crossingBoundariesWithDifferentTypes; + public Atlas nonCrossingBoundariesTwoSeparateWithEdges() + { + return this.nonCrossingBoundariesTwoSeparateWithEdges; } - public Atlas crossingBoundariesWithOnlyTagsOnWays() { - return this.crossingBoundariesWithOnlyTagsOnWays; + public Atlas nonCrossingOneContainOther() + { + return this.nonCrossingOneContainOther; } } From 387d5616305af825c1014d612f2c927490cca4b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Tue, 13 Oct 2020 13:14:04 +0200 Subject: [PATCH 18/36] SpotlessJava applied. --- .../checks/utility/RelationIntersections.java | 10 +- .../BoundaryIntersectionCheck.java | 180 ++--- .../BoundaryIntersectionCheckTest.java | 30 +- .../BoundaryIntersectionCheckTestRule.java | 699 ++++++------------ 4 files changed, 348 insertions(+), 571 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java b/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java index 778fce77b..f87f36d3f 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java +++ b/src/main/java/org/openstreetmap/atlas/checks/utility/RelationIntersections.java @@ -13,9 +13,9 @@ */ public class RelationIntersections { - + private final Map>> intersections = new HashMap<>(); - + public void addIntersection(final Relation relation, final LineItem lineItem) { this.intersections.computeIfAbsent(relation, k -> new HashMap<>()); @@ -23,15 +23,15 @@ public void addIntersection(final Relation relation, final LineItem lineItem) this.intersections.get(relation).computeIfAbsent(osmIdentifier, k -> new HashSet<>()); this.intersections.get(relation).get(osmIdentifier).add(lineItem); } - + public Map> getLineItemMap(final Relation relation) { return this.intersections.get(relation); } - + public Set getRelations() { return this.intersections.keySet(); } - + } diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 695b9090a..bcdacb585 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -31,81 +31,78 @@ import org.openstreetmap.atlas.tags.annotations.validation.Validators; import org.openstreetmap.atlas.utilities.configuration.Configuration; - /** * @author srachanski */ public class BoundaryIntersectionCheck extends BaseCheck { - + private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary {3} with way {2} at coordinates {4}."; - private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; - private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, INVALID_BOUNDARY_FORMAT); + private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + + " Two boundaries should not intersect each other."; + private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, + INVALID_BOUNDARY_FORMAT); public static final String DELIMITER = ", "; public static final int INDEX = 0; public static final String TYPE = "type"; public static final String BOUNDARY = "boundary"; public static final String EMPTY = ""; - - private static final Predicate LINE_ITEM_WITH_BOUNDARY_TAGS = lineItem -> BOUNDARY.equals(lineItem.getTag(TYPE).orElse(EMPTY)) && - lineItem.getTag(BOUNDARY).isPresent(); - - private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem.relations() - .stream() - .anyMatch(relationToCheck -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag(relationToCheck) || - LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem)); - - + + private static final Predicate LINE_ITEM_WITH_BOUNDARY_TAGS = lineItem -> BOUNDARY + .equals(lineItem.getTag(TYPE).orElse(EMPTY)) && lineItem.getTag(BOUNDARY).isPresent(); + + private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem + .relations().stream() + .anyMatch(relationToCheck -> BoundaryIntersectionCheck + .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) + || LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem)); + private static LineItem castToLineItem(final RelationMember relationMember) { return (LineItem) relationMember.getEntity(); } - + private static Set getLineItems(final RelationMemberList relationMembers) { - return relationMembers - .stream() - .map(BoundaryIntersectionCheck::castToLineItem) + return relationMembers.stream().map(BoundaryIntersectionCheck::castToLineItem) .collect(Collectors.toSet()); } - + private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) { - return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && - Validators.hasValuesFor(object, BoundaryTag.class); + return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) + && Validators.hasValuesFor(object, BoundaryTag.class); } - + private static boolean isRelationWithAnyLineItemWithBoundaryTags(final AtlasObject object) { final Relation relation = (Relation) object; return BoundaryIntersectionCheck.getLineItems(relation.membersOfType(ItemType.EDGE)) - .stream() - .anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS) || - BoundaryIntersectionCheck.getLineItems(relation.membersOfType(ItemType.LINE)) - .stream() - .anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS); + .stream().anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS) + || BoundaryIntersectionCheck.getLineItems(relation.membersOfType(ItemType.LINE)) + .stream().anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS); } - + public BoundaryIntersectionCheck(final Configuration configuration) { super(configuration); } - + @Override public boolean validCheckForObject(final AtlasObject object) { - return object instanceof Relation && - (isRelationTypeBoundaryWithBoundaryTag(object) || - isRelationWithAnyLineItemWithBoundaryTags(object)); + return object instanceof Relation && (isRelationTypeBoundaryWithBoundaryTag(object) + || isRelationWithAnyLineItemWithBoundaryTags(object)); } - + @Override protected Optional flag(final AtlasObject object) { final Relation relation = (Relation) object; final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); relationMemberLineItems.addAll(relation.membersOfType(ItemType.LINE)); - final Set lineItems = BoundaryIntersectionCheck.getLineItems(relationMemberLineItems); + final Set lineItems = BoundaryIntersectionCheck + .getLineItems(relationMemberLineItems); final CheckFlag checkFlag = this.prepareCheckFlag(object, relation, lineItems); if (checkFlag.getFlaggedObjects().isEmpty()) { @@ -113,44 +110,46 @@ protected Optional flag(final AtlasObject object) } return Optional.of(checkFlag); } - + @Override protected List getFallbackInstructions() { return FALLBACK_INSTRUCTIONS; } - - private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, final LineItem lineItem, final Relation intersectingBoundary, final Map> lineItems) + + private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, + final LineItem lineItem, final Relation intersectingBoundary, + final Map> lineItems) { lineItems.keySet().forEach(osmId -> { final Set currentLineItems = lineItems.get(osmId); - if(this.isSameBoundaryType(relation, intersectingBoundary) || - this.isSameBoundaryType(lineItem, currentLineItems)) + if (this.isSameBoundaryType(relation, intersectingBoundary) + || this.isSameBoundaryType(lineItem, currentLineItems)) { - final Set intersectingPoints = this.getIntersectingPoints(lineItem, currentLineItems); + final Set intersectingPoints = this.getIntersectingPoints(lineItem, + currentLineItems); checkFlag.addPoints(intersectingPoints); this.addLineItems(checkFlag, currentLineItems); checkFlag.addObject(intersectingBoundary); final String instruction = this.getLocalizedInstruction(INDEX, Long.toString(relation.getOsmIdentifier()), - Long.toString(lineItem.getOsmIdentifier()), - Long.toString(osmId), + Long.toString(lineItem.getOsmIdentifier()), Long.toString(osmId), Long.toString(intersectingBoundary.getOsmIdentifier()), this.locationsToList(intersectingPoints)); checkFlag.addInstruction(instruction); } }); - if(!checkFlag.getInstructions().isEmpty()) + if (!checkFlag.getInstructions().isEmpty()) { this.addLineItem(checkFlag, lineItem); checkFlag.addObject(relation); } } - + private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) { - if(lineItem instanceof Edge) + if (lineItem instanceof Edge) { checkFlag.addObjects(new OsmWayWalker((Edge) lineItem).collectEdges()); } @@ -159,107 +158,108 @@ private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) checkFlag.addObject(lineItem); } } - + private void addLineItems(final CheckFlag checkFlag, final Set lineItems) { lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); } - - private void analyzeIntersections(final Atlas atlas, final Relation relation, final CheckFlag checkFlag, final Set lineItems, final LineItem lineItem) + + private void analyzeIntersections(final Atlas atlas, final Relation relation, + final CheckFlag checkFlag, final Set lineItems, final LineItem lineItem) { final RelationIntersections relationIntersections = new RelationIntersections(); - lineItems - .stream() - .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), this.getPredicateForLineItemsSelection(lineItems, lineItem))) + lineItems.stream() + .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), + this.getPredicateForLineItemsSelection(lineItems, lineItem))) .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) .forEach(currentLineItem -> { final Set boundaries = this.getBoundary(currentLineItem); - boundaries.forEach(boundary -> relationIntersections.addIntersection(boundary, currentLineItem)); + boundaries.forEach(boundary -> relationIntersections.addIntersection(boundary, + currentLineItem)); }); relationIntersections.getRelations().forEach(currentRelation -> { - if(currentRelation.getOsmIdentifier() > relation.getOsmIdentifier()) + if (currentRelation.getOsmIdentifier() > relation.getOsmIdentifier()) { - this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, relationIntersections.getLineItemMap(currentRelation)); + this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, + relationIntersections.getLineItemMap(currentRelation)); } }); } - + private Set getBoundary(final LineItem currentLineItem) { - return currentLineItem.relations() - .stream() - .filter(relation -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag(relation) || - LINE_ITEM_WITH_BOUNDARY_TAGS.test(currentLineItem)) + return currentLineItem.relations().stream() + .filter(relation -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag( + relation) || LINE_ITEM_WITH_BOUNDARY_TAGS.test(currentLineItem)) .collect(Collectors.toSet()); } - - private Set getIntersectingPoints(final LineItem lineItem, final Set currentLineItems) + + private Set getIntersectingPoints(final LineItem lineItem, + final Set currentLineItems) { - return currentLineItems - .stream() - .map(currentLineItem -> currentLineItem.asPolyLine().intersections(lineItem.asPolyLine())) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); + return currentLineItems.stream() + .map(currentLineItem -> currentLineItem.asPolyLine() + .intersections(lineItem.asPolyLine())) + .flatMap(Collection::stream).collect(Collectors.toSet()); } - - private Predicate getPredicateForLineItemsSelection(final Set lineItems, final LineItem currentLineItem) + + private Predicate getPredicateForLineItemsSelection(final Set lineItems, + final LineItem currentLineItem) { return lineItemToCheck -> { - if (LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && - !lineItems.contains(lineItemToCheck)) + if (LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && !lineItems.contains(lineItemToCheck)) { return this.isCrossingNotTouching(currentLineItem, lineItemToCheck); } return false; }; } - - private boolean isCrossingNotTouching(final LineItem currentLineItem, final LineItem lineItemToCheck) + + private boolean isCrossingNotTouching(final LineItem currentLineItem, + final LineItem lineItemToCheck) { final WKTReader wktReader = new WKTReader(); try { final Geometry line1 = wktReader.read(lineItemToCheck.asPolyLine().toWkt()); final Geometry line2 = wktReader.read(currentLineItem.asPolyLine().toWkt()); - return line1.crosses(line2) && - !line1.touches(line2); + return line1.crosses(line2) && !line1.touches(line2); } catch (final ParseException e) { return false; } } - + private boolean isSameBoundaryType(final Relation relation, final Relation intersectingBoundary) { return intersectingBoundary.getTag(BOUNDARY).equals(relation.getTag(BOUNDARY)); } - - private boolean isSameBoundaryType(final LineItem lineItem, final Set currentLineItems) + + private boolean isSameBoundaryType(final LineItem lineItem, + final Set currentLineItems) { final LineItem intersectingLineItem = currentLineItems.iterator().next(); - return !currentLineItems.isEmpty() && - LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem) && - LINE_ITEM_WITH_BOUNDARY_TAGS.test(intersectingLineItem) && - lineItem.getTag(BOUNDARY).equals(intersectingLineItem.getTag(BOUNDARY)); + return !currentLineItems.isEmpty() && LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem) + && LINE_ITEM_WITH_BOUNDARY_TAGS.test(intersectingLineItem) + && lineItem.getTag(BOUNDARY).equals(intersectingLineItem.getTag(BOUNDARY)); } - + private String locationsToList(final Set locations) { - return locations - .stream() - .map(location -> String.format("(%s, %s)", location.getLatitude(), location.getLongitude())) - .collect(Collectors.joining(DELIMITER)); + return locations.stream().map(location -> String.format("(%s, %s)", location.getLatitude(), + location.getLongitude())).collect(Collectors.joining(DELIMITER)); } - - - private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, final Set lineItems) + + private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, + final Set lineItems) { final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); - lineItems.forEach(lineItem -> this.analyzeIntersections(object.getAtlas(), relation, checkFlag, lineItems, lineItem)); + lineItems.forEach(lineItem -> this.analyzeIntersections(object.getAtlas(), relation, + checkFlag, lineItems, lineItem)); return checkFlag; } } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index bfe3df2d2..889f847e9 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -12,15 +12,15 @@ */ public class BoundaryIntersectionCheckTest { - + @Rule public BoundaryIntersectionCheckTestRule setup = new BoundaryIntersectionCheckTestRule(); - + @Rule public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier(); - + private final Configuration configuration = ConfigurationResolver.emptyConfiguration(); - + @Test public void testInvalidThreeCrossingItemsAtlas() { @@ -28,7 +28,7 @@ public void testInvalidThreeCrossingItemsAtlas() new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); } - + @Test public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() { @@ -41,7 +41,7 @@ public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() Assert.assertEquals(1, flag.getInstructions().split("\n").length); }); } - + @Test public void testInvalidTwoCrossingItemsAtlas() { @@ -54,7 +54,7 @@ public void testInvalidTwoCrossingItemsAtlas() Assert.assertEquals(1, flag.getInstructions().split("\n").length); }); } - + @Test public void testInvalidTwoCrossingItemsWithEdgesAtlas() { @@ -67,7 +67,7 @@ public void testInvalidTwoCrossingItemsWithEdgesAtlas() Assert.assertEquals(1, flag.getInstructions().split("\n").length); }); } - + @Test public void testTouchingObjects() { @@ -75,7 +75,7 @@ public void testTouchingObjects() new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } - + @Test public void testValidCrossingObjectsOneMissingBoundarySpecificTag() { @@ -83,7 +83,7 @@ public void testValidCrossingObjectsOneMissingBoundarySpecificTag() new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } - + @Test public void testValidCrossingObjectsOneMissingType() { @@ -91,7 +91,7 @@ public void testValidCrossingObjectsOneMissingType() new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } - + @Test public void testValidCrossingObjectsWithDifferentTypes() { @@ -99,7 +99,7 @@ public void testValidCrossingObjectsWithDifferentTypes() new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } - + @Test public void testValidNonCrossingObjects() { @@ -107,7 +107,7 @@ public void testValidNonCrossingObjects() new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } - + @Test public void testValidNonCrossingObjectsOneContainOther() { @@ -115,7 +115,7 @@ public void testValidNonCrossingObjectsOneContainOther() new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } - + @Test public void testValidNonCrossingObjectsWithEdges() { @@ -123,5 +123,5 @@ public void testValidNonCrossingObjectsWithEdges() new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } - + } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java index 8e6325a4e..9875179f3 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -37,8 +37,7 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule private static final String COORD_19 = "4, 0"; private static final String COORD_20 = "1, 1"; private static final String COORD_21 = "1, 2"; - - + private static final String LINE_ONE = "1000001"; private static final String LINE_TWO = "2000001"; private static final String LINE_THREE = "3000001"; @@ -48,524 +47,302 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule private static final String LINE_SEVEN = "7000001"; private static final String LINE_EIGHT = "8000001"; private static final String LINE_NINE = "9000001"; - + private static final String EDGE_ONE = "11000001"; private static final String EDGE_TWO = "12000001"; - + private static final String RELATION_ONE = "21000011"; private static final String RELATION_TWO = "22000011"; private static final String RELATION_THREE = "23000011"; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_1)), - @Node(coordinates = @Loc(value = COORD_2)), - @Node(coordinates = @Loc(value = COORD_3)), - @Node(coordinates = @Loc(value = COORD_4)), - @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), - @Node(coordinates = @Loc(value = COORD_7)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_2), - @Loc(value = COORD_3), - @Loc(value = COORD_4), - @Loc(value = COORD_1)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_5), - @Loc(value = COORD_6), - @Loc(value = COORD_7), - @Loc(value = COORD_1)}, - id = LINE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"})}) + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_2), + @Loc(value = COORD_3), @Loc(value = COORD_4), + @Loc(value = COORD_1) }, id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), + @Loc(value = COORD_6), @Loc(value = COORD_7), + @Loc(value = COORD_1) }, id = LINE_TWO) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }) }) private Atlas crossingBoundariesTwoAreasTouchEachOther; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_1)), - @Node(coordinates = @Loc(value = COORD_2)), - @Node(coordinates = @Loc(value = COORD_3)), - @Node(coordinates = @Loc(value = COORD_4)), - @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), - @Node(coordinates = @Loc(value = COORD_7)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_15), - @Loc(value = COORD_3), - @Loc(value = COORD_4), - @Loc(value = COORD_1)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_5), + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_15), + @Loc(value = COORD_3), @Loc(value = COORD_4), + @Loc(value = COORD_1) }, id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), @Loc(value = COORD_6), - @Loc(value = COORD_1)}, - id = LINE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=political"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"})}) + @Loc(value = COORD_1) }, id = LINE_TWO) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=political" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }) }) private Atlas crossingBoundariesWithDifferentTypes; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_1)), - @Node(coordinates = @Loc(value = COORD_2)), - @Node(coordinates = @Loc(value = COORD_3)), - @Node(coordinates = @Loc(value = COORD_4)), - @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_15), - @Loc(value = COORD_3), - @Loc(value = COORD_4), - @Loc(value = COORD_1)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_5), + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_15), + @Loc(value = COORD_3), @Loc(value = COORD_4), + @Loc(value = COORD_1) }, id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), @Loc(value = COORD_6), - @Loc(value = COORD_1)}, - id = LINE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"})}) + @Loc(value = COORD_1) }, id = LINE_TWO) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }) }) private Atlas crossingBoundariesTwoAreasIntersectEachOther; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_1)), - @Node(coordinates = @Loc(value = COORD_2)), - @Node(coordinates = @Loc(value = COORD_3)), - @Node(coordinates = @Loc(value = COORD_4)), - @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_15), - @Loc(value = COORD_3), - @Loc(value = COORD_4), - @Loc(value = COORD_1)}, - id = LINE_ONE, - tags = { - "type=boundary", - "boundary=administrative"}), - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_5), - @Loc(value = COORD_6), - @Loc(value = COORD_1)}, - id = LINE_TWO, - tags = { - "type=boundary", - "boundary=administrative"})}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")})}) + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_15), + @Loc(value = COORD_3), @Loc(value = COORD_4), + @Loc(value = COORD_1) }, id = LINE_ONE, tags = { "type=boundary", + "boundary=administrative" }), + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), + @Loc(value = COORD_6), @Loc(value = COORD_1) }, id = LINE_TWO, tags = { + "type=boundary", "boundary=administrative" }) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line") }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line") }) }) private Atlas crossingBoundariesWithOnlyTagsOnWays; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_1)), - @Node(coordinates = @Loc(value = COORD_2)), - @Node(coordinates = @Loc(value = COORD_3)), - @Node(coordinates = @Loc(value = COORD_4)), - @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)) - }, - edges = { - @Edge(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_15), - @Loc(value = COORD_3), - @Loc(value = COORD_4), - @Loc(value = COORD_1)}, - id = EDGE_ONE), - @Edge(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_5), + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)) }, edges = { + @Edge(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_15), + @Loc(value = COORD_3), @Loc(value = COORD_4), + @Loc(value = COORD_1) }, id = EDGE_ONE), + @Edge(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), @Loc(value = COORD_6), - @Loc(value = COORD_1)}, - id = EDGE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = EDGE_ONE, role = "outer", type = "edge")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = EDGE_TWO, role = "outer", type = "edge")}, tags = { - "type=boundary", - "boundary=administrative"})}) + @Loc(value = COORD_1) }, id = EDGE_TWO) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = EDGE_ONE, role = "outer", type = "edge") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = EDGE_TWO, role = "outer", type = "edge") }, tags = { + "type=boundary", "boundary=administrative" }) }) private Atlas crossingBoundariesTwoAreasIntersectEachOtherWithEdges; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_8)), - @Node(coordinates = @Loc(value = COORD_9)), - @Node(coordinates = @Loc(value = COORD_10)), - @Node(coordinates = @Loc(value = COORD_11)), - @Node(coordinates = @Loc(value = COORD_12)), - @Node(coordinates = @Loc(value = COORD_13)), - @Node(coordinates = @Loc(value = COORD_14)), - @Node(coordinates = @Loc(value = COORD_15)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_8), - @Loc(value = COORD_9), - @Loc(value = COORD_10), - @Loc(value = COORD_11), - @Loc(value = COORD_8)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_12), - @Loc(value = COORD_13), - @Loc(value = COORD_14), - @Loc(value = COORD_15), - @Loc(value = COORD_12)}, - id = LINE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"})}) + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_8)), + @Node(coordinates = @Loc(value = COORD_9)), @Node(coordinates = @Loc(value = COORD_10)), + @Node(coordinates = @Loc(value = COORD_11)), + @Node(coordinates = @Loc(value = COORD_12)), + @Node(coordinates = @Loc(value = COORD_13)), + @Node(coordinates = @Loc(value = COORD_14)), + @Node(coordinates = @Loc(value = COORD_15)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_8), @Loc(value = COORD_9), + @Loc(value = COORD_10), @Loc(value = COORD_11), + @Loc(value = COORD_8) }, id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_12), @Loc(value = COORD_13), + @Loc(value = COORD_14), @Loc(value = COORD_15), + @Loc(value = COORD_12) }, id = LINE_TWO) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }) }) private Atlas nonCrossingBoundariesTwoSeparate; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_8)), - @Node(coordinates = @Loc(value = COORD_9)), - @Node(coordinates = @Loc(value = COORD_10)), - @Node(coordinates = @Loc(value = COORD_11)), - @Node(coordinates = @Loc(value = COORD_12)), - @Node(coordinates = @Loc(value = COORD_13)), - @Node(coordinates = @Loc(value = COORD_14)), - @Node(coordinates = @Loc(value = COORD_15)) - }, - edges = { - @Edge(coordinates = { - @Loc(value = COORD_8), - @Loc(value = COORD_9), - @Loc(value = COORD_10), - @Loc(value = COORD_11), - @Loc(value = COORD_8)}, - id = EDGE_ONE), - @Edge(coordinates = { - @Loc(value = COORD_12), - @Loc(value = COORD_13), - @Loc(value = COORD_14), - @Loc(value = COORD_15), - @Loc(value = COORD_12)}, - id = EDGE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = EDGE_ONE, role = "outer", type = "edge")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = EDGE_TWO, role = "outer", type = "edge")}, tags = { - "type=boundary", - "boundary=administrative"})}) + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_8)), + @Node(coordinates = @Loc(value = COORD_9)), @Node(coordinates = @Loc(value = COORD_10)), + @Node(coordinates = @Loc(value = COORD_11)), + @Node(coordinates = @Loc(value = COORD_12)), + @Node(coordinates = @Loc(value = COORD_13)), + @Node(coordinates = @Loc(value = COORD_14)), + @Node(coordinates = @Loc(value = COORD_15)) }, edges = { + @Edge(coordinates = { @Loc(value = COORD_8), @Loc(value = COORD_9), + @Loc(value = COORD_10), @Loc(value = COORD_11), + @Loc(value = COORD_8) }, id = EDGE_ONE), + @Edge(coordinates = { @Loc(value = COORD_12), @Loc(value = COORD_13), + @Loc(value = COORD_14), @Loc(value = COORD_15), + @Loc(value = COORD_12) }, id = EDGE_TWO) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = EDGE_ONE, role = "outer", type = "edge") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = EDGE_TWO, role = "outer", type = "edge") }, tags = { + "type=boundary", "boundary=administrative" }) }) private Atlas nonCrossingBoundariesTwoSeparateWithEdges; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_8)), - @Node(coordinates = @Loc(value = COORD_9)), - @Node(coordinates = @Loc(value = COORD_10)), - @Node(coordinates = @Loc(value = COORD_11)), - @Node(coordinates = @Loc(value = COORD_12)), - @Node(coordinates = @Loc(value = COORD_13)), - @Node(coordinates = @Loc(value = COORD_14)), - @Node(coordinates = @Loc(value = COORD_15)), - @Node(coordinates = @Loc(value = COORD_16)), - @Node(coordinates = @Loc(value = COORD_17)), - @Node(coordinates = @Loc(value = COORD_18)), - @Node(coordinates = @Loc(value = COORD_19)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_8), - @Loc(value = COORD_9)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_9), - @Loc(value = COORD_10)}, - id = LINE_TWO), - @Line(coordinates = { - @Loc(value = COORD_10), - @Loc(value = COORD_11)}, - id = LINE_THREE), - @Line(coordinates = { - @Loc(value = COORD_11), - @Loc(value = COORD_8)}, - id = LINE_FOUR), - @Line(coordinates = { - @Loc(value = COORD_12), - @Loc(value = COORD_13), - @Loc(value = COORD_14), - @Loc(value = COORD_15), - @Loc(value = COORD_12)}, - id = LINE_FIVE), - @Line(coordinates = { - @Loc(value = COORD_16), - @Loc(value = COORD_17)}, - id = LINE_SIX), - @Line(coordinates = { - @Loc(value = COORD_17), - @Loc(value = COORD_18)}, - id = LINE_SEVEN), - @Line(coordinates = { - @Loc(value = COORD_18), - @Loc(value = COORD_19)}, - id = LINE_EIGHT), - @Line(coordinates = { - @Loc(value = COORD_19), - @Loc(value = COORD_16)}, - id = LINE_NINE)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line"), - @Relation.Member(id = LINE_TWO, role = "outer", type = "line"), - @Relation.Member(id = LINE_THREE, role = "outer", type = "line"), - @Relation.Member(id = LINE_FOUR, role = "outer", type = "line") - }, - tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_FIVE, role = "outer", type = "line")}, - tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_THREE, - members = { - @Relation.Member(id = LINE_SIX, role = "outer", type = "line"), - @Relation.Member(id = LINE_SEVEN, role = "outer", type = "line"), - @Relation.Member(id = LINE_EIGHT, role = "outer", type = "line"), - @Relation.Member(id = LINE_NINE, role = "outer", type = "line") - }, - tags = { - "type=boundary", - "boundary=administrative"})}) + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_8)), + @Node(coordinates = @Loc(value = COORD_9)), @Node(coordinates = @Loc(value = COORD_10)), + @Node(coordinates = @Loc(value = COORD_11)), + @Node(coordinates = @Loc(value = COORD_12)), + @Node(coordinates = @Loc(value = COORD_13)), + @Node(coordinates = @Loc(value = COORD_14)), + @Node(coordinates = @Loc(value = COORD_15)), + @Node(coordinates = @Loc(value = COORD_16)), + @Node(coordinates = @Loc(value = COORD_17)), + @Node(coordinates = @Loc(value = COORD_18)), + @Node(coordinates = @Loc(value = COORD_19)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_8), + @Loc(value = COORD_9) }, id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_9), + @Loc(value = COORD_10) }, id = LINE_TWO), + @Line(coordinates = { @Loc(value = COORD_10), + @Loc(value = COORD_11) }, id = LINE_THREE), + @Line(coordinates = { @Loc(value = COORD_11), + @Loc(value = COORD_8) }, id = LINE_FOUR), + @Line(coordinates = { @Loc(value = COORD_12), @Loc(value = COORD_13), + @Loc(value = COORD_14), @Loc(value = COORD_15), + @Loc(value = COORD_12) }, id = LINE_FIVE), + @Line(coordinates = { @Loc(value = COORD_16), + @Loc(value = COORD_17) }, id = LINE_SIX), + @Line(coordinates = { @Loc(value = COORD_17), + @Loc(value = COORD_18) }, id = LINE_SEVEN), + @Line(coordinates = { @Loc(value = COORD_18), + @Loc(value = COORD_19) }, id = LINE_EIGHT), + @Line(coordinates = { @Loc(value = COORD_19), + @Loc(value = COORD_16) }, id = LINE_NINE) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line"), + @Relation.Member(id = LINE_TWO, role = "outer", type = "line"), + @Relation.Member(id = LINE_THREE, role = "outer", type = "line"), + @Relation.Member(id = LINE_FOUR, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = LINE_FIVE, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_THREE, members = { + @Relation.Member(id = LINE_SIX, role = "outer", type = "line"), + @Relation.Member(id = LINE_SEVEN, role = "outer", type = "line"), + @Relation.Member(id = LINE_EIGHT, role = "outer", type = "line"), + @Relation.Member(id = LINE_NINE, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }) }) private Atlas crossingBoundariesTwoAreasIntersectOneOther; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_1)), - @Node(coordinates = @Loc(value = COORD_2)), - @Node(coordinates = @Loc(value = COORD_3)), - @Node(coordinates = @Loc(value = COORD_4)), - @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), - @Node(coordinates = @Loc(value = COORD_7)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_19), - @Loc(value = COORD_6), - @Loc(value = COORD_5), - @Loc(value = COORD_1)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_20), - @Loc(value = COORD_11), - @Loc(value = COORD_3), - @Loc(value = COORD_21), - @Loc(value = COORD_20)}, - id = LINE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"})}) + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_19), + @Loc(value = COORD_6), @Loc(value = COORD_5), + @Loc(value = COORD_1) }, id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_20), @Loc(value = COORD_11), + @Loc(value = COORD_3), @Loc(value = COORD_21), + @Loc(value = COORD_20) }, id = LINE_TWO) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }) }) private Atlas nonCrossingOneContainOther; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_1)), - @Node(coordinates = @Loc(value = COORD_2)), - @Node(coordinates = @Loc(value = COORD_3)), - @Node(coordinates = @Loc(value = COORD_4)), - @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), - @Node(coordinates = @Loc(value = COORD_7)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_2), - @Loc(value = COORD_3), - @Loc(value = COORD_4), - @Loc(value = COORD_1)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_5), - @Loc(value = COORD_6), - @Loc(value = COORD_7), - @Loc(value = COORD_1)}, - id = LINE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { - "type=nonBoundary", - "boundary=administrative"})}) + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_2), + @Loc(value = COORD_3), @Loc(value = COORD_4), + @Loc(value = COORD_1) }, id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), + @Loc(value = COORD_6), @Loc(value = COORD_7), + @Loc(value = COORD_1) }, id = LINE_TWO) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line") }, tags = { + "type=nonBoundary", + "boundary=administrative" }) }) private Atlas crossingOneWithWrongType; - - @TestAtlas( - nodes = { - @Node(coordinates = @Loc(value = COORD_1)), - @Node(coordinates = @Loc(value = COORD_2)), - @Node(coordinates = @Loc(value = COORD_3)), - @Node(coordinates = @Loc(value = COORD_4)), - @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), - @Node(coordinates = @Loc(value = COORD_7)) - }, - lines = { - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_2), - @Loc(value = COORD_3), - @Loc(value = COORD_4), - @Loc(value = COORD_1)}, - id = LINE_ONE), - @Line(coordinates = { - @Loc(value = COORD_1), - @Loc(value = COORD_5), - @Loc(value = COORD_6), - @Loc(value = COORD_7), - @Loc(value = COORD_1)}, - id = LINE_TWO)}, - relations = { - @Relation(id = RELATION_ONE, - members = { - @Relation.Member(id = LINE_ONE, role = "outer", type = "line")}, tags = { - "type=boundary", - "boundary=administrative"}), - @Relation(id = RELATION_TWO, - members = { - @Relation.Member(id = LINE_TWO, role = "outer", type = "line")}, tags = { - "type=nonBoundary"})}) + + @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), + @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), + @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_7)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_2), + @Loc(value = COORD_3), @Loc(value = COORD_4), + @Loc(value = COORD_1) }, id = LINE_ONE), + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), + @Loc(value = COORD_6), @Loc(value = COORD_7), + @Loc(value = COORD_1) }, id = LINE_TWO) }, relations = { + @Relation(id = RELATION_ONE, members = { + @Relation.Member(id = LINE_ONE, role = "outer", type = "line") }, tags = { + "type=boundary", "boundary=administrative" }), + @Relation(id = RELATION_TWO, members = { + @Relation.Member(id = LINE_TWO, role = "outer", type = "line") }, tags = { + "type=nonBoundary" }) }) private Atlas crossingOneMissingBoundarySpecificTag; - + public Atlas boundariesTouchEachOther() { return this.crossingBoundariesTwoAreasTouchEachOther; } - + public Atlas crossingBoundariesTwoAreasIntersectEachOther() { return this.crossingBoundariesTwoAreasIntersectEachOther; } - + public Atlas crossingBoundariesTwoAreasIntersectEachOtherWithEdges() { return this.crossingBoundariesTwoAreasIntersectEachOtherWithEdges; } - + public Atlas crossingBoundariesTwoAreasIntersectOneOther() { return this.crossingBoundariesTwoAreasIntersectOneOther; } - + public Atlas crossingBoundariesWithDifferentTypes() { return this.crossingBoundariesWithDifferentTypes; } - + public Atlas crossingBoundariesWithOnlyTagsOnWays() { return this.crossingBoundariesWithOnlyTagsOnWays; } - + public Atlas crossingOneMissingBoundarySpecificTag() { return this.crossingOneMissingBoundarySpecificTag; } - + public Atlas crossingOneWithWrongType() { return this.crossingOneWithWrongType; } - + public Atlas nonCrossingBoundariesTwoSeparate() { return this.nonCrossingBoundariesTwoSeparate; } - + public Atlas nonCrossingBoundariesTwoSeparateWithEdges() { return this.nonCrossingBoundariesTwoSeparateWithEdges; } - + public Atlas nonCrossingOneContainOther() { return this.nonCrossingOneContainOther; From 0c355be458fca3e6242b6426dfe7f8369a15429b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Thu, 15 Oct 2020 10:51:12 +0200 Subject: [PATCH 19/36] Logging qualified objects to console and analyzing relation 2332402 and 2212273. --- .../intersections/BoundaryIntersectionCheck.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index bcdacb585..46cc5b45c 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -91,8 +91,18 @@ public BoundaryIntersectionCheck(final Configuration configuration) @Override public boolean validCheckForObject(final AtlasObject object) { - return object instanceof Relation && (isRelationTypeBoundaryWithBoundaryTag(object) + boolean qualifying = object instanceof Relation && (isRelationTypeBoundaryWithBoundaryTag(object) || isRelationWithAnyLineItemWithBoundaryTags(object)); + if(qualifying){ + System.out.println("OSM Identifier passed to Boundary Check: " + object.getOsmIdentifier()); + } + if(object.getOsmIdentifier() == 2332402){ + System.out.println("ID 2332402 found it is of type " + object.getClass()); + } + if(object.getOsmIdentifier() == 2212273){ + System.out.println("ID 2212273 found it is of type " + object.getClass()); + } + return qualifying; } @Override From 5777e351eeb1ec40ba3d4a60d68637f83fa443e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Mon, 26 Oct 2020 17:42:56 +0100 Subject: [PATCH 20/36] MultiRelation and MultiLine handling. --- .../BoundaryIntersectionCheck.java | 220 +++++++++---- .../BoundaryIntersectionCheck_old.java | 298 ++++++++++++++++++ .../intersections/RelationBoundary.java | 35 ++ .../BoundaryIntersectionCheckTest.java | 22 +- 4 files changed, 497 insertions(+), 78 deletions(-) create mode 100644 src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck_old.java create mode 100644 src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 46cc5b45c..fe933b263 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -1,15 +1,5 @@ package org.openstreetmap.atlas.checks.validation.intersections; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.WKTReader; @@ -25,19 +15,36 @@ import org.openstreetmap.atlas.geography.atlas.items.Relation; import org.openstreetmap.atlas.geography.atlas.items.RelationMember; import org.openstreetmap.atlas.geography.atlas.items.RelationMemberList; +import org.openstreetmap.atlas.geography.atlas.multi.MultiLine; +import org.openstreetmap.atlas.geography.atlas.multi.MultiRelation; import org.openstreetmap.atlas.geography.atlas.walker.OsmWayWalker; import org.openstreetmap.atlas.tags.BoundaryTag; import org.openstreetmap.atlas.tags.RelationTypeTag; import org.openstreetmap.atlas.tags.annotations.validation.Validators; import org.openstreetmap.atlas.utilities.configuration.Configuration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + /** * @author srachanski */ public class BoundaryIntersectionCheck extends BaseCheck { - private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary {3} with way {2} at coordinates {4}."; + private static final String INVALID_BOUNDARY_FORMAT = "Boundaries {0} with way {1} is crossing invalidly with boundaries {2} with way {3} at coordinates {4}."; private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, @@ -67,8 +74,8 @@ private static Set getLineItems(final RelationMemberList relationMembe return relationMembers.stream().map(BoundaryIntersectionCheck::castToLineItem) .collect(Collectors.toSet()); } - - private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) + + private static boolean isObjectOfBoundaryTypeWithBoundaryTag(final AtlasObject object) { return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && Validators.hasValuesFor(object, BoundaryTag.class); @@ -91,36 +98,132 @@ public BoundaryIntersectionCheck(final Configuration configuration) @Override public boolean validCheckForObject(final AtlasObject object) { - boolean qualifying = object instanceof Relation && (isRelationTypeBoundaryWithBoundaryTag(object) - || isRelationWithAnyLineItemWithBoundaryTags(object)); - if(qualifying){ - System.out.println("OSM Identifier passed to Boundary Check: " + object.getOsmIdentifier()); - } - if(object.getOsmIdentifier() == 2332402){ - System.out.println("ID 2332402 found it is of type " + object.getClass()); - } - if(object.getOsmIdentifier() == 2212273){ - System.out.println("ID 2212273 found it is of type " + object.getClass()); - } - return qualifying; + return (object instanceof Relation || object instanceof LineItem) && + isObjectOfBoundaryTypeWithBoundaryTag(object); } @Override protected Optional flag(final AtlasObject object) { - final Relation relation = (Relation) object; + if(object instanceof Relation){ + return processRelation(object); + } + return processWay(object); + } + + private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) + { + return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) + && Validators.hasValuesFor(object, BoundaryTag.class); + } + + private Optional processRelation(AtlasObject object) { + Map tagToRelation = new HashMap<>(); + if(object instanceof MultiRelation){ + ((MultiRelation) object).relations() + .stream() + .filter(BoundaryIntersectionCheck::isObjectOfBoundaryTypeWithBoundaryTag) + .forEach(relation -> tagToRelation.put(relation.getTag(BOUNDARY).get(), relation)); + } else { + tagToRelation.put(object.getTag(BOUNDARY).get(), (Relation) object); + } + RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, getLineItems((Relation) object)); + Set instructions = new HashSet<>(); + Set objectsToFlag = new HashSet<>(); + Set matchedTags = new HashSet<>(); + for(LineItem currentLineItem : relationBoundary.getLineItems()){ + //getIntersections + Iterable intersections = object.getAtlas().lineItemsIntersecting(currentLineItem.bounds(), + this.getPredicateForLineItemsSelection(relationBoundary.getLineItems(), currentLineItem, relationBoundary.getTagToRelation().keySet())); + Set currentMatchedTags = new HashSet<>(); + //get boundaries for relation of each intersecting line + intersections.forEach(lineItem -> { + Set matchingBoundaries = getBoundaries(lineItem) + .stream() + .filter(boundary -> relationBoundary.getTagToRelation().keySet().contains(boundary.getTag(BOUNDARY))) + .collect(Collectors.toSet()); + //update globally + if(!matchingBoundaries.isEmpty()) { + currentMatchedTags.addAll(matchingBoundaries + .stream() + .map(relation -> relation.getTag(BOUNDARY)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet())); + objectsToFlag.addAll(matchingBoundaries); + objectsToFlag.add(currentLineItem); + + //TODO check for multiline? + List lineItems = getLineItems(lineItem); + lineItems.forEach(line -> { + final Set intersectingPoints = this.getIntersectingPoints(lineItem, + line); + final String instruction = this.getLocalizedInstruction(INDEX, + objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)), + Long.toString(lineItem.getOsmIdentifier()), + objectsToString(matchingBoundaries), + Long.toString(line.getOsmIdentifier()), + this.locationsToList(intersectingPoints)); + instructions.add(instruction); + }); + } + matchedTags.addAll(currentMatchedTags); + }); + + objectsToFlag.addAll(relationBoundary.getRelationsByBoundaryTags(matchedTags)); + //createFlagRecord + } + //update flag with stored results + if(objectsToFlag.isEmpty()) + { + return Optional.empty(); + } else + { + CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); + instructions.forEach(checkFlag::addInstruction); + checkFlag.addObjects(objectsToFlag); + return Optional.of(checkFlag); + } + } + + private List getLineItems(LineItem lineItem) { + if(lineItem instanceof MultiLine) + { + List lines = new ArrayList<>(); + ((MultiLine) lineItem).getSubLines() + .forEach(lines::add); + return lines; + } + return Arrays.asList(lineItem); + } + + + private Optional processWay(AtlasObject object) { + //TODO to be implemented + return Optional.empty(); + } + + private Set getLineItems(Relation relation){ final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); relationMemberLineItems.addAll(relation.membersOfType(ItemType.LINE)); final Set lineItems = BoundaryIntersectionCheck .getLineItems(relationMemberLineItems); - final CheckFlag checkFlag = this.prepareCheckFlag(object, relation, lineItems); - if (checkFlag.getFlaggedObjects().isEmpty()) - { - return Optional.empty(); - } - return Optional.of(checkFlag); + + Set lineItemsExpanded = new HashSet<>(); + Set> iterators = lineItems + .stream() + .map(lineItem -> { + if (lineItem instanceof MultiLine) { + return ((MultiLine) lineItem).getSubLines().iterator(); + } + return Arrays.asList(lineItem).iterator(); + }) + .collect(Collectors.toSet()); + iterators.forEach(iterator -> iterator.forEachRemaining(lineItemsExpanded::add)); + return lineItemsExpanded; } - + + @Override protected List getFallbackInstructions() { @@ -174,38 +277,21 @@ private void addLineItems(final CheckFlag checkFlag, final Set lineIte lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); } - private void analyzeIntersections(final Atlas atlas, final Relation relation, - final CheckFlag checkFlag, final Set lineItems, final LineItem lineItem) - { - final RelationIntersections relationIntersections = new RelationIntersections(); - lineItems.stream() - .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), - this.getPredicateForLineItemsSelection(lineItems, lineItem))) - .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) - .forEach(currentLineItem -> - { - final Set boundaries = this.getBoundary(currentLineItem); - boundaries.forEach(boundary -> relationIntersections.addIntersection(boundary, - currentLineItem)); - }); - relationIntersections.getRelations().forEach(currentRelation -> - { - if (currentRelation.getOsmIdentifier() > relation.getOsmIdentifier()) - { - this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, - relationIntersections.getLineItemMap(currentRelation)); - } - }); - } - - private Set getBoundary(final LineItem currentLineItem) + private Set getBoundaries(final LineItem currentLineItem) { return currentLineItem.relations().stream() .filter(relation -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag( relation) || LINE_ITEM_WITH_BOUNDARY_TAGS.test(currentLineItem)) .collect(Collectors.toSet()); } - + + private Set getIntersectingPoints(final LineItem lineItem, + final LineItem secondLineItem) + { + return lineItem.asPolyLine() + .intersections(secondLineItem.asPolyLine()); + } + private Set getIntersectingPoints(final LineItem lineItem, final Set currentLineItems) { @@ -216,7 +302,7 @@ private Set getIntersectingPoints(final LineItem lineItem, } private Predicate getPredicateForLineItemsSelection(final Set lineItems, - final LineItem currentLineItem) + final LineItem currentLineItem, Set strings) { return lineItemToCheck -> { @@ -263,13 +349,13 @@ private String locationsToList(final Set locations) return locations.stream().map(location -> String.format("(%s, %s)", location.getLatitude(), location.getLongitude())).collect(Collectors.joining(DELIMITER)); } - - private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, - final Set lineItems) + + private String objectsToString(final Set objects) { - final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); - lineItems.forEach(lineItem -> this.analyzeIntersections(object.getAtlas(), relation, - checkFlag, lineItems, lineItem)); - return checkFlag; + return objects + .stream() + .map(object -> Long.toString(object.getOsmIdentifier())) + .collect(Collectors.joining(DELIMITER)); } + } diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck_old.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck_old.java new file mode 100644 index 000000000..934719424 --- /dev/null +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck_old.java @@ -0,0 +1,298 @@ +package org.openstreetmap.atlas.checks.validation.intersections; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.io.ParseException; +import org.locationtech.jts.io.WKTReader; +import org.openstreetmap.atlas.checks.base.BaseCheck; +import org.openstreetmap.atlas.checks.flag.CheckFlag; +import org.openstreetmap.atlas.checks.utility.RelationIntersections; +import org.openstreetmap.atlas.geography.Location; +import org.openstreetmap.atlas.geography.atlas.Atlas; +import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; +import org.openstreetmap.atlas.geography.atlas.items.Edge; +import org.openstreetmap.atlas.geography.atlas.items.ItemType; +import org.openstreetmap.atlas.geography.atlas.items.LineItem; +import org.openstreetmap.atlas.geography.atlas.items.Relation; +import org.openstreetmap.atlas.geography.atlas.items.RelationMember; +import org.openstreetmap.atlas.geography.atlas.items.RelationMemberList; +import org.openstreetmap.atlas.geography.atlas.multi.MultiLine; +import org.openstreetmap.atlas.geography.atlas.multi.MultiRelation; +import org.openstreetmap.atlas.geography.atlas.walker.OsmWayWalker; +import org.openstreetmap.atlas.tags.BoundaryTag; +import org.openstreetmap.atlas.tags.RelationTypeTag; +import org.openstreetmap.atlas.tags.annotations.validation.Validators; +import org.openstreetmap.atlas.utilities.configuration.Configuration; + +/** + * @author srachanski + */ +public class BoundaryIntersectionCheck_old extends BaseCheck +{ + + private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary {3} with way {2} at coordinates {4}."; + private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + + " Two boundaries should not intersect each other."; + private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, + INVALID_BOUNDARY_FORMAT); + public static final String DELIMITER = ", "; + public static final int INDEX = 0; + public static final String TYPE = "type"; + public static final String BOUNDARY = "boundary"; + public static final String EMPTY = ""; + + private static final Predicate LINE_ITEM_WITH_BOUNDARY_TAGS = lineItem -> BOUNDARY + .equals(lineItem.getTag(TYPE).orElse(EMPTY)) && lineItem.getTag(BOUNDARY).isPresent(); + + private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem + .relations().stream() + .anyMatch(relationToCheck -> BoundaryIntersectionCheck_old + .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) + || LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem)); + + private static LineItem castToLineItem(final RelationMember relationMember) + { + return (LineItem) relationMember.getEntity(); + } + + private static Set getLineItems(final RelationMemberList relationMembers) + { + return relationMembers.stream().map(BoundaryIntersectionCheck_old::castToLineItem) + .collect(Collectors.toSet()); + } + + private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) + { + return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) + && Validators.hasValuesFor(object, BoundaryTag.class); + } + + private static boolean isRelationWithAnyLineItemWithBoundaryTags(final AtlasObject object) + { + final Relation relation = (Relation) object; + return BoundaryIntersectionCheck_old.getLineItems(relation.membersOfType(ItemType.EDGE)) + .stream().anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS) + || BoundaryIntersectionCheck_old.getLineItems(relation.membersOfType(ItemType.LINE)) + .stream().anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS); + } + + public BoundaryIntersectionCheck_old(final Configuration configuration) + { + super(configuration); + } + + @Override + public boolean validCheckForObject(final AtlasObject object) + { + boolean qualifying = object instanceof Relation && (isRelationTypeBoundaryWithBoundaryTag(object) + || isRelationWithAnyLineItemWithBoundaryTags(object)); + if(qualifying){ + System.out.println("OSM Identifier passed to Boundary Check: " + object.getOsmIdentifier()); + } + if(object.getOsmIdentifier() == 2332402){ + System.out.println("ID 2332402 found it is of type " + object.getClass()); + } + if(object.getOsmIdentifier() == 2212273){ + System.out.println("ID 2212273 found it is of type " + object.getClass()); + } + return qualifying; + } + + @Override + protected Optional flag(final AtlasObject object) + { + final Relation relation = (Relation) object; + final MultiRelation multiRelation = (MultiRelation) object; + final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); + relationMemberLineItems.addAll(relation.membersOfType(ItemType.LINE)); + final Set lineItems = BoundaryIntersectionCheck_old + .getLineItems(relationMemberLineItems); + //TODO rename and clean up + Set lineItemsExpanded = new HashSet<>(); + // if(lineItem instanceof MultiEdge){ + // return ((MultiEdge) lineItem)getSubEdgeList().iterator(); + // } + Set> iterators = lineItems + .stream() + .map(lineItem -> { + if (lineItem instanceof MultiLine) { + return ((MultiLine) lineItem).getSubLines().iterator(); + } +// if(lineItem instanceof MultiEdge){ +// return ((MultiEdge) lineItem)getSubEdgeList().iterator(); +// } + return Arrays.asList(lineItem).iterator(); + }) + .collect(Collectors.toSet()); + iterators.forEach(iterator -> iterator.forEachRemaining(record -> lineItemsExpanded.add(record))); + final CheckFlag checkFlag = this.prepareCheckFlag(object, relation, lineItemsExpanded); + if (checkFlag.getFlaggedObjects().isEmpty()) + { + return Optional.empty(); + } + return Optional.of(checkFlag); + } + + @Override + protected List getFallbackInstructions() + { + return FALLBACK_INSTRUCTIONS; + } + + private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, + final LineItem lineItem, final Relation intersectingBoundary, + final Map> lineItems) + { + lineItems.keySet().forEach(osmId -> + { + final Set currentLineItems = lineItems.get(osmId); + if (this.isSameBoundaryType(relation, intersectingBoundary) + || this.isSameBoundaryType(lineItem, currentLineItems)) + { + final Set intersectingPoints = this.getIntersectingPoints(lineItem, + currentLineItems); + checkFlag.addPoints(intersectingPoints); + this.addLineItems(checkFlag, currentLineItems); + checkFlag.addObject(intersectingBoundary); + final String instruction = this.getLocalizedInstruction(INDEX, + Long.toString(relation.getOsmIdentifier()), + Long.toString(lineItem.getOsmIdentifier()), Long.toString(osmId), + Long.toString(intersectingBoundary.getOsmIdentifier()), + this.locationsToList(intersectingPoints)); + checkFlag.addInstruction(instruction); + } + }); + if (!checkFlag.getInstructions().isEmpty()) + { + this.addLineItem(checkFlag, lineItem); + checkFlag.addObject(relation); + } + } + + private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) + { + if (lineItem instanceof Edge) + { + checkFlag.addObjects(new OsmWayWalker((Edge) lineItem).collectEdges()); + } + else + { + checkFlag.addObject(lineItem); + } + } + + private void addLineItems(final CheckFlag checkFlag, final Set lineItems) + { + lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); + } + + private void analyzeIntersections(final Atlas atlas, final Relation relation, + final CheckFlag checkFlag, final Set lineItems, final LineItem lineItem) + { + final RelationIntersections relationIntersections = new RelationIntersections(); + lineItems.stream() + .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), + this.getPredicateForLineItemsSelection(lineItems, lineItem))) + .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) + .forEach(currentLineItem -> + { + final Set boundaries = this.getBoundary(currentLineItem); + boundaries.forEach(boundary -> relationIntersections.addIntersection(boundary, + currentLineItem)); + }); + relationIntersections.getRelations().forEach(currentRelation -> + { + if (currentRelation.getOsmIdentifier() > relation.getOsmIdentifier()) + { + this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, + relationIntersections.getLineItemMap(currentRelation)); + } + }); + } + + private Set getBoundary(final LineItem currentLineItem) + { + return currentLineItem.relations().stream() + .filter(relation -> BoundaryIntersectionCheck_old.isRelationTypeBoundaryWithBoundaryTag( + relation) || LINE_ITEM_WITH_BOUNDARY_TAGS.test(currentLineItem)) + .collect(Collectors.toSet()); + } + + private Set getIntersectingPoints(final LineItem lineItem, + final Set currentLineItems) + { + return currentLineItems.stream() + .map(currentLineItem -> currentLineItem.asPolyLine() + .intersections(lineItem.asPolyLine())) + .flatMap(Collection::stream).collect(Collectors.toSet()); + } + + private Predicate getPredicateForLineItemsSelection(final Set lineItems, + final LineItem currentLineItem) + { + return lineItemToCheck -> + { + if (LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && !lineItems.contains(lineItemToCheck)) + { + return this.isCrossingNotTouching(currentLineItem, lineItemToCheck); + } + return false; + }; + } + + private boolean isCrossingNotTouching(final LineItem currentLineItem, + final LineItem lineItemToCheck) + { + final WKTReader wktReader = new WKTReader(); + try + { + final Geometry line1 = wktReader.read(lineItemToCheck.asPolyLine().toWkt()); + final Geometry line2 = wktReader.read(currentLineItem.asPolyLine().toWkt()); + return line1.crosses(line2) && !line1.touches(line2); + } + catch (final ParseException e) + { + return false; + } + } + + private boolean isSameBoundaryType(final Relation relation, final Relation intersectingBoundary) + { + return intersectingBoundary.getTag(BOUNDARY).equals(relation.getTag(BOUNDARY)); + } + + private boolean isSameBoundaryType(final LineItem lineItem, + final Set currentLineItems) + { + final LineItem intersectingLineItem = currentLineItems.iterator().next(); + return !currentLineItems.isEmpty() && LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem) + && LINE_ITEM_WITH_BOUNDARY_TAGS.test(intersectingLineItem) + && lineItem.getTag(BOUNDARY).equals(intersectingLineItem.getTag(BOUNDARY)); + } + + private String locationsToList(final Set locations) + { + return locations.stream().map(location -> String.format("(%s, %s)", location.getLatitude(), + location.getLongitude())).collect(Collectors.joining(DELIMITER)); + } + + private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, + final Set lineItems) + { + final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); + lineItems.forEach(lineItem -> this.analyzeIntersections(object.getAtlas(), relation, + checkFlag, lineItems, lineItem)); + return checkFlag; + } +} diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java new file mode 100644 index 000000000..3a83a1224 --- /dev/null +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java @@ -0,0 +1,35 @@ +package org.openstreetmap.atlas.checks.validation.intersections; + +import org.openstreetmap.atlas.geography.atlas.items.LineItem; +import org.openstreetmap.atlas.geography.atlas.items.Relation; + +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class RelationBoundary { + + private final Map tagToRelation; + private final Set lineItems; + + public RelationBoundary(Map tagToRelation, Set lineItems) { + this.tagToRelation = tagToRelation; + this.lineItems = lineItems; + } + + public Map getTagToRelation() { + return tagToRelation; + } + + public Set getLineItems() { + return lineItems; + } + + public Set getRelationsByBoundaryTags(Set tags){ + return tagToRelation.keySet() + .stream() + .filter(tags::contains) + .map(tagToRelation::get) + .collect(Collectors.toSet()); + } +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index 889f847e9..0d725a0af 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -25,7 +25,7 @@ public class BoundaryIntersectionCheckTest public void testInvalidThreeCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectOneOther(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); } @@ -33,7 +33,7 @@ public void testInvalidThreeCrossingItemsAtlas() public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() { this.verifier.actual(this.setup.crossingBoundariesWithOnlyTagsOnWays(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); this.verifier.verify(flag -> { @@ -46,7 +46,7 @@ public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() public void testInvalidTwoCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); this.verifier.verify(flag -> { @@ -59,7 +59,7 @@ public void testInvalidTwoCrossingItemsAtlas() public void testInvalidTwoCrossingItemsWithEdgesAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOtherWithEdges(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); this.verifier.verify(flag -> { @@ -72,7 +72,7 @@ public void testInvalidTwoCrossingItemsWithEdgesAtlas() public void testTouchingObjects() { this.verifier.actual(this.setup.boundariesTouchEachOther(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -80,7 +80,7 @@ public void testTouchingObjects() public void testValidCrossingObjectsOneMissingBoundarySpecificTag() { this.verifier.actual(this.setup.crossingOneMissingBoundarySpecificTag(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -88,7 +88,7 @@ public void testValidCrossingObjectsOneMissingBoundarySpecificTag() public void testValidCrossingObjectsOneMissingType() { this.verifier.actual(this.setup.crossingOneWithWrongType(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -96,7 +96,7 @@ public void testValidCrossingObjectsOneMissingType() public void testValidCrossingObjectsWithDifferentTypes() { this.verifier.actual(this.setup.crossingBoundariesWithDifferentTypes(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -104,7 +104,7 @@ public void testValidCrossingObjectsWithDifferentTypes() public void testValidNonCrossingObjects() { this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparate(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -112,7 +112,7 @@ public void testValidNonCrossingObjects() public void testValidNonCrossingObjectsOneContainOther() { this.verifier.actual(this.setup.nonCrossingOneContainOther(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -120,7 +120,7 @@ public void testValidNonCrossingObjectsOneContainOther() public void testValidNonCrossingObjectsWithEdges() { this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparateWithEdges(), - new BoundaryIntersectionCheck(this.configuration)); + new BoundaryIntersectionCheck_old(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } From 10871c27343193bc24a8b93b067474326d9e0347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Tue, 27 Oct 2020 17:24:25 +0100 Subject: [PATCH 21/36] Tests fixed. --- .../BoundaryIntersectionCheck.java | 23 +- .../BoundaryIntersectionCheck_old.java | 298 ------------------ .../BoundaryIntersectionCheckTest.java | 48 +-- 3 files changed, 38 insertions(+), 331 deletions(-) delete mode 100644 src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck_old.java diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index fe933b263..8b2a87148 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -140,7 +140,7 @@ private Optional processRelation(AtlasObject object) { intersections.forEach(lineItem -> { Set matchingBoundaries = getBoundaries(lineItem) .stream() - .filter(boundary -> relationBoundary.getTagToRelation().keySet().contains(boundary.getTag(BOUNDARY))) + .filter(boundary -> relationBoundary.getTagToRelation().keySet().contains(boundary.getTag(BOUNDARY).get())) .collect(Collectors.toSet()); //update globally if(!matchingBoundaries.isEmpty()) { @@ -156,15 +156,20 @@ private Optional processRelation(AtlasObject object) { //TODO check for multiline? List lineItems = getLineItems(lineItem); lineItems.forEach(line -> { + objectsToFlag.add(line); final Set intersectingPoints = this.getIntersectingPoints(lineItem, line); - final String instruction = this.getLocalizedInstruction(INDEX, - objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)), - Long.toString(lineItem.getOsmIdentifier()), - objectsToString(matchingBoundaries), - Long.toString(line.getOsmIdentifier()), - this.locationsToList(intersectingPoints)); - instructions.add(instruction); + String firstBoundaries = objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); + String secondBoundaries = objectsToString(matchingBoundaries); + if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) { + final String instruction = this.getLocalizedInstruction(INDEX, + firstBoundaries, + Long.toString(lineItem.getOsmIdentifier()), + secondBoundaries, + Long.toString(line.getOsmIdentifier()), + this.locationsToList(intersectingPoints)); + instructions.add(instruction); + } }); } matchedTags.addAll(currentMatchedTags); @@ -174,7 +179,7 @@ private Optional processRelation(AtlasObject object) { //createFlagRecord } //update flag with stored results - if(objectsToFlag.isEmpty()) + if(instructions.isEmpty()) { return Optional.empty(); } else diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck_old.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck_old.java deleted file mode 100644 index 934719424..000000000 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck_old.java +++ /dev/null @@ -1,298 +0,0 @@ -package org.openstreetmap.atlas.checks.validation.intersections; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.io.ParseException; -import org.locationtech.jts.io.WKTReader; -import org.openstreetmap.atlas.checks.base.BaseCheck; -import org.openstreetmap.atlas.checks.flag.CheckFlag; -import org.openstreetmap.atlas.checks.utility.RelationIntersections; -import org.openstreetmap.atlas.geography.Location; -import org.openstreetmap.atlas.geography.atlas.Atlas; -import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; -import org.openstreetmap.atlas.geography.atlas.items.Edge; -import org.openstreetmap.atlas.geography.atlas.items.ItemType; -import org.openstreetmap.atlas.geography.atlas.items.LineItem; -import org.openstreetmap.atlas.geography.atlas.items.Relation; -import org.openstreetmap.atlas.geography.atlas.items.RelationMember; -import org.openstreetmap.atlas.geography.atlas.items.RelationMemberList; -import org.openstreetmap.atlas.geography.atlas.multi.MultiLine; -import org.openstreetmap.atlas.geography.atlas.multi.MultiRelation; -import org.openstreetmap.atlas.geography.atlas.walker.OsmWayWalker; -import org.openstreetmap.atlas.tags.BoundaryTag; -import org.openstreetmap.atlas.tags.RelationTypeTag; -import org.openstreetmap.atlas.tags.annotations.validation.Validators; -import org.openstreetmap.atlas.utilities.configuration.Configuration; - -/** - * @author srachanski - */ -public class BoundaryIntersectionCheck_old extends BaseCheck -{ - - private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary {3} with way {2} at coordinates {4}."; - private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT - + " Two boundaries should not intersect each other."; - private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, - INVALID_BOUNDARY_FORMAT); - public static final String DELIMITER = ", "; - public static final int INDEX = 0; - public static final String TYPE = "type"; - public static final String BOUNDARY = "boundary"; - public static final String EMPTY = ""; - - private static final Predicate LINE_ITEM_WITH_BOUNDARY_TAGS = lineItem -> BOUNDARY - .equals(lineItem.getTag(TYPE).orElse(EMPTY)) && lineItem.getTag(BOUNDARY).isPresent(); - - private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem - .relations().stream() - .anyMatch(relationToCheck -> BoundaryIntersectionCheck_old - .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) - || LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem)); - - private static LineItem castToLineItem(final RelationMember relationMember) - { - return (LineItem) relationMember.getEntity(); - } - - private static Set getLineItems(final RelationMemberList relationMembers) - { - return relationMembers.stream().map(BoundaryIntersectionCheck_old::castToLineItem) - .collect(Collectors.toSet()); - } - - private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) - { - return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) - && Validators.hasValuesFor(object, BoundaryTag.class); - } - - private static boolean isRelationWithAnyLineItemWithBoundaryTags(final AtlasObject object) - { - final Relation relation = (Relation) object; - return BoundaryIntersectionCheck_old.getLineItems(relation.membersOfType(ItemType.EDGE)) - .stream().anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS) - || BoundaryIntersectionCheck_old.getLineItems(relation.membersOfType(ItemType.LINE)) - .stream().anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS); - } - - public BoundaryIntersectionCheck_old(final Configuration configuration) - { - super(configuration); - } - - @Override - public boolean validCheckForObject(final AtlasObject object) - { - boolean qualifying = object instanceof Relation && (isRelationTypeBoundaryWithBoundaryTag(object) - || isRelationWithAnyLineItemWithBoundaryTags(object)); - if(qualifying){ - System.out.println("OSM Identifier passed to Boundary Check: " + object.getOsmIdentifier()); - } - if(object.getOsmIdentifier() == 2332402){ - System.out.println("ID 2332402 found it is of type " + object.getClass()); - } - if(object.getOsmIdentifier() == 2212273){ - System.out.println("ID 2212273 found it is of type " + object.getClass()); - } - return qualifying; - } - - @Override - protected Optional flag(final AtlasObject object) - { - final Relation relation = (Relation) object; - final MultiRelation multiRelation = (MultiRelation) object; - final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); - relationMemberLineItems.addAll(relation.membersOfType(ItemType.LINE)); - final Set lineItems = BoundaryIntersectionCheck_old - .getLineItems(relationMemberLineItems); - //TODO rename and clean up - Set lineItemsExpanded = new HashSet<>(); - // if(lineItem instanceof MultiEdge){ - // return ((MultiEdge) lineItem)getSubEdgeList().iterator(); - // } - Set> iterators = lineItems - .stream() - .map(lineItem -> { - if (lineItem instanceof MultiLine) { - return ((MultiLine) lineItem).getSubLines().iterator(); - } -// if(lineItem instanceof MultiEdge){ -// return ((MultiEdge) lineItem)getSubEdgeList().iterator(); -// } - return Arrays.asList(lineItem).iterator(); - }) - .collect(Collectors.toSet()); - iterators.forEach(iterator -> iterator.forEachRemaining(record -> lineItemsExpanded.add(record))); - final CheckFlag checkFlag = this.prepareCheckFlag(object, relation, lineItemsExpanded); - if (checkFlag.getFlaggedObjects().isEmpty()) - { - return Optional.empty(); - } - return Optional.of(checkFlag); - } - - @Override - protected List getFallbackInstructions() - { - return FALLBACK_INSTRUCTIONS; - } - - private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, - final LineItem lineItem, final Relation intersectingBoundary, - final Map> lineItems) - { - lineItems.keySet().forEach(osmId -> - { - final Set currentLineItems = lineItems.get(osmId); - if (this.isSameBoundaryType(relation, intersectingBoundary) - || this.isSameBoundaryType(lineItem, currentLineItems)) - { - final Set intersectingPoints = this.getIntersectingPoints(lineItem, - currentLineItems); - checkFlag.addPoints(intersectingPoints); - this.addLineItems(checkFlag, currentLineItems); - checkFlag.addObject(intersectingBoundary); - final String instruction = this.getLocalizedInstruction(INDEX, - Long.toString(relation.getOsmIdentifier()), - Long.toString(lineItem.getOsmIdentifier()), Long.toString(osmId), - Long.toString(intersectingBoundary.getOsmIdentifier()), - this.locationsToList(intersectingPoints)); - checkFlag.addInstruction(instruction); - } - }); - if (!checkFlag.getInstructions().isEmpty()) - { - this.addLineItem(checkFlag, lineItem); - checkFlag.addObject(relation); - } - } - - private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) - { - if (lineItem instanceof Edge) - { - checkFlag.addObjects(new OsmWayWalker((Edge) lineItem).collectEdges()); - } - else - { - checkFlag.addObject(lineItem); - } - } - - private void addLineItems(final CheckFlag checkFlag, final Set lineItems) - { - lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); - } - - private void analyzeIntersections(final Atlas atlas, final Relation relation, - final CheckFlag checkFlag, final Set lineItems, final LineItem lineItem) - { - final RelationIntersections relationIntersections = new RelationIntersections(); - lineItems.stream() - .map(currentLineItem -> atlas.lineItemsIntersecting(currentLineItem.bounds(), - this.getPredicateForLineItemsSelection(lineItems, lineItem))) - .flatMap(iterable -> StreamSupport.stream(iterable.spliterator(), false)) - .forEach(currentLineItem -> - { - final Set boundaries = this.getBoundary(currentLineItem); - boundaries.forEach(boundary -> relationIntersections.addIntersection(boundary, - currentLineItem)); - }); - relationIntersections.getRelations().forEach(currentRelation -> - { - if (currentRelation.getOsmIdentifier() > relation.getOsmIdentifier()) - { - this.addInformationToFlag(checkFlag, relation, lineItem, currentRelation, - relationIntersections.getLineItemMap(currentRelation)); - } - }); - } - - private Set getBoundary(final LineItem currentLineItem) - { - return currentLineItem.relations().stream() - .filter(relation -> BoundaryIntersectionCheck_old.isRelationTypeBoundaryWithBoundaryTag( - relation) || LINE_ITEM_WITH_BOUNDARY_TAGS.test(currentLineItem)) - .collect(Collectors.toSet()); - } - - private Set getIntersectingPoints(final LineItem lineItem, - final Set currentLineItems) - { - return currentLineItems.stream() - .map(currentLineItem -> currentLineItem.asPolyLine() - .intersections(lineItem.asPolyLine())) - .flatMap(Collection::stream).collect(Collectors.toSet()); - } - - private Predicate getPredicateForLineItemsSelection(final Set lineItems, - final LineItem currentLineItem) - { - return lineItemToCheck -> - { - if (LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && !lineItems.contains(lineItemToCheck)) - { - return this.isCrossingNotTouching(currentLineItem, lineItemToCheck); - } - return false; - }; - } - - private boolean isCrossingNotTouching(final LineItem currentLineItem, - final LineItem lineItemToCheck) - { - final WKTReader wktReader = new WKTReader(); - try - { - final Geometry line1 = wktReader.read(lineItemToCheck.asPolyLine().toWkt()); - final Geometry line2 = wktReader.read(currentLineItem.asPolyLine().toWkt()); - return line1.crosses(line2) && !line1.touches(line2); - } - catch (final ParseException e) - { - return false; - } - } - - private boolean isSameBoundaryType(final Relation relation, final Relation intersectingBoundary) - { - return intersectingBoundary.getTag(BOUNDARY).equals(relation.getTag(BOUNDARY)); - } - - private boolean isSameBoundaryType(final LineItem lineItem, - final Set currentLineItems) - { - final LineItem intersectingLineItem = currentLineItems.iterator().next(); - return !currentLineItems.isEmpty() && LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem) - && LINE_ITEM_WITH_BOUNDARY_TAGS.test(intersectingLineItem) - && lineItem.getTag(BOUNDARY).equals(intersectingLineItem.getTag(BOUNDARY)); - } - - private String locationsToList(final Set locations) - { - return locations.stream().map(location -> String.format("(%s, %s)", location.getLatitude(), - location.getLongitude())).collect(Collectors.joining(DELIMITER)); - } - - private CheckFlag prepareCheckFlag(final AtlasObject object, final Relation relation, - final Set lineItems) - { - final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); - lineItems.forEach(lineItem -> this.analyzeIntersections(object.getAtlas(), relation, - checkFlag, lineItems, lineItem)); - return checkFlag; - } -} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index 0d725a0af..d0613f528 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -25,32 +25,32 @@ public class BoundaryIntersectionCheckTest public void testInvalidThreeCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectOneOther(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); } - @Test - public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() - { - this.verifier.actual(this.setup.crossingBoundariesWithOnlyTagsOnWays(), - new BoundaryIntersectionCheck_old(this.configuration)); - this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); - this.verifier.verify(flag -> - { - Assert.assertEquals(6, flag.getFlaggedObjects().size()); - Assert.assertEquals(1, flag.getInstructions().split("\n").length); - }); - } +// @Test +// public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() +// { +// this.verifier.actual(this.setup.crossingBoundariesWithOnlyTagsOnWays(), +// new BoundaryIntersectionCheck(this.configuration)); +// this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); +// this.verifier.verify(flag -> +// { +// Assert.assertEquals(6, flag.getFlaggedObjects().size()); +// Assert.assertEquals(1, flag.getInstructions().split("\n").length); +// }); +// } @Test public void testInvalidTwoCrossingItemsAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOther(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); this.verifier.verify(flag -> { - Assert.assertEquals(6, flag.getFlaggedObjects().size()); + Assert.assertEquals(4, flag.getFlaggedObjects().size()); Assert.assertEquals(1, flag.getInstructions().split("\n").length); }); } @@ -59,11 +59,11 @@ public void testInvalidTwoCrossingItemsAtlas() public void testInvalidTwoCrossingItemsWithEdgesAtlas() { this.verifier.actual(this.setup.crossingBoundariesTwoAreasIntersectEachOtherWithEdges(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); this.verifier.verify(flag -> { - Assert.assertEquals(6, flag.getFlaggedObjects().size()); + Assert.assertEquals(4, flag.getFlaggedObjects().size()); Assert.assertEquals(1, flag.getInstructions().split("\n").length); }); } @@ -72,7 +72,7 @@ public void testInvalidTwoCrossingItemsWithEdgesAtlas() public void testTouchingObjects() { this.verifier.actual(this.setup.boundariesTouchEachOther(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -80,7 +80,7 @@ public void testTouchingObjects() public void testValidCrossingObjectsOneMissingBoundarySpecificTag() { this.verifier.actual(this.setup.crossingOneMissingBoundarySpecificTag(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -88,7 +88,7 @@ public void testValidCrossingObjectsOneMissingBoundarySpecificTag() public void testValidCrossingObjectsOneMissingType() { this.verifier.actual(this.setup.crossingOneWithWrongType(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -96,7 +96,7 @@ public void testValidCrossingObjectsOneMissingType() public void testValidCrossingObjectsWithDifferentTypes() { this.verifier.actual(this.setup.crossingBoundariesWithDifferentTypes(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -104,7 +104,7 @@ public void testValidCrossingObjectsWithDifferentTypes() public void testValidNonCrossingObjects() { this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparate(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -112,7 +112,7 @@ public void testValidNonCrossingObjects() public void testValidNonCrossingObjectsOneContainOther() { this.verifier.actual(this.setup.nonCrossingOneContainOther(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } @@ -120,7 +120,7 @@ public void testValidNonCrossingObjectsOneContainOther() public void testValidNonCrossingObjectsWithEdges() { this.verifier.actual(this.setup.nonCrossingBoundariesTwoSeparateWithEdges(), - new BoundaryIntersectionCheck_old(this.configuration)); + new BoundaryIntersectionCheck(this.configuration)); this.verifier.globallyVerify(flags -> Assert.assertEquals(0, flags.size())); } From aacdd01aa24cd17ce9afcaee260a64903cb55e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 28 Oct 2020 14:21:58 +0100 Subject: [PATCH 22/36] Parent relation included. --- .../BoundaryIntersectionCheck.java | 127 ++++-------------- 1 file changed, 24 insertions(+), 103 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 8b2a87148..fc14ba3b3 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -5,11 +5,8 @@ import org.locationtech.jts.io.WKTReader; import org.openstreetmap.atlas.checks.base.BaseCheck; import org.openstreetmap.atlas.checks.flag.CheckFlag; -import org.openstreetmap.atlas.checks.utility.RelationIntersections; import org.openstreetmap.atlas.geography.Location; -import org.openstreetmap.atlas.geography.atlas.Atlas; import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; -import org.openstreetmap.atlas.geography.atlas.items.Edge; import org.openstreetmap.atlas.geography.atlas.items.ItemType; import org.openstreetmap.atlas.geography.atlas.items.LineItem; import org.openstreetmap.atlas.geography.atlas.items.Relation; @@ -17,7 +14,6 @@ import org.openstreetmap.atlas.geography.atlas.items.RelationMemberList; import org.openstreetmap.atlas.geography.atlas.multi.MultiLine; import org.openstreetmap.atlas.geography.atlas.multi.MultiRelation; -import org.openstreetmap.atlas.geography.atlas.walker.OsmWayWalker; import org.openstreetmap.atlas.tags.BoundaryTag; import org.openstreetmap.atlas.tags.RelationTypeTag; import org.openstreetmap.atlas.tags.annotations.validation.Validators; @@ -25,7 +21,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -35,8 +30,6 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; /** * @author srachanski @@ -81,15 +74,6 @@ private static boolean isObjectOfBoundaryTypeWithBoundaryTag(final AtlasObject o && Validators.hasValuesFor(object, BoundaryTag.class); } - private static boolean isRelationWithAnyLineItemWithBoundaryTags(final AtlasObject object) - { - final Relation relation = (Relation) object; - return BoundaryIntersectionCheck.getLineItems(relation.membersOfType(ItemType.EDGE)) - .stream().anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS) - || BoundaryIntersectionCheck.getLineItems(relation.membersOfType(ItemType.LINE)) - .stream().anyMatch(LINE_ITEM_WITH_BOUNDARY_TAGS); - } - public BoundaryIntersectionCheck(final Configuration configuration) { super(configuration); @@ -118,15 +102,7 @@ private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject o } private Optional processRelation(AtlasObject object) { - Map tagToRelation = new HashMap<>(); - if(object instanceof MultiRelation){ - ((MultiRelation) object).relations() - .stream() - .filter(BoundaryIntersectionCheck::isObjectOfBoundaryTypeWithBoundaryTag) - .forEach(relation -> tagToRelation.put(relation.getTag(BOUNDARY).get(), relation)); - } else { - tagToRelation.put(object.getTag(BOUNDARY).get(), (Relation) object); - } + Map tagToRelation = getRelationMap(object); RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, getLineItems((Relation) object)); Set instructions = new HashSet<>(); Set objectsToFlag = new HashSet<>(); @@ -153,7 +129,6 @@ private Optional processRelation(AtlasObject object) { objectsToFlag.addAll(matchingBoundaries); objectsToFlag.add(currentLineItem); - //TODO check for multiline? List lineItems = getLineItems(lineItem); lineItems.forEach(line -> { objectsToFlag.add(line); @@ -162,13 +137,7 @@ private Optional processRelation(AtlasObject object) { String firstBoundaries = objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); String secondBoundaries = objectsToString(matchingBoundaries); if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) { - final String instruction = this.getLocalizedInstruction(INDEX, - firstBoundaries, - Long.toString(lineItem.getOsmIdentifier()), - secondBoundaries, - Long.toString(line.getOsmIdentifier()), - this.locationsToList(intersectingPoints)); - instructions.add(instruction); + addInstruction(instructions, lineItem, line, intersectingPoints, firstBoundaries, secondBoundaries); } }); } @@ -191,6 +160,28 @@ private Optional processRelation(AtlasObject object) { } } + private void addInstruction(Set instructions, LineItem lineItem, LineItem line, Set intersectingPoints, String firstBoundaries, String secondBoundaries) { + final String instruction = this.getLocalizedInstruction(INDEX, + firstBoundaries, + Long.toString(lineItem.getOsmIdentifier()), + secondBoundaries, + Long.toString(line.getOsmIdentifier()), + this.locationsToList(intersectingPoints)); + instructions.add(instruction); + } + + private Map getRelationMap(AtlasObject object) { + Map tagToRelation = new HashMap<>(); + if(object instanceof MultiRelation){ + ((MultiRelation) object).relations() + .stream() + .filter(BoundaryIntersectionCheck::isObjectOfBoundaryTypeWithBoundaryTag) + .forEach(relation -> tagToRelation.put(relation.getTag(BOUNDARY).get(), relation)); + } + tagToRelation.put(object.getTag(BOUNDARY).get(), (Relation) object); + return tagToRelation; + } + private List getLineItems(LineItem lineItem) { if(lineItem instanceof MultiLine) { @@ -235,53 +226,6 @@ protected List getFallbackInstructions() return FALLBACK_INSTRUCTIONS; } - private void addInformationToFlag(final CheckFlag checkFlag, final Relation relation, - final LineItem lineItem, final Relation intersectingBoundary, - final Map> lineItems) - { - lineItems.keySet().forEach(osmId -> - { - final Set currentLineItems = lineItems.get(osmId); - if (this.isSameBoundaryType(relation, intersectingBoundary) - || this.isSameBoundaryType(lineItem, currentLineItems)) - { - final Set intersectingPoints = this.getIntersectingPoints(lineItem, - currentLineItems); - checkFlag.addPoints(intersectingPoints); - this.addLineItems(checkFlag, currentLineItems); - checkFlag.addObject(intersectingBoundary); - final String instruction = this.getLocalizedInstruction(INDEX, - Long.toString(relation.getOsmIdentifier()), - Long.toString(lineItem.getOsmIdentifier()), Long.toString(osmId), - Long.toString(intersectingBoundary.getOsmIdentifier()), - this.locationsToList(intersectingPoints)); - checkFlag.addInstruction(instruction); - } - }); - if (!checkFlag.getInstructions().isEmpty()) - { - this.addLineItem(checkFlag, lineItem); - checkFlag.addObject(relation); - } - } - - private void addLineItem(final CheckFlag checkFlag, final LineItem lineItem) - { - if (lineItem instanceof Edge) - { - checkFlag.addObjects(new OsmWayWalker((Edge) lineItem).collectEdges()); - } - else - { - checkFlag.addObject(lineItem); - } - } - - private void addLineItems(final CheckFlag checkFlag, final Set lineItems) - { - lineItems.forEach(lineItem -> this.addLineItem(checkFlag, lineItem)); - } - private Set getBoundaries(final LineItem currentLineItem) { return currentLineItem.relations().stream() @@ -296,15 +240,6 @@ private Set getIntersectingPoints(final LineItem lineItem, return lineItem.asPolyLine() .intersections(secondLineItem.asPolyLine()); } - - private Set getIntersectingPoints(final LineItem lineItem, - final Set currentLineItems) - { - return currentLineItems.stream() - .map(currentLineItem -> currentLineItem.asPolyLine() - .intersections(lineItem.asPolyLine())) - .flatMap(Collection::stream).collect(Collectors.toSet()); - } private Predicate getPredicateForLineItemsSelection(final Set lineItems, final LineItem currentLineItem, Set strings) @@ -335,20 +270,6 @@ private boolean isCrossingNotTouching(final LineItem currentLineItem, } } - private boolean isSameBoundaryType(final Relation relation, final Relation intersectingBoundary) - { - return intersectingBoundary.getTag(BOUNDARY).equals(relation.getTag(BOUNDARY)); - } - - private boolean isSameBoundaryType(final LineItem lineItem, - final Set currentLineItems) - { - final LineItem intersectingLineItem = currentLineItems.iterator().next(); - return !currentLineItems.isEmpty() && LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem) - && LINE_ITEM_WITH_BOUNDARY_TAGS.test(intersectingLineItem) - && lineItem.getTag(BOUNDARY).equals(intersectingLineItem.getTag(BOUNDARY)); - } - private String locationsToList(final Set locations) { return locations.stream().map(location -> String.format("(%s, %s)", location.getLatitude(), From 6353f6b9adf002c5ac427c7c835faae8de90e43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 28 Oct 2020 14:54:21 +0100 Subject: [PATCH 23/36] Line tags handling excluded. --- .../BoundaryIntersectionCheck.java | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index fc14ba3b3..a74dea266 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -48,14 +49,14 @@ public class BoundaryIntersectionCheck extends BaseCheck public static final String BOUNDARY = "boundary"; public static final String EMPTY = ""; - private static final Predicate LINE_ITEM_WITH_BOUNDARY_TAGS = lineItem -> BOUNDARY - .equals(lineItem.getTag(TYPE).orElse(EMPTY)) && lineItem.getTag(BOUNDARY).isPresent(); +// private static final Predicate LINE_ITEM_WITH_BOUNDARY_TAGS = lineItem -> BOUNDARY +// .equals(lineItem.getTag(TYPE).orElse(EMPTY)) && lineItem.getTag(BOUNDARY).isPresent(); private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem .relations().stream() .anyMatch(relationToCheck -> BoundaryIntersectionCheck - .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) - || LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem)); + .isRelationTypeBoundaryWithBoundaryTag(relationToCheck)); +// || LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem)); private static LineItem castToLineItem(final RelationMember relationMember) { @@ -228,9 +229,13 @@ protected List getFallbackInstructions() private Set getBoundaries(final LineItem currentLineItem) { - return currentLineItem.relations().stream() - .filter(relation -> BoundaryIntersectionCheck.isRelationTypeBoundaryWithBoundaryTag( - relation) || LINE_ITEM_WITH_BOUNDARY_TAGS.test(currentLineItem)) + Set relations = currentLineItem.relations().stream() + .filter(relation -> relation instanceof MultiRelation) + .map(relation -> ((MultiRelation) relation).relations()) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + relations.addAll(currentLineItem.relations()); + return relations.stream().filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) .collect(Collectors.toSet()); } @@ -242,17 +247,25 @@ private Set getIntersectingPoints(final LineItem lineItem, } private Predicate getPredicateForLineItemsSelection(final Set lineItems, - final LineItem currentLineItem, Set strings) + final LineItem currentLineItem, Set boundaryTags) { return lineItemToCheck -> { - if (LINE_ITEM_AS_BOUNDARY.test(lineItemToCheck) && !lineItems.contains(lineItemToCheck)) + if (checkLineItemAsBoundary(lineItemToCheck, boundaryTags) && !lineItems.contains(lineItemToCheck)) { return this.isCrossingNotTouching(currentLineItem, lineItemToCheck); } return false; }; } + + private boolean checkLineItemAsBoundary(LineItem lineItem, Set boundaryTags){ + return lineItem + .relations().stream() + .anyMatch(relationToCheck -> BoundaryIntersectionCheck + .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) + && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())); + } private boolean isCrossingNotTouching(final LineItem currentLineItem, final LineItem lineItemToCheck) From 630e6034b9ed286e4f1c87dc85e9fbb2e5b21aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Thu, 5 Nov 2020 22:42:47 +0100 Subject: [PATCH 24/36] Self way intersection fixed. --- .../validation/intersections/BoundaryIntersectionCheck.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index a74dea266..83a957ce1 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -133,12 +133,12 @@ private Optional processRelation(AtlasObject object) { List lineItems = getLineItems(lineItem); lineItems.forEach(line -> { objectsToFlag.add(line); - final Set intersectingPoints = this.getIntersectingPoints(lineItem, + final Set intersectingPoints = this.getIntersectingPoints(currentLineItem, line); String firstBoundaries = objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); String secondBoundaries = objectsToString(matchingBoundaries); if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) { - addInstruction(instructions, lineItem, line, intersectingPoints, firstBoundaries, secondBoundaries); + addInstruction(instructions, currentLineItem, line, intersectingPoints, firstBoundaries, secondBoundaries); } }); } From 2843b7e86f147453c8775bbe1967bfefdd628269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Thu, 19 Nov 2020 17:25:50 +0100 Subject: [PATCH 25/36] Crude logging added. --- .../validation/intersections/BoundaryIntersectionCheck.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 83a957ce1..4b3c350cb 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -83,6 +83,7 @@ public BoundaryIntersectionCheck(final Configuration configuration) @Override public boolean validCheckForObject(final AtlasObject object) { + System.out.println("Checking id " + object.getOsmIdentifier() + " " + object.getClass()); return (object instanceof Relation || object instanceof LineItem) && isObjectOfBoundaryTypeWithBoundaryTag(object); } @@ -90,7 +91,9 @@ public boolean validCheckForObject(final AtlasObject object) @Override protected Optional flag(final AtlasObject object) { + System.out.println("Checking for flag id " + object.getOsmIdentifier() + " " + object.getClass()); if(object instanceof Relation){ + System.out.println("Processing id " + object.getOsmIdentifier() + " " + object.getClass()); return processRelation(object); } return processWay(object); From 639b009ac6e3c7c3d44e82223c351a5513bcc022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Fri, 27 Nov 2020 18:26:52 +0100 Subject: [PATCH 26/36] Working version. --- .../BoundaryIntersectionCheck.java | 309 ++++++++++++++---- .../intersections/BoundaryPart.java | 41 +++ .../intersections/RelationBoundary.java | 15 +- 3 files changed, 288 insertions(+), 77 deletions(-) create mode 100644 src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 4b3c350cb..5145dda84 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -1,11 +1,13 @@ package org.openstreetmap.atlas.checks.validation.intersections; +import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.WKTReader; import org.openstreetmap.atlas.checks.base.BaseCheck; import org.openstreetmap.atlas.checks.flag.CheckFlag; import org.openstreetmap.atlas.geography.Location; +import org.openstreetmap.atlas.geography.atlas.items.Area; import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; import org.openstreetmap.atlas.geography.atlas.items.ItemType; import org.openstreetmap.atlas.geography.atlas.items.LineItem; @@ -24,13 +26,13 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * @author srachanski @@ -65,7 +67,8 @@ private static LineItem castToLineItem(final RelationMember relationMember) private static Set getLineItems(final RelationMemberList relationMembers) { - return relationMembers.stream().map(BoundaryIntersectionCheck::castToLineItem) + return relationMembers.stream() + .map(BoundaryIntersectionCheck::castToLineItem) .collect(Collectors.toSet()); } @@ -83,7 +86,6 @@ public BoundaryIntersectionCheck(final Configuration configuration) @Override public boolean validCheckForObject(final AtlasObject object) { - System.out.println("Checking id " + object.getOsmIdentifier() + " " + object.getClass()); return (object instanceof Relation || object instanceof LineItem) && isObjectOfBoundaryTypeWithBoundaryTag(object); } @@ -91,11 +93,10 @@ public boolean validCheckForObject(final AtlasObject object) @Override protected Optional flag(final AtlasObject object) { - System.out.println("Checking for flag id " + object.getOsmIdentifier() + " " + object.getClass()); if(object instanceof Relation){ - System.out.println("Processing id " + object.getOsmIdentifier() + " " + object.getClass()); return processRelation(object); } + //process way -> line, edge, area return processWay(object); } @@ -106,49 +107,44 @@ private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject o } private Optional processRelation(AtlasObject object) { + if(2021031 == object.getOsmIdentifier()){ + System.out.println(2021031 + " found"); + } + if(2332348 == object.getOsmIdentifier()){ + System.out.println(2332348 + " found"); + } + if(2022068 == object.getOsmIdentifier()){ + System.out.println(2022068 + " found"); + } + if(2075811 == object.getOsmIdentifier()){ + System.out.println(2075811 + " found"); + } + if(2212273 == object.getOsmIdentifier()){ + System.out.println(2212273 + " found"); + } + if(2332402 == object.getOsmIdentifier()){ + System.out.println(2332402 + " found"); + } Map tagToRelation = getRelationMap(object); - RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, getLineItems((Relation) object)); + RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, getBoundaryParts((Relation) object)); Set instructions = new HashSet<>(); Set objectsToFlag = new HashSet<>(); Set matchedTags = new HashSet<>(); - for(LineItem currentLineItem : relationBoundary.getLineItems()){ + for(BoundaryPart currentBoundaryPart : relationBoundary.getBoundaryParts()){ //getIntersections - Iterable intersections = object.getAtlas().lineItemsIntersecting(currentLineItem.bounds(), - this.getPredicateForLineItemsSelection(relationBoundary.getLineItems(), currentLineItem, relationBoundary.getTagToRelation().keySet())); + //getLineItems + //getAreas + Iterable lineItemsIntersecting = object.getAtlas().lineItemsIntersecting(currentBoundaryPart.getBounds(), + this.getPredicateForLineItemsSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); + Iterable areasIntersecting = object.getAtlas().areasIntersecting(currentBoundaryPart.getBounds(), + this.getPredicateForAreaSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); Set currentMatchedTags = new HashSet<>(); //get boundaries for relation of each intersecting line - intersections.forEach(lineItem -> { - Set matchingBoundaries = getBoundaries(lineItem) - .stream() - .filter(boundary -> relationBoundary.getTagToRelation().keySet().contains(boundary.getTag(BOUNDARY).get())) - .collect(Collectors.toSet()); - //update globally - if(!matchingBoundaries.isEmpty()) { - currentMatchedTags.addAll(matchingBoundaries - .stream() - .map(relation -> relation.getTag(BOUNDARY)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet())); - objectsToFlag.addAll(matchingBoundaries); - objectsToFlag.add(currentLineItem); + processLineItems(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, lineItemsIntersecting, currentMatchedTags); + processAreas(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, areasIntersecting, currentMatchedTags); - List lineItems = getLineItems(lineItem); - lineItems.forEach(line -> { - objectsToFlag.add(line); - final Set intersectingPoints = this.getIntersectingPoints(currentLineItem, - line); - String firstBoundaries = objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); - String secondBoundaries = objectsToString(matchingBoundaries); - if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) { - addInstruction(instructions, currentLineItem, line, intersectingPoints, firstBoundaries, secondBoundaries); - } - }); - } - matchedTags.addAll(currentMatchedTags); - }); - - objectsToFlag.addAll(relationBoundary.getRelationsByBoundaryTags(matchedTags)); + //TODO ? + objectsToFlag.addAll(relationBoundary.getRelationsByBoundaryTags(matchedTags)); //createFlagRecord } //update flag with stored results @@ -160,17 +156,93 @@ private Optional processRelation(AtlasObject object) { CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); instructions.forEach(checkFlag::addInstruction); checkFlag.addObjects(objectsToFlag); + System.out.println(checkFlag.getInstructions()); return Optional.of(checkFlag); } } - private void addInstruction(Set instructions, LineItem lineItem, LineItem line, Set intersectingPoints, String firstBoundaries, String secondBoundaries) { + private void processAreas(RelationBoundary relationBoundary, Set instructions, Set objectsToFlag, Set matchedTags, BoundaryPart currentBoundaryPart, Iterable areasIntersecting, Set currentMatchedTags) { + areasIntersecting.forEach(area -> { + //TODO + Set matchingBoundaries = getBoundaries(area) + .stream() + .filter(boundary -> relationBoundary.getTagToRelation().keySet().contains(boundary.getTag(BOUNDARY).get())) + .collect(Collectors.toSet()); + //update globally + if(!matchingBoundaries.isEmpty()) { + currentMatchedTags.addAll(matchingBoundaries + .stream() + .map(relation -> relation.getTag(BOUNDARY)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet())); + objectsToFlag.addAll(matchingBoundaries); +// objectsToFlag.add(currentLineItem); + +// objectsToFlag.add(area); + final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), + area.toWkt()); + String firstBoundaries = objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); + String secondBoundaries = objectsToString(matchingBoundaries); + if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) { + addInstruction(instructions, currentBoundaryPart, area, intersectingPoints, firstBoundaries, secondBoundaries); + } + + } + matchedTags.addAll(currentMatchedTags); + }); + } + + private void processLineItems(RelationBoundary relationBoundary, Set instructions, Set objectsToFlag, Set matchedTags, BoundaryPart currentBoundaryPart, Iterable lineItemsIntersecting, Set currentMatchedTags) { + lineItemsIntersecting.forEach(lineItem -> { + Set matchingBoundaries = getBoundaries(lineItem) + .stream() + .filter(boundary -> relationBoundary.getTagToRelation().keySet().contains(boundary.getTag(BOUNDARY).get())) + .collect(Collectors.toSet()); + //update globally + if(!matchingBoundaries.isEmpty()) { + currentMatchedTags.addAll(matchingBoundaries + .stream() + .map(relation -> relation.getTag(BOUNDARY)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet())); + objectsToFlag.addAll(matchingBoundaries); +// objectsToFlag.add(currentLineItem); + + List lineItems = getLineItems(lineItem); + lineItems.forEach(line -> { + objectsToFlag.add(line); + final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), + line.toWkt()); + String firstBoundaries = objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); + String secondBoundaries = objectsToString(matchingBoundaries); + if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) { + addInstruction(instructions, currentBoundaryPart, line, intersectingPoints, firstBoundaries, secondBoundaries); + } + }); + } + matchedTags.addAll(currentMatchedTags); + }); + } + + private void addInstruction(Set instructions, BoundaryPart lineItem, LineItem line, Coordinate[] intersectingPoints, String firstBoundaries, String secondBoundaries) { final String instruction = this.getLocalizedInstruction(INDEX, firstBoundaries, Long.toString(lineItem.getOsmIdentifier()), secondBoundaries, Long.toString(line.getOsmIdentifier()), - this.locationsToList(intersectingPoints)); + this.coordinatesToList(intersectingPoints)); + instructions.add(instruction); + } + + private void addInstruction(Set instructions, BoundaryPart lineItem, Area area, Coordinate[] intersectingPoints, String firstBoundaries, String secondBoundaries) { + final String instruction = this.getLocalizedInstruction(INDEX, + firstBoundaries, + Long.toString(lineItem.getOsmIdentifier()), + secondBoundaries, + Long.toString(area.getOsmIdentifier()), + this.coordinatesToList(intersectingPoints)); instructions.add(instruction); } @@ -203,26 +275,53 @@ private Optional processWay(AtlasObject object) { return Optional.empty(); } - private Set getLineItems(Relation relation){ - final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE); - relationMemberLineItems.addAll(relation.membersOfType(ItemType.LINE)); - final Set lineItems = BoundaryIntersectionCheck - .getLineItems(relationMemberLineItems); - - Set lineItemsExpanded = new HashSet<>(); - Set> iterators = lineItems - .stream() - .map(lineItem -> { - if (lineItem instanceof MultiLine) { - return ((MultiLine) lineItem).getSubLines().iterator(); - } - return Arrays.asList(lineItem).iterator(); + private Set getBoundaryParts(Relation relation){ + //TODO??!! + // relation.toWkt() + final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE, ItemType.LINE, ItemType.AREA); + return relationMemberLineItems + .stream().map(RelationMember::getEntity) + .map(entity -> { + String tag = entity.getTags().get(BOUNDARY); + Set boundaryTags = entity.relations() + .stream() + .filter(currentRelation -> BOUNDARY.equals(currentRelation.getTag(TYPE))) + .map(currentRelation -> currentRelation.getTag(BOUNDARY).orElse("")) + .collect(Collectors.toSet()); + boundaryTags.add(tag); + boundaryTags.remove(""); + return new BoundaryPart(entity.getOsmIdentifier(), + entity.bounds(), entity.toWkt(), boundaryTags); }) .collect(Collectors.toSet()); - iterators.forEach(iterator -> iterator.forEachRemaining(lineItemsExpanded::add)); - return lineItemsExpanded; + // final Set lineItems = BoundaryIntersectionCheck +// .getLineItems(relationMemberLineItems); + +// if(relation instanceof MultiRelation && lineItems.isEmpty()){ +// lineItems.addAll(getLineItemsFromMultiRelation((MultiRelation) relation)); +// } + +// Set lineItemsExpanded = new HashSet<>(); +// Set> iterators = lineItems +// .stream() +// .map(lineItem -> { +// if (lineItem instanceof MultiLine) { +// return ((MultiLine) lineItem).getSubLines().iterator(); +// } +// return Arrays.asList(lineItem).iterator(); +// }) +// .collect(Collectors.toSet()); +// iterators.forEach(iterator -> iterator.forEachRemaining(lineItemsExpanded::add)); +// return lineItemsExpanded; +// return lineItems; + } + + private Collection getLineItemsFromMultiRelation(MultiRelation relation) { + return relation.relations().stream() + .flatMap(subRelation -> BoundaryIntersectionCheck.getLineItems(subRelation.membersOfType(ItemType.LINE, ItemType.EDGE)).stream()) + .collect(Collectors.toSet()); } - + @Override protected List getFallbackInstructions() @@ -242,21 +341,76 @@ private Set getBoundaries(final LineItem currentLineItem) .collect(Collectors.toSet()); } + private Set getBoundaries(final Area area) + { + Set relations = area.relations().stream() + .filter(relation -> relation instanceof MultiRelation) + .map(relation -> ((MultiRelation) relation).relations()) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + relations.addAll(area.relations()); + return relations.stream().filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) + .collect(Collectors.toSet()); + } + private Set getIntersectingPoints(final LineItem lineItem, final LineItem secondLineItem) { return lineItem.asPolyLine() .intersections(secondLineItem.asPolyLine()); } + + private Coordinate[] getIntersectionPoints(final String wktFirst, + final String wktSecond) + { + final WKTReader wktReader = new WKTReader(); + try + { + final Geometry line1 = wktReader.read(wktFirst); + final Geometry line2 = wktReader.read(wktSecond); + return line1.intersection(line2).getCoordinates(); + } + catch (final ParseException e) + { + //TODO ? +// return false; + throw new IllegalStateException(e); + } + } - private Predicate getPredicateForLineItemsSelection(final Set lineItems, - final LineItem currentLineItem, Set boundaryTags) + //TODO old +// private Predicate getPredicateForLineItemsSelection_old(final Set lineItems, +// final LineItem currentLineItem, Set boundaryTags) +// { +// return lineItemToCheck -> +// { +// if (checkLineItemAsBoundary(lineItemToCheck, boundaryTags) && !lineItems.contains(lineItemToCheck)) +// { +// return this.isCrossingNotTouching(currentLineItem, lineItemToCheck); +// } +// return false; +// }; +// } + + private Predicate getPredicateForLineItemsSelection(final BoundaryPart boundaryPart, final Set boundaryTags) { return lineItemToCheck -> { - if (checkLineItemAsBoundary(lineItemToCheck, boundaryTags) && !lineItems.contains(lineItemToCheck)) + if (checkLineItemAsBoundary(lineItemToCheck, boundaryTags)) + { + return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), lineItemToCheck.toWkt()); + } + return false; + }; + } + + private Predicate getPredicateForAreaSelection(final BoundaryPart boundaryPart, final Set boundaryTags) + { + return areaToCheck -> + { + if (checkAreaAsBoundary(areaToCheck, boundaryTags)) { - return this.isCrossingNotTouching(currentLineItem, lineItemToCheck); + return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), areaToCheck.toWkt()); } return false; }; @@ -267,18 +421,28 @@ private boolean checkLineItemAsBoundary(LineItem lineItem, Set boundaryT .relations().stream() .anyMatch(relationToCheck -> BoundaryIntersectionCheck .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) - && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())); + && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())) + || boundaryTags.contains(lineItem.getTag(BOUNDARY).orElse("")); + } + + private boolean checkAreaAsBoundary(Area area, Set boundaryTags){ + return area + .relations().stream() + .anyMatch(relationToCheck -> BoundaryIntersectionCheck + .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) + && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())) + || boundaryTags.contains(area.getTag(BOUNDARY).orElse("")); } - private boolean isCrossingNotTouching(final LineItem currentLineItem, - final LineItem lineItemToCheck) + private boolean isCrossingNotTouching(final String wktFirst, + final String wktSecond) { final WKTReader wktReader = new WKTReader(); try { - final Geometry line1 = wktReader.read(lineItemToCheck.asPolyLine().toWkt()); - final Geometry line2 = wktReader.read(currentLineItem.asPolyLine().toWkt()); - return line1.crosses(line2) && !line1.touches(line2); + final Geometry line1 = wktReader.read(wktFirst); + final Geometry line2 = wktReader.read(wktSecond); + return line1.intersects(line2) && !line1.touches(line2); } catch (final ParseException e) { @@ -286,10 +450,11 @@ private boolean isCrossingNotTouching(final LineItem currentLineItem, } } - private String locationsToList(final Set locations) + private String coordinatesToList(final Coordinate[] locations) { - return locations.stream().map(location -> String.format("(%s, %s)", location.getLatitude(), - location.getLongitude())).collect(Collectors.joining(DELIMITER)); + return Stream.of(locations) + .map(coordinate -> String.format("(%s, %s)", coordinate.getX(), coordinate.getY())) + .collect(Collectors.joining(DELIMITER)); } private String objectsToString(final Set objects) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java new file mode 100644 index 000000000..c55e8e925 --- /dev/null +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java @@ -0,0 +1,41 @@ +package org.openstreetmap.atlas.checks.validation.intersections; + +import org.openstreetmap.atlas.geography.Rectangle; +import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; + +import java.util.List; +import java.util.Set; + + +public class BoundaryPart { + + private final Rectangle bounds; + private final long osmIdentifier; + private final String wktGeometry; + private final Set boundaryTags; + //TODO? +// private final Set atlasObjects; + + public BoundaryPart(long osmIdentifier, Rectangle bounds, String wktGeometry, Set boundaryTags) { + this.osmIdentifier = osmIdentifier; + this.bounds = bounds; + this.wktGeometry = wktGeometry; + this.boundaryTags = boundaryTags; + } + + public Rectangle getBounds() { + return bounds; + } + + public long getOsmIdentifier() { + return osmIdentifier; + } + + public String getWktGeometry() { + return wktGeometry; + } + + public Set getBoundaryTags() { + return boundaryTags; + } +} diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java index 3a83a1224..d5a3704e4 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java @@ -1,8 +1,10 @@ package org.openstreetmap.atlas.checks.validation.intersections; +import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; import org.openstreetmap.atlas.geography.atlas.items.LineItem; import org.openstreetmap.atlas.geography.atlas.items.Relation; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -10,19 +12,22 @@ public class RelationBoundary { private final Map tagToRelation; - private final Set lineItems; + private final Set boundaryParts; +// private final Set boundaryObjects; - public RelationBoundary(Map tagToRelation, Set lineItems) { + public RelationBoundary(Map tagToRelation, Set boundaryParts) { this.tagToRelation = tagToRelation; - this.lineItems = lineItems; + this.boundaryParts = boundaryParts; +// this.boundaryObjects = boundaryParts.stream() +// .map(boundaryPart -> boundaryPart.get) } public Map getTagToRelation() { return tagToRelation; } - public Set getLineItems() { - return lineItems; + public Set getBoundaryParts() { + return boundaryParts; } public Set getRelationsByBoundaryTags(Set tags){ From f7c0dd68cdbd10508c297dd83276c6c7a57e6c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Tue, 1 Dec 2020 20:48:38 +0100 Subject: [PATCH 27/36] Intersection and touching handling fixed to work for all combinations of area and line. Checkstyle fixed. --- .../BoundaryIntersectionCheck.java | 356 +++++++----------- 1 file changed, 137 insertions(+), 219 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 5145dda84..3cf41a228 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -1,13 +1,19 @@ package org.openstreetmap.atlas.checks.validation.intersections; +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.lang.StringUtils; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.WKTReader; import org.openstreetmap.atlas.checks.base.BaseCheck; import org.openstreetmap.atlas.checks.flag.CheckFlag; -import org.openstreetmap.atlas.geography.Location; import org.openstreetmap.atlas.geography.atlas.items.Area; +import org.openstreetmap.atlas.geography.atlas.items.AtlasEntity; import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; import org.openstreetmap.atlas.geography.atlas.items.ItemType; import org.openstreetmap.atlas.geography.atlas.items.LineItem; @@ -21,155 +27,100 @@ import org.openstreetmap.atlas.tags.annotations.validation.Validators; import org.openstreetmap.atlas.utilities.configuration.Configuration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - /** * @author srachanski */ public class BoundaryIntersectionCheck extends BaseCheck { + public static final String DELIMITER = ", "; + public static final int INDEX = 0; + public static final String TYPE = "type"; + public static final String BOUNDARY = "boundary"; private static final String INVALID_BOUNDARY_FORMAT = "Boundaries {0} with way {1} is crossing invalidly with boundaries {2} with way {3} at coordinates {4}."; private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, INVALID_BOUNDARY_FORMAT); - public static final String DELIMITER = ", "; - public static final int INDEX = 0; - public static final String TYPE = "type"; - public static final String BOUNDARY = "boundary"; - public static final String EMPTY = ""; - -// private static final Predicate LINE_ITEM_WITH_BOUNDARY_TAGS = lineItem -> BOUNDARY -// .equals(lineItem.getTag(TYPE).orElse(EMPTY)) && lineItem.getTag(BOUNDARY).isPresent(); - private static final Predicate LINE_ITEM_AS_BOUNDARY = lineItem -> lineItem - .relations().stream() - .anyMatch(relationToCheck -> BoundaryIntersectionCheck - .isRelationTypeBoundaryWithBoundaryTag(relationToCheck)); -// || LINE_ITEM_WITH_BOUNDARY_TAGS.test(lineItem)); - private static LineItem castToLineItem(final RelationMember relationMember) + public BoundaryIntersectionCheck(final Configuration configuration) { - return (LineItem) relationMember.getEntity(); + super(configuration); } - private static Set getLineItems(final RelationMemberList relationMembers) - { - return relationMembers.stream() - .map(BoundaryIntersectionCheck::castToLineItem) - .collect(Collectors.toSet()); - } - private static boolean isObjectOfBoundaryTypeWithBoundaryTag(final AtlasObject object) { return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && Validators.hasValuesFor(object, BoundaryTag.class); } - public BoundaryIntersectionCheck(final Configuration configuration) + private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) { - super(configuration); + return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) + && Validators.hasValuesFor(object, BoundaryTag.class); } @Override public boolean validCheckForObject(final AtlasObject object) { - return (object instanceof Relation || object instanceof LineItem) && - isObjectOfBoundaryTypeWithBoundaryTag(object); + return object instanceof Relation && isObjectOfBoundaryTypeWithBoundaryTag(object); } @Override protected Optional flag(final AtlasObject object) { - if(object instanceof Relation){ - return processRelation(object); - } - //process way -> line, edge, area - return processWay(object); + return this.processRelation(object); } - - private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) + + private Optional processRelation(final AtlasObject object) { - return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) - && Validators.hasValuesFor(object, BoundaryTag.class); - } - - private Optional processRelation(AtlasObject object) { - if(2021031 == object.getOsmIdentifier()){ - System.out.println(2021031 + " found"); - } - if(2332348 == object.getOsmIdentifier()){ - System.out.println(2332348 + " found"); - } - if(2022068 == object.getOsmIdentifier()){ - System.out.println(2022068 + " found"); - } - if(2075811 == object.getOsmIdentifier()){ - System.out.println(2075811 + " found"); - } - if(2212273 == object.getOsmIdentifier()){ - System.out.println(2212273 + " found"); - } - if(2332402 == object.getOsmIdentifier()){ - System.out.println(2332402 + " found"); - } - Map tagToRelation = getRelationMap(object); - RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, getBoundaryParts((Relation) object)); - Set instructions = new HashSet<>(); - Set objectsToFlag = new HashSet<>(); - Set matchedTags = new HashSet<>(); - for(BoundaryPart currentBoundaryPart : relationBoundary.getBoundaryParts()){ - //getIntersections - //getLineItems - //getAreas - Iterable lineItemsIntersecting = object.getAtlas().lineItemsIntersecting(currentBoundaryPart.getBounds(), + final Map tagToRelation = this.getRelationMap(object); + final RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, this.getBoundaryParts((Relation) object)); + final Set instructions = new HashSet<>(); + final Set objectsToFlag = new HashSet<>(); + final Set matchedTags = new HashSet<>(); + for(final BoundaryPart currentBoundaryPart : relationBoundary.getBoundaryParts()) + { + final Iterable lineItemsIntersecting = object.getAtlas().lineItemsIntersecting(currentBoundaryPart.getBounds(), this.getPredicateForLineItemsSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); - Iterable areasIntersecting = object.getAtlas().areasIntersecting(currentBoundaryPart.getBounds(), + final Iterable areasIntersecting = object.getAtlas().areasIntersecting(currentBoundaryPart.getBounds(), this.getPredicateForAreaSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); - Set currentMatchedTags = new HashSet<>(); - //get boundaries for relation of each intersecting line - processLineItems(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, lineItemsIntersecting, currentMatchedTags); - processAreas(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, areasIntersecting, currentMatchedTags); - - //TODO ? + final Set currentMatchedTags = new HashSet<>(); + this.processLineItems(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, lineItemsIntersecting, currentMatchedTags); + this.processAreas(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, areasIntersecting, currentMatchedTags); + objectsToFlag.addAll(relationBoundary.getRelationsByBoundaryTags(matchedTags)); - //createFlagRecord } - //update flag with stored results if(instructions.isEmpty()) { return Optional.empty(); - } else + } + else { - CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); + final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); instructions.forEach(checkFlag::addInstruction); checkFlag.addObjects(objectsToFlag); - System.out.println(checkFlag.getInstructions()); return Optional.of(checkFlag); } } - - private void processAreas(RelationBoundary relationBoundary, Set instructions, Set objectsToFlag, Set matchedTags, BoundaryPart currentBoundaryPart, Iterable areasIntersecting, Set currentMatchedTags) { - areasIntersecting.forEach(area -> { - //TODO - Set matchingBoundaries = getBoundaries(area) + + private void processAreas(final RelationBoundary relationBoundary, + final Set instructions, + final Set objectsToFlag, + final Set matchedTags, + final BoundaryPart currentBoundaryPart, + final Iterable areasIntersecting, + final Set currentMatchedTags) + { + areasIntersecting.forEach(area -> + { + final Set matchingBoundaries = this.getBoundaries(area) .stream() - .filter(boundary -> relationBoundary.getTagToRelation().keySet().contains(boundary.getTag(BOUNDARY).get())) + .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).orElse(StringUtils.EMPTY))) .collect(Collectors.toSet()); - //update globally - if(!matchingBoundaries.isEmpty()) { + if(!matchingBoundaries.isEmpty()) + { currentMatchedTags.addAll(matchingBoundaries .stream() .map(relation -> relation.getTag(BOUNDARY)) @@ -177,30 +128,35 @@ private void processAreas(RelationBoundary relationBoundary, Set instruc .map(Optional::get) .collect(Collectors.toSet())); objectsToFlag.addAll(matchingBoundaries); -// objectsToFlag.add(currentLineItem); - -// objectsToFlag.add(area); final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), area.toWkt()); - String firstBoundaries = objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); - String secondBoundaries = objectsToString(matchingBoundaries); - if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) { - addInstruction(instructions, currentBoundaryPart, area, intersectingPoints, firstBoundaries, secondBoundaries); + final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); + final String secondBoundaries = this.objectsToString(matchingBoundaries); + if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) + { + this.addInstruction(instructions, currentBoundaryPart, area, intersectingPoints, firstBoundaries, secondBoundaries); } - } matchedTags.addAll(currentMatchedTags); }); } - - private void processLineItems(RelationBoundary relationBoundary, Set instructions, Set objectsToFlag, Set matchedTags, BoundaryPart currentBoundaryPart, Iterable lineItemsIntersecting, Set currentMatchedTags) { - lineItemsIntersecting.forEach(lineItem -> { - Set matchingBoundaries = getBoundaries(lineItem) + + private void processLineItems(final RelationBoundary relationBoundary, + final Set instructions, + final Set objectsToFlag, + final Set matchedTags, + final BoundaryPart currentBoundaryPart, + final Iterable lineItemsIntersecting, + final Set currentMatchedTags) + { + lineItemsIntersecting.forEach(lineItem -> + { + final Set matchingBoundaries = this.getBoundaries(lineItem) .stream() - .filter(boundary -> relationBoundary.getTagToRelation().keySet().contains(boundary.getTag(BOUNDARY).get())) + .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).get())) .collect(Collectors.toSet()); - //update globally - if(!matchingBoundaries.isEmpty()) { + if(!matchingBoundaries.isEmpty()) + { currentMatchedTags.addAll(matchingBoundaries .stream() .map(relation -> relation.getTag(BOUNDARY)) @@ -208,25 +164,32 @@ private void processLineItems(RelationBoundary relationBoundary, Set ins .map(Optional::get) .collect(Collectors.toSet())); objectsToFlag.addAll(matchingBoundaries); -// objectsToFlag.add(currentLineItem); - - List lineItems = getLineItems(lineItem); - lineItems.forEach(line -> { + + final List lineItems = this.getLineItems(lineItem); + lineItems.forEach(line -> + { objectsToFlag.add(line); final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), line.toWkt()); - String firstBoundaries = objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); - String secondBoundaries = objectsToString(matchingBoundaries); - if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) { - addInstruction(instructions, currentBoundaryPart, line, intersectingPoints, firstBoundaries, secondBoundaries); + final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); + final String secondBoundaries = this.objectsToString(matchingBoundaries); + if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) + { + this.addInstruction(instructions, currentBoundaryPart, line, intersectingPoints, firstBoundaries, secondBoundaries); } }); } matchedTags.addAll(currentMatchedTags); }); } - - private void addInstruction(Set instructions, BoundaryPart lineItem, LineItem line, Coordinate[] intersectingPoints, String firstBoundaries, String secondBoundaries) { + + private void addInstruction(final Set instructions, + final BoundaryPart lineItem, + final LineItem line, + final Coordinate[] intersectingPoints, + final String firstBoundaries, + final String secondBoundaries) + { final String instruction = this.getLocalizedInstruction(INDEX, firstBoundaries, Long.toString(lineItem.getOsmIdentifier()), @@ -235,8 +198,14 @@ private void addInstruction(Set instructions, BoundaryPart lineItem, Lin this.coordinatesToList(intersectingPoints)); instructions.add(instruction); } - - private void addInstruction(Set instructions, BoundaryPart lineItem, Area area, Coordinate[] intersectingPoints, String firstBoundaries, String secondBoundaries) { + + private void addInstruction(final Set instructions, + final BoundaryPart lineItem, + final Area area, + final Coordinate[] intersectingPoints, + final String firstBoundaries, + final String secondBoundaries) + { final String instruction = this.getLocalizedInstruction(INDEX, firstBoundaries, Long.toString(lineItem.getOsmIdentifier()), @@ -245,10 +214,12 @@ private void addInstruction(Set instructions, BoundaryPart lineItem, Are this.coordinatesToList(intersectingPoints)); instructions.add(instruction); } - - private Map getRelationMap(AtlasObject object) { - Map tagToRelation = new HashMap<>(); - if(object instanceof MultiRelation){ + + private Map getRelationMap(final AtlasObject object) + { + final Map tagToRelation = new HashMap<>(); + if(object instanceof MultiRelation) + { ((MultiRelation) object).relations() .stream() .filter(BoundaryIntersectionCheck::isObjectOfBoundaryTypeWithBoundaryTag) @@ -257,72 +228,40 @@ private Map getRelationMap(AtlasObject object) { tagToRelation.put(object.getTag(BOUNDARY).get(), (Relation) object); return tagToRelation; } - - private List getLineItems(LineItem lineItem) { + + private List getLineItems(final LineItem lineItem) + { if(lineItem instanceof MultiLine) { - List lines = new ArrayList<>(); + final List lines = new ArrayList<>(); ((MultiLine) lineItem).getSubLines() .forEach(lines::add); return lines; } - return Arrays.asList(lineItem); - } - - - private Optional processWay(AtlasObject object) { - //TODO to be implemented - return Optional.empty(); + return Collections.singletonList(lineItem); } - - private Set getBoundaryParts(Relation relation){ - //TODO??!! - // relation.toWkt() + + private Set getBoundaryParts(final Relation relation) + { final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE, ItemType.LINE, ItemType.AREA); return relationMemberLineItems .stream().map(RelationMember::getEntity) - .map(entity -> { - String tag = entity.getTags().get(BOUNDARY); - Set boundaryTags = entity.relations() + .map(entity -> + { + final String tag = entity.getTags().get(BOUNDARY); + final Set boundaryTags = entity.relations() .stream() - .filter(currentRelation -> BOUNDARY.equals(currentRelation.getTag(TYPE))) - .map(currentRelation -> currentRelation.getTag(BOUNDARY).orElse("")) + .filter(currentRelation -> BOUNDARY.equals(currentRelation.getTag(TYPE).get())) + .map(currentRelation -> currentRelation.getTag(BOUNDARY).orElse(StringUtils.EMPTY)) .collect(Collectors.toSet()); boundaryTags.add(tag); - boundaryTags.remove(""); + boundaryTags.remove(StringUtils.EMPTY); return new BoundaryPart(entity.getOsmIdentifier(), entity.bounds(), entity.toWkt(), boundaryTags); }) .collect(Collectors.toSet()); - // final Set lineItems = BoundaryIntersectionCheck -// .getLineItems(relationMemberLineItems); - -// if(relation instanceof MultiRelation && lineItems.isEmpty()){ -// lineItems.addAll(getLineItemsFromMultiRelation((MultiRelation) relation)); -// } - -// Set lineItemsExpanded = new HashSet<>(); -// Set> iterators = lineItems -// .stream() -// .map(lineItem -> { -// if (lineItem instanceof MultiLine) { -// return ((MultiLine) lineItem).getSubLines().iterator(); -// } -// return Arrays.asList(lineItem).iterator(); -// }) -// .collect(Collectors.toSet()); -// iterators.forEach(iterator -> iterator.forEachRemaining(lineItemsExpanded::add)); -// return lineItemsExpanded; -// return lineItems; - } - - private Collection getLineItemsFromMultiRelation(MultiRelation relation) { - return relation.relations().stream() - .flatMap(subRelation -> BoundaryIntersectionCheck.getLineItems(subRelation.membersOfType(ItemType.LINE, ItemType.EDGE)).stream()) - .collect(Collectors.toSet()); } - - + @Override protected List getFallbackInstructions() { @@ -331,35 +270,28 @@ protected List getFallbackInstructions() private Set getBoundaries(final LineItem currentLineItem) { - Set relations = currentLineItem.relations().stream() + final Set relations = currentLineItem.relations().stream() .filter(relation -> relation instanceof MultiRelation) - .map(relation -> ((MultiRelation) relation).relations()) + .map(AtlasEntity::relations) .flatMap(Collection::stream) .collect(Collectors.toSet()); relations.addAll(currentLineItem.relations()); return relations.stream().filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) .collect(Collectors.toSet()); } - + private Set getBoundaries(final Area area) { - Set relations = area.relations().stream() + final Set relations = area.relations().stream() .filter(relation -> relation instanceof MultiRelation) - .map(relation -> ((MultiRelation) relation).relations()) + .map(AtlasEntity::relations) .flatMap(Collection::stream) .collect(Collectors.toSet()); relations.addAll(area.relations()); return relations.stream().filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) .collect(Collectors.toSet()); } - - private Set getIntersectingPoints(final LineItem lineItem, - final LineItem secondLineItem) - { - return lineItem.asPolyLine() - .intersections(secondLineItem.asPolyLine()); - } - + private Coordinate[] getIntersectionPoints(final String wktFirst, final String wktSecond) { @@ -372,51 +304,36 @@ private Coordinate[] getIntersectionPoints(final String wktFirst, } catch (final ParseException e) { - //TODO ? -// return false; throw new IllegalStateException(e); } } - //TODO old -// private Predicate getPredicateForLineItemsSelection_old(final Set lineItems, -// final LineItem currentLineItem, Set boundaryTags) -// { -// return lineItemToCheck -> -// { -// if (checkLineItemAsBoundary(lineItemToCheck, boundaryTags) && !lineItems.contains(lineItemToCheck)) -// { -// return this.isCrossingNotTouching(currentLineItem, lineItemToCheck); -// } -// return false; -// }; -// } - private Predicate getPredicateForLineItemsSelection(final BoundaryPart boundaryPart, final Set boundaryTags) { return lineItemToCheck -> { - if (checkLineItemAsBoundary(lineItemToCheck, boundaryTags)) + if (this.checkLineItemAsBoundary(lineItemToCheck, boundaryTags)) { return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), lineItemToCheck.toWkt()); } return false; }; } - + private Predicate getPredicateForAreaSelection(final BoundaryPart boundaryPart, final Set boundaryTags) { return areaToCheck -> { - if (checkAreaAsBoundary(areaToCheck, boundaryTags)) + if (this.checkAreaAsBoundary(areaToCheck, boundaryTags)) { return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), areaToCheck.toWkt()); } return false; }; } - - private boolean checkLineItemAsBoundary(LineItem lineItem, Set boundaryTags){ + + private boolean checkLineItemAsBoundary(final LineItem lineItem, final Set boundaryTags) + { return lineItem .relations().stream() .anyMatch(relationToCheck -> BoundaryIntersectionCheck @@ -424,8 +341,9 @@ private boolean checkLineItemAsBoundary(LineItem lineItem, Set boundaryT && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())) || boundaryTags.contains(lineItem.getTag(BOUNDARY).orElse("")); } - - private boolean checkAreaAsBoundary(Area area, Set boundaryTags){ + + private boolean checkAreaAsBoundary(final Area area, final Set boundaryTags) + { return area .relations().stream() .anyMatch(relationToCheck -> BoundaryIntersectionCheck @@ -440,9 +358,9 @@ private boolean isCrossingNotTouching(final String wktFirst, final WKTReader wktReader = new WKTReader(); try { - final Geometry line1 = wktReader.read(wktFirst); - final Geometry line2 = wktReader.read(wktSecond); - return line1.intersects(line2) && !line1.touches(line2); + final Geometry geometry1 = wktReader.read(wktFirst); + final Geometry geometry2 = wktReader.read(wktSecond); + return geometry1.intersects(geometry2) && !(geometry1.within(geometry2) || geometry1.contains(geometry2)); } catch (final ParseException e) { @@ -456,7 +374,7 @@ private String coordinatesToList(final Coordinate[] locations) .map(coordinate -> String.format("(%s, %s)", coordinate.getX(), coordinate.getY())) .collect(Collectors.joining(DELIMITER)); } - + private String objectsToString(final Set objects) { return objects From 86741f00845a9c32f079999dab150702438dba0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 2 Dec 2020 18:34:38 +0100 Subject: [PATCH 28/36] Intersection and touching handling fixed to work for all combinations of area and line. --- .../BoundaryIntersectionCheck.java | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 3cf41a228..5c42cc9a7 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -1,6 +1,15 @@ package org.openstreetmap.atlas.checks.validation.intersections; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -360,12 +369,36 @@ private boolean isCrossingNotTouching(final String wktFirst, { final Geometry geometry1 = wktReader.read(wktFirst); final Geometry geometry2 = wktReader.read(wktSecond); - return geometry1.intersects(geometry2) && !(geometry1.within(geometry2) || geometry1.contains(geometry2)); + if(geometry1.intersects(geometry2)) + { + if(this.isAnyGeometryLineString(geometry1, geometry2)) + { + return this.isLineIntersectionNotTouch(geometry1, geometry2); + } + return this.isAreaIntersectionNotTouch(geometry1, geometry2); + } } catch (final ParseException e) { return false; } + return false; + } + + private boolean isAnyGeometryLineString(final Geometry lineString, final Geometry lineString2) + { + return lineString.getGeometryType().equals("LineString") && lineString2.getGeometryType().equals("LineString"); + } + + private boolean isLineIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) + { + return !geometry1.overlaps(geometry2); + } + + private boolean isAreaIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) + { + return (!geometry1.covers(geometry2) || !geometry2.coveredBy(geometry1)) && + (!geometry2.covers(geometry1) || !geometry1.coveredBy(geometry2)); } private String coordinatesToList(final Coordinate[] locations) From bb3d84de73ebb21eb11def6afd1ccd66107532a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 9 Dec 2020 10:30:42 +0100 Subject: [PATCH 29/36] All three cases of areas intersection are handled. There is still a problem when incorrect geometry is entered. --- .../BoundaryIntersectionCheck.java | 56 +++++++++++--- .../intersections/UnwalkableWaysCheck.java | 4 +- .../BoundaryIntersectionCheckTest.java | 75 +++++++++++++++++++ 3 files changed, 123 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 5c42cc9a7..90e40c8f1 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -84,6 +84,12 @@ protected Optional flag(final AtlasObject object) private Optional processRelation(final AtlasObject object) { + if(object.getOsmIdentifier() == 2327223){ + System.out.println("2327223 FOUND"); + } + if(object.getOsmIdentifier() == 3890254){ + System.out.println("3890254 FOUND"); + } final Map tagToRelation = this.getRelationMap(object); final RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, this.getBoundaryParts((Relation) object)); final Set instructions = new HashSet<>(); @@ -91,6 +97,12 @@ private Optional processRelation(final AtlasObject object) final Set matchedTags = new HashSet<>(); for(final BoundaryPart currentBoundaryPart : relationBoundary.getBoundaryParts()) { +// if(currentBoundaryPart.getOsmIdentifier() == 2327223){ +// System.out.println("2327223 FOUND"); +// } +// if(currentBoundaryPart.getOsmIdentifier() == 3890254){ +// System.out.println("3890254 FOUND"); +// } final Iterable lineItemsIntersecting = object.getAtlas().lineItemsIntersecting(currentBoundaryPart.getBounds(), this.getPredicateForLineItemsSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); final Iterable areasIntersecting = object.getAtlas().areasIntersecting(currentBoundaryPart.getBounds(), @@ -109,6 +121,8 @@ private Optional processRelation(final AtlasObject object) { final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); instructions.forEach(checkFlag::addInstruction); + //TODO remove +// instructions.forEach(System.out::println); checkFlag.addObjects(objectsToFlag); return Optional.of(checkFlag); } @@ -304,12 +318,11 @@ private Set getBoundaries(final Area area) private Coordinate[] getIntersectionPoints(final String wktFirst, final String wktSecond) { - final WKTReader wktReader = new WKTReader(); try { - final Geometry line1 = wktReader.read(wktFirst); - final Geometry line2 = wktReader.read(wktSecond); - return line1.intersection(line2).getCoordinates(); + Geometry geometry1 = getGeometryForIntersection(wktFirst); + Geometry geometry2 = getGeometryForIntersection(wktSecond); + return geometry1.intersection(geometry2).getCoordinates(); } catch (final ParseException e) { @@ -317,6 +330,17 @@ private Coordinate[] getIntersectionPoints(final String wktFirst, } } + private Geometry getGeometryForIntersection(String wktFirst) throws ParseException + { + + final WKTReader wktReader = new WKTReader(); + Geometry geometry1 = wktReader.read(wktFirst); + if (geometry1.getGeometryType().equals("Polygon")) { + geometry1 = geometry1.getBoundary(); + } + return geometry1; + } + private Predicate getPredicateForLineItemsSelection(final BoundaryPart boundaryPart, final Set boundaryTags) { return lineItemToCheck -> @@ -331,8 +355,20 @@ private Predicate getPredicateForLineItemsSelection(final BoundaryPart private Predicate getPredicateForAreaSelection(final BoundaryPart boundaryPart, final Set boundaryTags) { +// if(boundaryPart.getOsmIdentifier() == 2327223){ +// System.out.println("2327223 FOUND"); +// } +// if(boundaryPart.getOsmIdentifier() == 3890254){ +// System.out.println("3890254 FOUND"); +// } return areaToCheck -> { +// if(areaToCheck.getOsmIdentifier() == 2327223){ +// System.out.println("2327223 FOUND"); +// } +// if(areaToCheck.getOsmIdentifier() == 3890254){ +// System.out.println("3890254 FOUND"); +// } if (this.checkAreaAsBoundary(areaToCheck, boundaryTags)) { return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), areaToCheck.toWkt()); @@ -361,7 +397,8 @@ private boolean checkAreaAsBoundary(final Area area, final Set boundaryT || boundaryTags.contains(area.getTag(BOUNDARY).orElse("")); } - private boolean isCrossingNotTouching(final String wktFirst, + //TODO change + public boolean isCrossingNotTouching(final String wktFirst, final String wktSecond) { final WKTReader wktReader = new WKTReader(); @@ -371,7 +408,7 @@ private boolean isCrossingNotTouching(final String wktFirst, final Geometry geometry2 = wktReader.read(wktSecond); if(geometry1.intersects(geometry2)) { - if(this.isAnyGeometryLineString(geometry1, geometry2)) + if(!this.isGeometryPairOfLineType(geometry1, geometry2)) { return this.isLineIntersectionNotTouch(geometry1, geometry2); } @@ -385,7 +422,7 @@ private boolean isCrossingNotTouching(final String wktFirst, return false; } - private boolean isAnyGeometryLineString(final Geometry lineString, final Geometry lineString2) + private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) { return lineString.getGeometryType().equals("LineString") && lineString2.getGeometryType().equals("LineString"); } @@ -397,8 +434,9 @@ private boolean isLineIntersectionNotTouch(final Geometry geometry1, final Geome private boolean isAreaIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) { - return (!geometry1.covers(geometry2) || !geometry2.coveredBy(geometry1)) && - (!geometry2.covers(geometry1) || !geometry1.coveredBy(geometry2)); + return !(geometry1.covers(geometry2) || + geometry1.coveredBy(geometry2) || + geometry1.touches(geometry2)); } private String coordinatesToList(final Coordinate[] locations) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/UnwalkableWaysCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/UnwalkableWaysCheck.java index e5d0203fe..7635368f0 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/UnwalkableWaysCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/UnwalkableWaysCheck.java @@ -37,9 +37,7 @@ public class UnwalkableWaysCheck extends BaseCheck private static final Logger logger = LoggerFactory.getLogger(UnwalkableWaysCheck.class); // Instructions private static final List FALLBACK_INSTRUCTIONS = Collections - .singletonList("Way {0,number,#} may be unwalkable and needs verification if safe " - + "pedestrian crossing exists. If it does, it should be marked ‘foot=yes’. If " - + "safe pedestrian crossing does not exist, the Way should be marked ‘foot=no'."); + .singletonList(""); // The minimum highway type considered for potential dual carriageways private static final HighwayTag MINIMUM_HIGHWAY_TYPE_DEFAULT = HighwayTag.PRIMARY; private static final List DEFAULT_WALKWAY_TAGS = Arrays.asList( diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index d0613f528..c9300997c 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -3,6 +3,9 @@ import org.junit.Assert; import org.junit.Rule; import org.junit.Test; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.io.ParseException; +import org.locationtech.jts.io.WKTReader; import org.openstreetmap.atlas.checks.configuration.ConfigurationResolver; import org.openstreetmap.atlas.checks.validation.verifier.ConsumerBasedExpectedCheckVerifier; import org.openstreetmap.atlas.utilities.configuration.Configuration; @@ -55,6 +58,78 @@ public void testInvalidTwoCrossingItemsAtlas() }); } + //TODO remove + @Test + public void test(){ + String area1 = "POLYGON((0 0, 3 0, 3 3, 3 0, 0 0))"; + String area2 = "POLYGON((0 0, 2 0, 2 2, 2 0, 0 0))"; + String area3 = "POLYGON((0 0, 3 1, 4 4, 1 3, 0 0))"; + String line1 = "LINESTRING(1 1, 4 4)"; + String line2 = "LINESTRING(1 4, 4 1)"; + +// BoundaryIntersectionCheck boundaryIntersectionCheck = new BoundaryIntersectionCheck(null); + System.out.println(isCrossingNotTouching(area1, area2)); + System.out.println(isCrossingNotTouching(area1, area3)); + + System.out.println("x"); + } + + public boolean isCrossingNotTouching(final String wktFirst, + final String wktSecond) + { + final WKTReader wktReader = new WKTReader(); + try + { + final Geometry geometry1 = wktReader.read(wktFirst); + final Geometry geometry2 = wktReader.read(wktSecond); + if(geometry1.intersects(geometry2)) + { + if(this.isAnyGeometryLineString(geometry1, geometry2)) + { + return this.isLineIntersectionNotTouch(geometry1, geometry2); + } + return this.isAreaIntersectionNotTouch(geometry1, geometry2); + } + } + catch (final ParseException e) + { + return false; + } + return false; + } + + private boolean isAnyGeometryLineString(final Geometry lineString, final Geometry lineString2) + { + return lineString.getGeometryType().equals("LineString") && lineString2.getGeometryType().equals("LineString"); + } + + private boolean isLineIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) + { + return !geometry1.overlaps(geometry2); + } + + private boolean isAreaIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) + { + return !(geometry1.covers(geometry2) || geometry1.coveredBy(geometry2)); + } + + + //TODO remove + @Test + public void intersectionTest() throws ParseException { + String area1 = "POLYGON((20.280407724000565 53.637694953623836,23.378552255250565 53.637694953623836,23.378552255250565 51.81495886522041,20.280407724000565 51.81495886522041,20.280407724000565 53.637694953623836))"; + String area2 = "POLYGON((19.049938974000565 53.04738220299281,21.620739755250565 53.04738220299281,21.620739755250565 51.29582283674896,19.049938974000565 51.29582283674896,19.049938974000565 53.04738220299281))"; + String line1 = "LINESTRING(19.325022325433846 53.530197223167754,22.818674669183846 51.97440230490904,22.357248887933846 51.66200440966252)"; + String line2 = "LINESTRING(18.885569200433846 52.19044648242124,23.389963731683842 53.51713468341888)"; + + Geometry a1 = new WKTReader().read(area1); + Geometry a2 = new WKTReader().read(area2); + Geometry l1 = new WKTReader().read(line1); + Geometry l2 = new WKTReader().read(line2); + + System.out.println("test"); + } + @Test public void testInvalidTwoCrossingItemsWithEdgesAtlas() { From 8b52d161c8aab09cf469d7fcf2c9eb8e24891159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 9 Dec 2020 10:55:59 +0100 Subject: [PATCH 30/36] Not simple or not valid geometries are ignored. --- .../intersections/BoundaryIntersectionCheck.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 90e40c8f1..af379c041 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -84,12 +84,12 @@ protected Optional flag(final AtlasObject object) private Optional processRelation(final AtlasObject object) { - if(object.getOsmIdentifier() == 2327223){ - System.out.println("2327223 FOUND"); - } - if(object.getOsmIdentifier() == 3890254){ - System.out.println("3890254 FOUND"); - } +// if(object.getOsmIdentifier() == 2327223){ +// System.out.println("2327223 FOUND"); +// } +// if(object.getOsmIdentifier() == 3890254){ +// System.out.println("3890254 FOUND"); +// } final Map tagToRelation = this.getRelationMap(object); final RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, this.getBoundaryParts((Relation) object)); final Set instructions = new HashSet<>(); @@ -406,6 +406,9 @@ public boolean isCrossingNotTouching(final String wktFirst, { final Geometry geometry1 = wktReader.read(wktFirst); final Geometry geometry2 = wktReader.read(wktSecond); + if(!geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple()){ + return false; + } if(geometry1.intersects(geometry2)) { if(!this.isGeometryPairOfLineType(geometry1, geometry2)) From ec2693049919810812a85a00351de0407d46098e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Tue, 15 Dec 2020 12:20:59 +0100 Subject: [PATCH 31/36] Improved check of line and area intersection. --- .../BoundaryIntersectionCheck.java | 4 +- .../BoundaryIntersectionCheckTest.java | 39 ++++++++++++------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index af379c041..9173c87b5 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -411,7 +411,7 @@ public boolean isCrossingNotTouching(final String wktFirst, } if(geometry1.intersects(geometry2)) { - if(!this.isGeometryPairOfLineType(geometry1, geometry2)) + if(this.isGeometryPairOfLineType(geometry1, geometry2)) { return this.isLineIntersectionNotTouch(geometry1, geometry2); } @@ -432,7 +432,7 @@ private boolean isGeometryPairOfLineType(final Geometry lineString, final Geomet private boolean isLineIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) { - return !geometry1.overlaps(geometry2); + return !(geometry1.overlaps(geometry2) || geometry1.touches(geometry2)); } private boolean isAreaIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index c9300997c..2940809f6 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -1,5 +1,6 @@ package org.openstreetmap.atlas.checks.validation.intersections; +import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -10,6 +11,9 @@ import org.openstreetmap.atlas.checks.validation.verifier.ConsumerBasedExpectedCheckVerifier; import org.openstreetmap.atlas.utilities.configuration.Configuration; +import java.io.FileInputStream; +import java.io.IOException; + /** * @author srachanski */ @@ -73,7 +77,6 @@ public void test(){ System.out.println("x"); } - public boolean isCrossingNotTouching(final String wktFirst, final String wktSecond) { @@ -82,9 +85,12 @@ public boolean isCrossingNotTouching(final String wktFirst, { final Geometry geometry1 = wktReader.read(wktFirst); final Geometry geometry2 = wktReader.read(wktSecond); + if(!geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple()){ + return false; + } if(geometry1.intersects(geometry2)) { - if(this.isAnyGeometryLineString(geometry1, geometry2)) + if(!this.isGeometryPairOfLineType(geometry1, geometry2)) { return this.isLineIntersectionNotTouch(geometry1, geometry2); } @@ -98,7 +104,7 @@ public boolean isCrossingNotTouching(final String wktFirst, return false; } - private boolean isAnyGeometryLineString(final Geometry lineString, final Geometry lineString2) + private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) { return lineString.getGeometryType().equals("LineString") && lineString2.getGeometryType().equals("LineString"); } @@ -110,24 +116,29 @@ private boolean isLineIntersectionNotTouch(final Geometry geometry1, final Geome private boolean isAreaIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) { - return !(geometry1.covers(geometry2) || geometry1.coveredBy(geometry2)); + return !(geometry1.covers(geometry2) || + geometry1.coveredBy(geometry2) || + geometry1.touches(geometry2)); } - //TODO remove @Test - public void intersectionTest() throws ParseException { - String area1 = "POLYGON((20.280407724000565 53.637694953623836,23.378552255250565 53.637694953623836,23.378552255250565 51.81495886522041,20.280407724000565 51.81495886522041,20.280407724000565 53.637694953623836))"; - String area2 = "POLYGON((19.049938974000565 53.04738220299281,21.620739755250565 53.04738220299281,21.620739755250565 51.29582283674896,19.049938974000565 51.29582283674896,19.049938974000565 53.04738220299281))"; - String line1 = "LINESTRING(19.325022325433846 53.530197223167754,22.818674669183846 51.97440230490904,22.357248887933846 51.66200440966252)"; - String line2 = "LINESTRING(18.885569200433846 52.19044648242124,23.389963731683842 53.51713468341888)"; + public void intersectionTest() throws ParseException, IOException { + FileInputStream fis = new FileInputStream("src/test/resources/area1"); + String area1 = IOUtils.toString(fis, "UTF-8"); +// String area1 = + FileInputStream fis2 = new FileInputStream("src/test/resources/area2"); + String area2 = IOUtils.toString(fis2, "UTF-8"); +// String area2 = +// String line1 = "LINESTRING(19.325022325433846 53.530197223167754,22.818674669183846 51.97440230490904,22.357248887933846 51.66200440966252)"; +// String line2 = "LINESTRING(18.885569200433846 52.19044648242124,23.389963731683842 53.51713468341888)"; Geometry a1 = new WKTReader().read(area1); Geometry a2 = new WKTReader().read(area2); - Geometry l1 = new WKTReader().read(line1); - Geometry l2 = new WKTReader().read(line2); - - System.out.println("test"); +// Geometry l1 = new WKTReader().read(line1); +// Geometry l2 = new WKTReader().read(line2); + System.out.println(isCrossingNotTouching(area1, area2)); + Assert.assertEquals(isCrossingNotTouching(area1, area2), false); } @Test From 3066a94da683da83582f4a237bd8f8bf8fa02d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Wed, 30 Dec 2020 15:51:37 +0100 Subject: [PATCH 32/36] Further intersection logic improvement and tests fixes. --- .../BoundaryIntersectionCheck.java | 95 +++-------- .../intersections/BoundaryPart.java | 31 ++-- .../intersections/RelationBoundary.java | 7 + .../BoundaryIntersectionCheckTest.java | 156 +++++++++--------- .../BoundaryIntersectionCheckTestRule.java | 20 +-- 5 files changed, 133 insertions(+), 176 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 9173c87b5..94c53e4e0 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -46,7 +46,7 @@ public class BoundaryIntersectionCheck extends BaseCheck public static final int INDEX = 0; public static final String TYPE = "type"; public static final String BOUNDARY = "boundary"; - private static final String INVALID_BOUNDARY_FORMAT = "Boundaries {0} with way {1} is crossing invalidly with boundaries {2} with way {3} at coordinates {4}."; + private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary {2} with way {3} at coordinates {4}."; private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, @@ -84,12 +84,6 @@ protected Optional flag(final AtlasObject object) private Optional processRelation(final AtlasObject object) { -// if(object.getOsmIdentifier() == 2327223){ -// System.out.println("2327223 FOUND"); -// } -// if(object.getOsmIdentifier() == 3890254){ -// System.out.println("3890254 FOUND"); -// } final Map tagToRelation = this.getRelationMap(object); final RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, this.getBoundaryParts((Relation) object)); final Set instructions = new HashSet<>(); @@ -97,12 +91,6 @@ private Optional processRelation(final AtlasObject object) final Set matchedTags = new HashSet<>(); for(final BoundaryPart currentBoundaryPart : relationBoundary.getBoundaryParts()) { -// if(currentBoundaryPart.getOsmIdentifier() == 2327223){ -// System.out.println("2327223 FOUND"); -// } -// if(currentBoundaryPart.getOsmIdentifier() == 3890254){ -// System.out.println("3890254 FOUND"); -// } final Iterable lineItemsIntersecting = object.getAtlas().lineItemsIntersecting(currentBoundaryPart.getBounds(), this.getPredicateForLineItemsSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); final Iterable areasIntersecting = object.getAtlas().areasIntersecting(currentBoundaryPart.getBounds(), @@ -112,6 +100,7 @@ private Optional processRelation(final AtlasObject object) this.processAreas(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, areasIntersecting, currentMatchedTags); objectsToFlag.addAll(relationBoundary.getRelationsByBoundaryTags(matchedTags)); + objectsToFlag.add(currentBoundaryPart.getAtlasEntity()); } if(instructions.isEmpty()) { @@ -122,7 +111,7 @@ private Optional processRelation(final AtlasObject object) final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); instructions.forEach(checkFlag::addInstruction); //TODO remove -// instructions.forEach(System.out::println); + instructions.forEach(System.out::println); checkFlag.addObjects(objectsToFlag); return Optional.of(checkFlag); } @@ -141,6 +130,7 @@ private void processAreas(final RelationBoundary relationBoundary, final Set matchingBoundaries = this.getBoundaries(area) .stream() .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).orElse(StringUtils.EMPTY))) + .filter(boundary -> !relationBoundary.containsRelationId(boundary.getOsmIdentifier())) .collect(Collectors.toSet()); if(!matchingBoundaries.isEmpty()) { @@ -155,9 +145,9 @@ private void processAreas(final RelationBoundary relationBoundary, area.toWkt()); final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); final String secondBoundaries = this.objectsToString(matchingBoundaries); - if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) + if(intersectingPoints.length != 0 && firstBoundaries.hashCode() < secondBoundaries.hashCode()) { - this.addInstruction(instructions, currentBoundaryPart, area, intersectingPoints, firstBoundaries, secondBoundaries); + this.addInstruction(instructions, currentBoundaryPart, area.getOsmIdentifier(), intersectingPoints, firstBoundaries, secondBoundaries); } } matchedTags.addAll(currentMatchedTags); @@ -177,6 +167,7 @@ private void processLineItems(final RelationBoundary relationBoundary, final Set matchingBoundaries = this.getBoundaries(lineItem) .stream() .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).get())) + .filter(boundary -> !relationBoundary.containsRelationId(boundary.getOsmIdentifier())) .collect(Collectors.toSet()); if(!matchingBoundaries.isEmpty()) { @@ -196,9 +187,9 @@ private void processLineItems(final RelationBoundary relationBoundary, line.toWkt()); final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); final String secondBoundaries = this.objectsToString(matchingBoundaries); - if(firstBoundaries.hashCode() < secondBoundaries.hashCode()) + if(intersectingPoints.length != 0 && firstBoundaries.hashCode() < secondBoundaries.hashCode()) { - this.addInstruction(instructions, currentBoundaryPart, line, intersectingPoints, firstBoundaries, secondBoundaries); + this.addInstruction(instructions, currentBoundaryPart, line.getOsmIdentifier(), intersectingPoints, firstBoundaries, secondBoundaries); } }); } @@ -208,7 +199,7 @@ private void processLineItems(final RelationBoundary relationBoundary, private void addInstruction(final Set instructions, final BoundaryPart lineItem, - final LineItem line, + final long osmIdentifier, final Coordinate[] intersectingPoints, final String firstBoundaries, final String secondBoundaries) @@ -217,23 +208,7 @@ private void addInstruction(final Set instructions, firstBoundaries, Long.toString(lineItem.getOsmIdentifier()), secondBoundaries, - Long.toString(line.getOsmIdentifier()), - this.coordinatesToList(intersectingPoints)); - instructions.add(instruction); - } - - private void addInstruction(final Set instructions, - final BoundaryPart lineItem, - final Area area, - final Coordinate[] intersectingPoints, - final String firstBoundaries, - final String secondBoundaries) - { - final String instruction = this.getLocalizedInstruction(INDEX, - firstBoundaries, - Long.toString(lineItem.getOsmIdentifier()), - secondBoundaries, - Long.toString(area.getOsmIdentifier()), + Long.toString(osmIdentifier), this.coordinatesToList(intersectingPoints)); instructions.add(instruction); } @@ -279,8 +254,7 @@ private Set getBoundaryParts(final Relation relation) .collect(Collectors.toSet()); boundaryTags.add(tag); boundaryTags.remove(StringUtils.EMPTY); - return new BoundaryPart(entity.getOsmIdentifier(), - entity.bounds(), entity.toWkt(), boundaryTags); + return new BoundaryPart(entity, boundaryTags); }) .collect(Collectors.toSet()); } @@ -335,7 +309,7 @@ private Geometry getGeometryForIntersection(String wktFirst) throws ParseExcepti final WKTReader wktReader = new WKTReader(); Geometry geometry1 = wktReader.read(wktFirst); - if (geometry1.getGeometryType().equals("Polygon")) { + if (geometry1.getGeometryType().equals(Geometry.TYPENAME_POLYGON)) { geometry1 = geometry1.getBoundary(); } return geometry1; @@ -355,20 +329,8 @@ private Predicate getPredicateForLineItemsSelection(final BoundaryPart private Predicate getPredicateForAreaSelection(final BoundaryPart boundaryPart, final Set boundaryTags) { -// if(boundaryPart.getOsmIdentifier() == 2327223){ -// System.out.println("2327223 FOUND"); -// } -// if(boundaryPart.getOsmIdentifier() == 3890254){ -// System.out.println("3890254 FOUND"); -// } return areaToCheck -> { -// if(areaToCheck.getOsmIdentifier() == 2327223){ -// System.out.println("2327223 FOUND"); -// } -// if(areaToCheck.getOsmIdentifier() == 3890254){ -// System.out.println("3890254 FOUND"); -// } if (this.checkAreaAsBoundary(areaToCheck, boundaryTags)) { return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), areaToCheck.toWkt()); @@ -397,7 +359,6 @@ private boolean checkAreaAsBoundary(final Area area, final Set boundaryT || boundaryTags.contains(area.getTag(BOUNDARY).orElse("")); } - //TODO change public boolean isCrossingNotTouching(final String wktFirst, final String wktSecond) { @@ -406,40 +367,32 @@ public boolean isCrossingNotTouching(final String wktFirst, { final Geometry geometry1 = wktReader.read(wktFirst); final Geometry geometry2 = wktReader.read(wktSecond); - if(!geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple()){ + if(geometry1.equals(geometry2)){ return false; } - if(geometry1.intersects(geometry2)) - { - if(this.isGeometryPairOfLineType(geometry1, geometry2)) - { - return this.isLineIntersectionNotTouch(geometry1, geometry2); - } - return this.isAreaIntersectionNotTouch(geometry1, geometry2); + if(anyGeometryInvalid(geometry1, geometry2)){ + return false; } + return isIntersectingNotTouching(geometry1, geometry2); } catch (final ParseException e) { return false; } - return false; } - private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) - { - return lineString.getGeometryType().equals("LineString") && lineString2.getGeometryType().equals("LineString"); + private boolean anyGeometryInvalid(Geometry geometry1, Geometry geometry2) { + return !geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple(); } - private boolean isLineIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) - { - return !(geometry1.overlaps(geometry2) || geometry1.touches(geometry2)); + private boolean isIntersectingNotTouching(final Geometry geometry1, final Geometry geometry2){ + return geometry1.intersects(geometry2) && + (geometry1.crosses(geometry2) || (geometry1.overlaps(geometry2) && !this.isGeometryPairOfLineType(geometry1, geometry2))); } - private boolean isAreaIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) + private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) { - return !(geometry1.covers(geometry2) || - geometry1.coveredBy(geometry2) || - geometry1.touches(geometry2)); + return lineString.getGeometryType().equals(Geometry.TYPENAME_LINESTRING) && lineString2.getGeometryType().equals(Geometry.TYPENAME_LINESTRING); } private String coordinatesToList(final Coordinate[] locations) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java index c55e8e925..88abfed6a 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java @@ -1,38 +1,35 @@ package org.openstreetmap.atlas.checks.validation.intersections; import org.openstreetmap.atlas.geography.Rectangle; -import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; +import org.openstreetmap.atlas.geography.atlas.items.AtlasEntity; -import java.util.List; import java.util.Set; public class BoundaryPart { - - private final Rectangle bounds; - private final long osmIdentifier; - private final String wktGeometry; + private final Set boundaryTags; - //TODO? -// private final Set atlasObjects; - - public BoundaryPart(long osmIdentifier, Rectangle bounds, String wktGeometry, Set boundaryTags) { - this.osmIdentifier = osmIdentifier; - this.bounds = bounds; - this.wktGeometry = wktGeometry; + private final AtlasEntity atlasEntity; + + public BoundaryPart(AtlasEntity entity, Set boundaryTags) { + this.atlasEntity = entity; this.boundaryTags = boundaryTags; } - + + public AtlasEntity getAtlasEntity() { + return atlasEntity; + } + public Rectangle getBounds() { - return bounds; + return atlasEntity.bounds(); } public long getOsmIdentifier() { - return osmIdentifier; + return atlasEntity.getOsmIdentifier(); } public String getWktGeometry() { - return wktGeometry; + return atlasEntity.toWkt(); } public Set getBoundaryTags() { diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java index d5a3704e4..d09a282f1 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java @@ -37,4 +37,11 @@ public Set getRelationsByBoundaryTags(Set tags){ .map(tagToRelation::get) .collect(Collectors.toSet()); } + + public boolean containsRelationId(long osmIdentifier) { + return tagToRelation.values() + .stream() + .map(Relation::getOsmIdentifier) + .anyMatch(id -> id == osmIdentifier); + } } diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index 2940809f6..15a6e09d3 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -62,84 +62,84 @@ public void testInvalidTwoCrossingItemsAtlas() }); } - //TODO remove - @Test - public void test(){ - String area1 = "POLYGON((0 0, 3 0, 3 3, 3 0, 0 0))"; - String area2 = "POLYGON((0 0, 2 0, 2 2, 2 0, 0 0))"; - String area3 = "POLYGON((0 0, 3 1, 4 4, 1 3, 0 0))"; - String line1 = "LINESTRING(1 1, 4 4)"; - String line2 = "LINESTRING(1 4, 4 1)"; - -// BoundaryIntersectionCheck boundaryIntersectionCheck = new BoundaryIntersectionCheck(null); - System.out.println(isCrossingNotTouching(area1, area2)); - System.out.println(isCrossingNotTouching(area1, area3)); - - System.out.println("x"); - } - public boolean isCrossingNotTouching(final String wktFirst, - final String wktSecond) - { - final WKTReader wktReader = new WKTReader(); - try - { - final Geometry geometry1 = wktReader.read(wktFirst); - final Geometry geometry2 = wktReader.read(wktSecond); - if(!geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple()){ - return false; - } - if(geometry1.intersects(geometry2)) - { - if(!this.isGeometryPairOfLineType(geometry1, geometry2)) - { - return this.isLineIntersectionNotTouch(geometry1, geometry2); - } - return this.isAreaIntersectionNotTouch(geometry1, geometry2); - } - } - catch (final ParseException e) - { - return false; - } - return false; - } - - private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) - { - return lineString.getGeometryType().equals("LineString") && lineString2.getGeometryType().equals("LineString"); - } - - private boolean isLineIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) - { - return !geometry1.overlaps(geometry2); - } - - private boolean isAreaIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) - { - return !(geometry1.covers(geometry2) || - geometry1.coveredBy(geometry2) || - geometry1.touches(geometry2)); - } - - //TODO remove - @Test - public void intersectionTest() throws ParseException, IOException { - FileInputStream fis = new FileInputStream("src/test/resources/area1"); - String area1 = IOUtils.toString(fis, "UTF-8"); -// String area1 = - FileInputStream fis2 = new FileInputStream("src/test/resources/area2"); - String area2 = IOUtils.toString(fis2, "UTF-8"); -// String area2 = -// String line1 = "LINESTRING(19.325022325433846 53.530197223167754,22.818674669183846 51.97440230490904,22.357248887933846 51.66200440966252)"; -// String line2 = "LINESTRING(18.885569200433846 52.19044648242124,23.389963731683842 53.51713468341888)"; - - Geometry a1 = new WKTReader().read(area1); - Geometry a2 = new WKTReader().read(area2); -// Geometry l1 = new WKTReader().read(line1); -// Geometry l2 = new WKTReader().read(line2); - System.out.println(isCrossingNotTouching(area1, area2)); - Assert.assertEquals(isCrossingNotTouching(area1, area2), false); - } +// //TODO remove +// @Test +// public void test(){ +// String area1 = "POLYGON((0 0, 3 0, 3 3, 3 0, 0 0))"; +// String area2 = "POLYGON((0 0, 2 0, 2 2, 2 0, 0 0))"; +// String area3 = "POLYGON((0 0, 3 1, 4 4, 1 3, 0 0))"; +// String line1 = "LINESTRING(1 1, 4 4)"; +// String line2 = "LINESTRING(1 4, 4 1)"; +// +//// BoundaryIntersectionCheck boundaryIntersectionCheck = new BoundaryIntersectionCheck(null); +// System.out.println(isCrossingNotTouching(area1, area2)); +// System.out.println(isCrossingNotTouching(area1, area3)); +// +// System.out.println("x"); +// } +// public boolean isCrossingNotTouching(final String wktFirst, +// final String wktSecond) +// { +// final WKTReader wktReader = new WKTReader(); +// try +// { +// final Geometry geometry1 = wktReader.read(wktFirst); +// final Geometry geometry2 = wktReader.read(wktSecond); +// if(!geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple()){ +// return false; +// } +// if(geometry1.intersects(geometry2)) +// { +// if(!this.isGeometryPairOfLineType(geometry1, geometry2)) +// { +// return this.isLineIntersectionNotTouch(geometry1, geometry2); +// } +// return this.isAreaIntersectionNotTouch(geometry1, geometry2); +// } +// } +// catch (final ParseException e) +// { +// return false; +// } +// return false; +// } +// +// private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) +// { +// return lineString.getGeometryType().equals("LineString") && lineString2.getGeometryType().equals("LineString"); +// } +// +// private boolean isLineIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) +// { +// return !geometry1.overlaps(geometry2); +// } +// +// private boolean isAreaIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) +// { +// return !(geometry1.covers(geometry2) || +// geometry1.coveredBy(geometry2) || +// geometry1.touches(geometry2)); +// } +// +// //TODO remove +// @Test +// public void intersectionTest() throws ParseException, IOException { +// FileInputStream fis = new FileInputStream("src/test/resources/area1"); +// String area1 = IOUtils.toString(fis, "UTF-8"); +//// String area1 = +// FileInputStream fis2 = new FileInputStream("src/test/resources/area2"); +// String area2 = IOUtils.toString(fis2, "UTF-8"); +//// String area2 = +//// String line1 = "LINESTRING(19.325022325433846 53.530197223167754,22.818674669183846 51.97440230490904,22.357248887933846 51.66200440966252)"; +//// String line2 = "LINESTRING(18.885569200433846 52.19044648242124,23.389963731683842 53.51713468341888)"; +// +// Geometry a1 = new WKTReader().read(area1); +// Geometry a2 = new WKTReader().read(area2); +//// Geometry l1 = new WKTReader().read(line1); +//// Geometry l2 = new WKTReader().read(line2); +// System.out.println(isCrossingNotTouching(area1, area2)); +// Assert.assertEquals(isCrossingNotTouching(area1, area2), false); +// } @Test public void testInvalidTwoCrossingItemsWithEdgesAtlas() diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java index 9875179f3..2e2638bf9 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -97,12 +97,12 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), @Node(coordinates = @Loc(value = COORD_6)) }, lines = { - @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_15), + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_2), @Loc(value = COORD_3), @Loc(value = COORD_4), @Loc(value = COORD_1) }, id = LINE_ONE), - @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), + @Line(coordinates = { @Loc(value = COORD_20), @Loc(value = COORD_5), @Loc(value = COORD_6), - @Loc(value = COORD_1) }, id = LINE_TWO) }, relations = { + @Loc(value = COORD_20) }, id = LINE_TWO) }, relations = { @Relation(id = RELATION_ONE, members = { @Relation.Member(id = LINE_ONE, role = "outer", type = "line") }, tags = { "type=boundary", "boundary=administrative" }), @@ -114,12 +114,12 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)) }, lines = { - @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_15), + @Node(coordinates = @Loc(value = COORD_6)), @Node(coordinates = @Loc(value = COORD_20)) }, lines = { + @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_2), @Loc(value = COORD_3), @Loc(value = COORD_4), @Loc(value = COORD_1) }, id = LINE_ONE, tags = { "type=boundary", "boundary=administrative" }), - @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), + @Line(coordinates = { @Loc(value = COORD_20), @Loc(value = COORD_5), @Loc(value = COORD_6), @Loc(value = COORD_1) }, id = LINE_TWO, tags = { "type=boundary", "boundary=administrative" }) }, relations = { @Relation(id = RELATION_ONE, members = { @@ -131,13 +131,13 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)) }, edges = { - @Edge(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_15), + @Node(coordinates = @Loc(value = COORD_6)), @Node(coordinates = @Loc(value = COORD_20)) }, edges = { + @Edge(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_2), @Loc(value = COORD_3), @Loc(value = COORD_4), @Loc(value = COORD_1) }, id = EDGE_ONE), - @Edge(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_5), + @Edge(coordinates = { @Loc(value = COORD_20), @Loc(value = COORD_5), @Loc(value = COORD_6), - @Loc(value = COORD_1) }, id = EDGE_TWO) }, relations = { + @Loc(value = COORD_20) }, id = EDGE_TWO) }, relations = { @Relation(id = RELATION_ONE, members = { @Relation.Member(id = EDGE_ONE, role = "outer", type = "edge") }, tags = { "type=boundary", "boundary=administrative" }), From 7cf2e02b7a4e757b7f0e9fa037f412f1fb3e4f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Sun, 3 Jan 2021 20:22:52 +0100 Subject: [PATCH 33/36] Checkstyle corrections. --- .../BoundaryIntersectionCheck.java | 35 ++++++++-------- .../intersections/BoundaryPart.java | 38 ++++++++++------- .../intersections/RelationBoundary.java | 41 ++++++++++--------- .../intersections/UnwalkableWaysCheck.java | 4 +- 4 files changed, 65 insertions(+), 53 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 94c53e4e0..5c54ffa04 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -58,12 +58,6 @@ public BoundaryIntersectionCheck(final Configuration configuration) super(configuration); } - private static boolean isObjectOfBoundaryTypeWithBoundaryTag(final AtlasObject object) - { - return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) - && Validators.hasValuesFor(object, BoundaryTag.class); - } - private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) { return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) @@ -73,7 +67,7 @@ private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject o @Override public boolean validCheckForObject(final AtlasObject object) { - return object instanceof Relation && isObjectOfBoundaryTypeWithBoundaryTag(object); + return object instanceof Relation && isRelationTypeBoundaryWithBoundaryTag(object); } @Override @@ -110,8 +104,6 @@ private Optional processRelation(final AtlasObject object) { final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); instructions.forEach(checkFlag::addInstruction); - //TODO remove - instructions.forEach(System.out::println); checkFlag.addObjects(objectsToFlag); return Optional.of(checkFlag); } @@ -220,7 +212,7 @@ private Map getRelationMap(final AtlasObject object) { ((MultiRelation) object).relations() .stream() - .filter(BoundaryIntersectionCheck::isObjectOfBoundaryTypeWithBoundaryTag) + .filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) .forEach(relation -> tagToRelation.put(relation.getTag(BOUNDARY).get(), relation)); } tagToRelation.put(object.getTag(BOUNDARY).get(), (Relation) object); @@ -294,8 +286,8 @@ private Coordinate[] getIntersectionPoints(final String wktFirst, { try { - Geometry geometry1 = getGeometryForIntersection(wktFirst); - Geometry geometry2 = getGeometryForIntersection(wktSecond); + final Geometry geometry1 = this.getGeometryForIntersection(wktFirst); + final Geometry geometry2 = this.getGeometryForIntersection(wktSecond); return geometry1.intersection(geometry2).getCoordinates(); } catch (final ParseException e) @@ -304,12 +296,13 @@ private Coordinate[] getIntersectionPoints(final String wktFirst, } } - private Geometry getGeometryForIntersection(String wktFirst) throws ParseException + private Geometry getGeometryForIntersection(final String wktFirst) throws ParseException { final WKTReader wktReader = new WKTReader(); Geometry geometry1 = wktReader.read(wktFirst); - if (geometry1.getGeometryType().equals(Geometry.TYPENAME_POLYGON)) { + if (geometry1.getGeometryType().equals(Geometry.TYPENAME_POLYGON)) + { geometry1 = geometry1.getBoundary(); } return geometry1; @@ -367,13 +360,15 @@ public boolean isCrossingNotTouching(final String wktFirst, { final Geometry geometry1 = wktReader.read(wktFirst); final Geometry geometry2 = wktReader.read(wktSecond); - if(geometry1.equals(geometry2)){ + if(geometry1.equals(geometry2)) + { return false; } - if(anyGeometryInvalid(geometry1, geometry2)){ + if(this.anyGeometryInvalid(geometry1, geometry2)) + { return false; } - return isIntersectingNotTouching(geometry1, geometry2); + return this.isIntersectingNotTouching(geometry1, geometry2); } catch (final ParseException e) { @@ -381,11 +376,13 @@ public boolean isCrossingNotTouching(final String wktFirst, } } - private boolean anyGeometryInvalid(Geometry geometry1, Geometry geometry2) { + private boolean anyGeometryInvalid(final Geometry geometry1, final Geometry geometry2) + { return !geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple(); } - private boolean isIntersectingNotTouching(final Geometry geometry1, final Geometry geometry2){ + private boolean isIntersectingNotTouching(final Geometry geometry1, final Geometry geometry2) + { return geometry1.intersects(geometry2) && (geometry1.crosses(geometry2) || (geometry1.overlaps(geometry2) && !this.isGeometryPairOfLineType(geometry1, geometry2))); } diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java index 88abfed6a..c5ee5565d 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java @@ -1,38 +1,48 @@ package org.openstreetmap.atlas.checks.validation.intersections; +import java.util.Set; + import org.openstreetmap.atlas.geography.Rectangle; import org.openstreetmap.atlas.geography.atlas.items.AtlasEntity; -import java.util.Set; - -public class BoundaryPart { +/** + * @author srachanski + */ +public class BoundaryPart +{ private final Set boundaryTags; private final AtlasEntity atlasEntity; - public BoundaryPart(AtlasEntity entity, Set boundaryTags) { + public BoundaryPart(final AtlasEntity entity, final Set boundaryTags) + { this.atlasEntity = entity; this.boundaryTags = boundaryTags; } - public AtlasEntity getAtlasEntity() { - return atlasEntity; + public AtlasEntity getAtlasEntity() + { + return this.atlasEntity; } - public Rectangle getBounds() { - return atlasEntity.bounds(); + public Rectangle getBounds() + { + return this.atlasEntity.bounds(); } - public long getOsmIdentifier() { - return atlasEntity.getOsmIdentifier(); + public long getOsmIdentifier() + { + return this.atlasEntity.getOsmIdentifier(); } - public String getWktGeometry() { - return atlasEntity.toWkt(); + public String getWktGeometry() + { + return this.atlasEntity.toWkt(); } - public Set getBoundaryTags() { - return boundaryTags; + public Set getBoundaryTags() + { + return this.boundaryTags; } } diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java index d09a282f1..73fb9f97a 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java @@ -1,45 +1,48 @@ package org.openstreetmap.atlas.checks.validation.intersections; -import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; -import org.openstreetmap.atlas.geography.atlas.items.LineItem; -import org.openstreetmap.atlas.geography.atlas.items.Relation; - -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -public class RelationBoundary { +import org.openstreetmap.atlas.geography.atlas.items.Relation; + +/** + * @author srachanski + */ +public class RelationBoundary +{ private final Map tagToRelation; private final Set boundaryParts; -// private final Set boundaryObjects; - public RelationBoundary(Map tagToRelation, Set boundaryParts) { + public RelationBoundary(final Map tagToRelation, final Set boundaryParts) + { this.tagToRelation = tagToRelation; this.boundaryParts = boundaryParts; -// this.boundaryObjects = boundaryParts.stream() -// .map(boundaryPart -> boundaryPart.get) } - public Map getTagToRelation() { - return tagToRelation; + public Map getTagToRelation() + { + return this.tagToRelation; } - public Set getBoundaryParts() { - return boundaryParts; + public Set getBoundaryParts() + { + return this.boundaryParts; } - public Set getRelationsByBoundaryTags(Set tags){ - return tagToRelation.keySet() + public Set getRelationsByBoundaryTags(final Set tags) + { + return this.tagToRelation.keySet() .stream() .filter(tags::contains) - .map(tagToRelation::get) + .map(this.tagToRelation::get) .collect(Collectors.toSet()); } - public boolean containsRelationId(long osmIdentifier) { - return tagToRelation.values() + public boolean containsRelationId(final long osmIdentifier) + { + return this.tagToRelation.values() .stream() .map(Relation::getOsmIdentifier) .anyMatch(id -> id == osmIdentifier); diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/UnwalkableWaysCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/UnwalkableWaysCheck.java index 7635368f0..e5d0203fe 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/UnwalkableWaysCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/UnwalkableWaysCheck.java @@ -37,7 +37,9 @@ public class UnwalkableWaysCheck extends BaseCheck private static final Logger logger = LoggerFactory.getLogger(UnwalkableWaysCheck.class); // Instructions private static final List FALLBACK_INSTRUCTIONS = Collections - .singletonList(""); + .singletonList("Way {0,number,#} may be unwalkable and needs verification if safe " + + "pedestrian crossing exists. If it does, it should be marked ‘foot=yes’. If " + + "safe pedestrian crossing does not exist, the Way should be marked ‘foot=no'."); // The minimum highway type considered for potential dual carriageways private static final HighwayTag MINIMUM_HIGHWAY_TYPE_DEFAULT = HighwayTag.PRIMARY; private static final List DEFAULT_WALKWAY_TAGS = Arrays.asList( From e2bcffa551f39fbdeba87a130d04ce67ccbd622b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Sun, 3 Jan 2021 21:39:29 +0100 Subject: [PATCH 34/36] Checkstyle ordering. --- .../BoundaryIntersectionCheck.java | 414 +++++++++--------- .../intersections/BoundaryPart.java | 14 +- .../intersections/RelationBoundary.java | 18 +- 3 files changed, 222 insertions(+), 224 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 5c54ffa04..032205d8f 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -42,28 +42,27 @@ public class BoundaryIntersectionCheck extends BaseCheck { - public static final String DELIMITER = ", "; - public static final int INDEX = 0; - public static final String TYPE = "type"; - public static final String BOUNDARY = "boundary"; + private static final String DELIMITER = ", "; + private static final int INDEX = 0; + private static final String TYPE = "type"; + private static final String BOUNDARY = "boundary"; private static final String INVALID_BOUNDARY_FORMAT = "Boundary {0} with way {1} is crossing invalidly with boundary {2} with way {3} at coordinates {4}."; private static final String INSTRUCTION_FORMAT = INVALID_BOUNDARY_FORMAT + " Two boundaries should not intersect each other."; private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(INSTRUCTION_FORMAT, INVALID_BOUNDARY_FORMAT); - - public BoundaryIntersectionCheck(final Configuration configuration) - { - super(configuration); - } - private static boolean isRelationTypeBoundaryWithBoundaryTag(final AtlasObject object) { return Validators.isOfType(object, RelationTypeTag.class, RelationTypeTag.BOUNDARY) && Validators.hasValuesFor(object, BoundaryTag.class); } + public BoundaryIntersectionCheck(final Configuration configuration) + { + super(configuration); + } + @Override public boolean validCheckForObject(final AtlasObject object) { @@ -76,117 +75,10 @@ protected Optional flag(final AtlasObject object) return this.processRelation(object); } - private Optional processRelation(final AtlasObject object) - { - final Map tagToRelation = this.getRelationMap(object); - final RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, this.getBoundaryParts((Relation) object)); - final Set instructions = new HashSet<>(); - final Set objectsToFlag = new HashSet<>(); - final Set matchedTags = new HashSet<>(); - for(final BoundaryPart currentBoundaryPart : relationBoundary.getBoundaryParts()) - { - final Iterable lineItemsIntersecting = object.getAtlas().lineItemsIntersecting(currentBoundaryPart.getBounds(), - this.getPredicateForLineItemsSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); - final Iterable areasIntersecting = object.getAtlas().areasIntersecting(currentBoundaryPart.getBounds(), - this.getPredicateForAreaSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); - final Set currentMatchedTags = new HashSet<>(); - this.processLineItems(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, lineItemsIntersecting, currentMatchedTags); - this.processAreas(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, areasIntersecting, currentMatchedTags); - - objectsToFlag.addAll(relationBoundary.getRelationsByBoundaryTags(matchedTags)); - objectsToFlag.add(currentBoundaryPart.getAtlasEntity()); - } - if(instructions.isEmpty()) - { - return Optional.empty(); - } - else - { - final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); - instructions.forEach(checkFlag::addInstruction); - checkFlag.addObjects(objectsToFlag); - return Optional.of(checkFlag); - } - } - - private void processAreas(final RelationBoundary relationBoundary, - final Set instructions, - final Set objectsToFlag, - final Set matchedTags, - final BoundaryPart currentBoundaryPart, - final Iterable areasIntersecting, - final Set currentMatchedTags) - { - areasIntersecting.forEach(area -> - { - final Set matchingBoundaries = this.getBoundaries(area) - .stream() - .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).orElse(StringUtils.EMPTY))) - .filter(boundary -> !relationBoundary.containsRelationId(boundary.getOsmIdentifier())) - .collect(Collectors.toSet()); - if(!matchingBoundaries.isEmpty()) - { - currentMatchedTags.addAll(matchingBoundaries - .stream() - .map(relation -> relation.getTag(BOUNDARY)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet())); - objectsToFlag.addAll(matchingBoundaries); - final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), - area.toWkt()); - final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); - final String secondBoundaries = this.objectsToString(matchingBoundaries); - if(intersectingPoints.length != 0 && firstBoundaries.hashCode() < secondBoundaries.hashCode()) - { - this.addInstruction(instructions, currentBoundaryPart, area.getOsmIdentifier(), intersectingPoints, firstBoundaries, secondBoundaries); - } - } - matchedTags.addAll(currentMatchedTags); - }); - } - - private void processLineItems(final RelationBoundary relationBoundary, - final Set instructions, - final Set objectsToFlag, - final Set matchedTags, - final BoundaryPart currentBoundaryPart, - final Iterable lineItemsIntersecting, - final Set currentMatchedTags) + @Override + protected List getFallbackInstructions() { - lineItemsIntersecting.forEach(lineItem -> - { - final Set matchingBoundaries = this.getBoundaries(lineItem) - .stream() - .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).get())) - .filter(boundary -> !relationBoundary.containsRelationId(boundary.getOsmIdentifier())) - .collect(Collectors.toSet()); - if(!matchingBoundaries.isEmpty()) - { - currentMatchedTags.addAll(matchingBoundaries - .stream() - .map(relation -> relation.getTag(BOUNDARY)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet())); - objectsToFlag.addAll(matchingBoundaries); - - final List lineItems = this.getLineItems(lineItem); - lineItems.forEach(line -> - { - objectsToFlag.add(line); - final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), - line.toWkt()); - final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); - final String secondBoundaries = this.objectsToString(matchingBoundaries); - if(intersectingPoints.length != 0 && firstBoundaries.hashCode() < secondBoundaries.hashCode()) - { - this.addInstruction(instructions, currentBoundaryPart, line.getOsmIdentifier(), intersectingPoints, firstBoundaries, secondBoundaries); - } - }); - } - matchedTags.addAll(currentMatchedTags); - }); + return FALLBACK_INSTRUCTIONS; } private void addInstruction(final Set instructions, @@ -205,56 +97,31 @@ private void addInstruction(final Set instructions, instructions.add(instruction); } - private Map getRelationMap(final AtlasObject object) - { - final Map tagToRelation = new HashMap<>(); - if(object instanceof MultiRelation) - { - ((MultiRelation) object).relations() - .stream() - .filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) - .forEach(relation -> tagToRelation.put(relation.getTag(BOUNDARY).get(), relation)); - } - tagToRelation.put(object.getTag(BOUNDARY).get(), (Relation) object); - return tagToRelation; - } - - private List getLineItems(final LineItem lineItem) + private boolean checkAreaAsBoundary(final Area area, final Set boundaryTags) { - if(lineItem instanceof MultiLine) - { - final List lines = new ArrayList<>(); - ((MultiLine) lineItem).getSubLines() - .forEach(lines::add); - return lines; - } - return Collections.singletonList(lineItem); + return area + .relations().stream() + .anyMatch(relationToCheck -> BoundaryIntersectionCheck + .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) + && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())) + || boundaryTags.contains(area.getTag(BOUNDARY).orElse("")); } - private Set getBoundaryParts(final Relation relation) + private boolean checkLineItemAsBoundary(final LineItem lineItem, final Set boundaryTags) { - final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE, ItemType.LINE, ItemType.AREA); - return relationMemberLineItems - .stream().map(RelationMember::getEntity) - .map(entity -> - { - final String tag = entity.getTags().get(BOUNDARY); - final Set boundaryTags = entity.relations() - .stream() - .filter(currentRelation -> BOUNDARY.equals(currentRelation.getTag(TYPE).get())) - .map(currentRelation -> currentRelation.getTag(BOUNDARY).orElse(StringUtils.EMPTY)) - .collect(Collectors.toSet()); - boundaryTags.add(tag); - boundaryTags.remove(StringUtils.EMPTY); - return new BoundaryPart(entity, boundaryTags); - }) - .collect(Collectors.toSet()); + return lineItem + .relations().stream() + .anyMatch(relationToCheck -> BoundaryIntersectionCheck + .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) + && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())) + || boundaryTags.contains(lineItem.getTag(BOUNDARY).orElse("")); } - @Override - protected List getFallbackInstructions() + private String coordinatesToList(final Coordinate[] locations) { - return FALLBACK_INSTRUCTIONS; + return Stream.of(locations) + .map(coordinate -> String.format("(%s, %s)", coordinate.getX(), coordinate.getY())) + .collect(Collectors.joining(DELIMITER)); } private Set getBoundaries(final LineItem currentLineItem) @@ -281,6 +148,38 @@ private Set getBoundaries(final Area area) .collect(Collectors.toSet()); } + private Set getBoundaryParts(final Relation relation) + { + final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE, ItemType.LINE, ItemType.AREA); + return relationMemberLineItems + .stream().map(RelationMember::getEntity) + .map(entity -> + { + final String tag = entity.getTags().get(BOUNDARY); + final Set boundaryTags = entity.relations() + .stream() + .filter(currentRelation -> BOUNDARY.equals(currentRelation.getTag(TYPE).get())) + .map(currentRelation -> currentRelation.getTag(BOUNDARY).orElse(StringUtils.EMPTY)) + .collect(Collectors.toSet()); + boundaryTags.add(tag); + boundaryTags.remove(StringUtils.EMPTY); + return new BoundaryPart(entity, boundaryTags); + }) + .collect(Collectors.toSet()); + } + + private Geometry getGeometryForIntersection(final String wktFirst) throws ParseException + { + + final WKTReader wktReader = new WKTReader(); + Geometry geometry1 = wktReader.read(wktFirst); + if (geometry1.getGeometryType().equals(Geometry.TYPENAME_POLYGON)) + { + geometry1 = geometry1.getBoundary(); + } + return geometry1; + } + private Coordinate[] getIntersectionPoints(final String wktFirst, final String wktSecond) { @@ -296,64 +195,62 @@ private Coordinate[] getIntersectionPoints(final String wktFirst, } } - private Geometry getGeometryForIntersection(final String wktFirst) throws ParseException + private List getLineItems(final LineItem lineItem) { - - final WKTReader wktReader = new WKTReader(); - Geometry geometry1 = wktReader.read(wktFirst); - if (geometry1.getGeometryType().equals(Geometry.TYPENAME_POLYGON)) + if(lineItem instanceof MultiLine) { - geometry1 = geometry1.getBoundary(); + final List lines = new ArrayList<>(); + ((MultiLine) lineItem).getSubLines() + .forEach(lines::add); + return lines; } - return geometry1; + return Collections.singletonList(lineItem); } - private Predicate getPredicateForLineItemsSelection(final BoundaryPart boundaryPart, final Set boundaryTags) + private Predicate getPredicateForAreaSelection(final BoundaryPart boundaryPart, final Set boundaryTags) { - return lineItemToCheck -> + return areaToCheck -> { - if (this.checkLineItemAsBoundary(lineItemToCheck, boundaryTags)) + if (this.checkAreaAsBoundary(areaToCheck, boundaryTags)) { - return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), lineItemToCheck.toWkt()); + return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), areaToCheck.toWkt()); } return false; }; } - private Predicate getPredicateForAreaSelection(final BoundaryPart boundaryPart, final Set boundaryTags) + private Predicate getPredicateForLineItemsSelection(final BoundaryPart boundaryPart, final Set boundaryTags) { - return areaToCheck -> + return lineItemToCheck -> { - if (this.checkAreaAsBoundary(areaToCheck, boundaryTags)) + if (this.checkLineItemAsBoundary(lineItemToCheck, boundaryTags)) { - return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), areaToCheck.toWkt()); + return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), lineItemToCheck.toWkt()); } return false; }; } - private boolean checkLineItemAsBoundary(final LineItem lineItem, final Set boundaryTags) + private Map getRelationMap(final AtlasObject object) { - return lineItem - .relations().stream() - .anyMatch(relationToCheck -> BoundaryIntersectionCheck - .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) - && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())) - || boundaryTags.contains(lineItem.getTag(BOUNDARY).orElse("")); + final Map tagToRelation = new HashMap<>(); + if(object instanceof MultiRelation) + { + ((MultiRelation) object).relations() + .stream() + .filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) + .forEach(relation -> tagToRelation.put(relation.getTag(BOUNDARY).get(), relation)); + } + tagToRelation.put(object.getTag(BOUNDARY).get(), (Relation) object); + return tagToRelation; } - private boolean checkAreaAsBoundary(final Area area, final Set boundaryTags) + private boolean isAnyGeometryInvalid(final Geometry geometry1, final Geometry geometry2) { - return area - .relations().stream() - .anyMatch(relationToCheck -> BoundaryIntersectionCheck - .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) - && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())) - || boundaryTags.contains(area.getTag(BOUNDARY).orElse("")); + return !geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple(); } - public boolean isCrossingNotTouching(final String wktFirst, - final String wktSecond) + private boolean isCrossingNotTouching(final String wktFirst, final String wktSecond) { final WKTReader wktReader = new WKTReader(); try @@ -364,7 +261,7 @@ public boolean isCrossingNotTouching(final String wktFirst, { return false; } - if(this.anyGeometryInvalid(geometry1, geometry2)) + if(this.isAnyGeometryInvalid(geometry1, geometry2)) { return false; } @@ -376,9 +273,9 @@ public boolean isCrossingNotTouching(final String wktFirst, } } - private boolean anyGeometryInvalid(final Geometry geometry1, final Geometry geometry2) + private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) { - return !geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple(); + return lineString.getGeometryType().equals(Geometry.TYPENAME_LINESTRING) && lineString2.getGeometryType().equals(Geometry.TYPENAME_LINESTRING); } private boolean isIntersectingNotTouching(final Geometry geometry1, final Geometry geometry2) @@ -387,24 +284,125 @@ private boolean isIntersectingNotTouching(final Geometry geometry1, final Geomet (geometry1.crosses(geometry2) || (geometry1.overlaps(geometry2) && !this.isGeometryPairOfLineType(geometry1, geometry2))); } - private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) + private String objectsToString(final Set objects) { - return lineString.getGeometryType().equals(Geometry.TYPENAME_LINESTRING) && lineString2.getGeometryType().equals(Geometry.TYPENAME_LINESTRING); + return objects + .stream() + .map(object -> Long.toString(object.getOsmIdentifier())) + .collect(Collectors.joining(DELIMITER)); } - private String coordinatesToList(final Coordinate[] locations) + private void processAreas(final RelationBoundary relationBoundary, + final Set instructions, + final Set objectsToFlag, + final Set matchedTags, + final BoundaryPart currentBoundaryPart, + final Iterable areasIntersecting, + final Set currentMatchedTags) { - return Stream.of(locations) - .map(coordinate -> String.format("(%s, %s)", coordinate.getX(), coordinate.getY())) - .collect(Collectors.joining(DELIMITER)); + areasIntersecting.forEach(area -> + { + final Set matchingBoundaries = this.getBoundaries(area) + .stream() + .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).orElse(StringUtils.EMPTY))) + .filter(boundary -> !relationBoundary.containsRelationId(boundary.getOsmIdentifier())) + .collect(Collectors.toSet()); + if(!matchingBoundaries.isEmpty()) + { + currentMatchedTags.addAll(matchingBoundaries + .stream() + .map(relation -> relation.getTag(BOUNDARY)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet())); + objectsToFlag.addAll(matchingBoundaries); + final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), + area.toWkt()); + final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); + final String secondBoundaries = this.objectsToString(matchingBoundaries); + if(intersectingPoints.length != 0 && firstBoundaries.hashCode() < secondBoundaries.hashCode()) + { + this.addInstruction(instructions, currentBoundaryPart, area.getOsmIdentifier(), intersectingPoints, firstBoundaries, secondBoundaries); + } + } + matchedTags.addAll(currentMatchedTags); + }); } - private String objectsToString(final Set objects) + private void processLineItems(final RelationBoundary relationBoundary, + final Set instructions, + final Set objectsToFlag, + final Set matchedTags, + final BoundaryPart currentBoundaryPart, + final Iterable lineItemsIntersecting, + final Set currentMatchedTags) { - return objects - .stream() - .map(object -> Long.toString(object.getOsmIdentifier())) - .collect(Collectors.joining(DELIMITER)); + lineItemsIntersecting.forEach(lineItem -> + { + final Set matchingBoundaries = this.getBoundaries(lineItem) + .stream() + .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).get())) + .filter(boundary -> !relationBoundary.containsRelationId(boundary.getOsmIdentifier())) + .collect(Collectors.toSet()); + if(!matchingBoundaries.isEmpty()) + { + currentMatchedTags.addAll(matchingBoundaries + .stream() + .map(relation -> relation.getTag(BOUNDARY)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet())); + objectsToFlag.addAll(matchingBoundaries); + + final List lineItems = this.getLineItems(lineItem); + lineItems.forEach(line -> + { + objectsToFlag.add(line); + final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), + line.toWkt()); + final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); + final String secondBoundaries = this.objectsToString(matchingBoundaries); + if(intersectingPoints.length != 0 && firstBoundaries.hashCode() < secondBoundaries.hashCode()) + { + this.addInstruction(instructions, currentBoundaryPart, line.getOsmIdentifier(), intersectingPoints, firstBoundaries, secondBoundaries); + } + }); + } + matchedTags.addAll(currentMatchedTags); + }); + } + + private Optional processRelation(final AtlasObject object) + { + final Map tagToRelation = this.getRelationMap(object); + final RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, this.getBoundaryParts((Relation) object)); + final Set instructions = new HashSet<>(); + final Set objectsToFlag = new HashSet<>(); + final Set matchedTags = new HashSet<>(); + for(final BoundaryPart currentBoundaryPart : relationBoundary.getBoundaryParts()) + { + final Iterable lineItemsIntersecting = object.getAtlas().lineItemsIntersecting(currentBoundaryPart.getBounds(), + this.getPredicateForLineItemsSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); + final Iterable areasIntersecting = object.getAtlas().areasIntersecting(currentBoundaryPart.getBounds(), + this.getPredicateForAreaSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); + final Set currentMatchedTags = new HashSet<>(); + this.processLineItems(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, lineItemsIntersecting, currentMatchedTags); + this.processAreas(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, areasIntersecting, currentMatchedTags); + + objectsToFlag.addAll(relationBoundary.getRelationsByBoundaryTags(matchedTags)); + objectsToFlag.add(currentBoundaryPart.getAtlasEntity()); + } + if(instructions.isEmpty()) + { + return Optional.empty(); + } + else + { + final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); + instructions.forEach(checkFlag::addInstruction); + checkFlag.addObjects(objectsToFlag); + return Optional.of(checkFlag); + } } } diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java index c5ee5565d..b5f1ed115 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java @@ -26,23 +26,23 @@ public AtlasEntity getAtlasEntity() return this.atlasEntity; } + public Set getBoundaryTags() + { + return this.boundaryTags; + } + public Rectangle getBounds() { return this.atlasEntity.bounds(); } - + public long getOsmIdentifier() { return this.atlasEntity.getOsmIdentifier(); } - + public String getWktGeometry() { return this.atlasEntity.toWkt(); } - - public Set getBoundaryTags() - { - return this.boundaryTags; - } } diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java index 73fb9f97a..cb878802a 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java @@ -20,12 +20,15 @@ public RelationBoundary(final Map tagToRelation, final Set getTagToRelation() + + public boolean containsRelationId(final long osmIdentifier) { - return this.tagToRelation; + return this.tagToRelation.values() + .stream() + .map(Relation::getOsmIdentifier) + .anyMatch(id -> id == osmIdentifier); } - + public Set getBoundaryParts() { return this.boundaryParts; @@ -40,11 +43,8 @@ public Set getRelationsByBoundaryTags(final Set tags) .collect(Collectors.toSet()); } - public boolean containsRelationId(final long osmIdentifier) + public Map getTagToRelation() { - return this.tagToRelation.values() - .stream() - .map(Relation::getOsmIdentifier) - .anyMatch(id -> id == osmIdentifier); + return this.tagToRelation; } } From 3fb516e63a6aca7017a78c15c1d60151cbcce48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Sun, 3 Jan 2021 21:45:06 +0100 Subject: [PATCH 35/36] Checkstyle test. --- .../BoundaryIntersectionCheckTest.java | 99 ------------------- 1 file changed, 99 deletions(-) diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java index 15a6e09d3..2f90a9e3b 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTest.java @@ -1,19 +1,12 @@ package org.openstreetmap.atlas.checks.validation.intersections; -import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.io.ParseException; -import org.locationtech.jts.io.WKTReader; import org.openstreetmap.atlas.checks.configuration.ConfigurationResolver; import org.openstreetmap.atlas.checks.validation.verifier.ConsumerBasedExpectedCheckVerifier; import org.openstreetmap.atlas.utilities.configuration.Configuration; -import java.io.FileInputStream; -import java.io.IOException; - /** * @author srachanski */ @@ -36,19 +29,6 @@ public void testInvalidThreeCrossingItemsAtlas() this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); } -// @Test -// public void testInvalidTwoCrossingBoundariesWithOnlyWayTags() -// { -// this.verifier.actual(this.setup.crossingBoundariesWithOnlyTagsOnWays(), -// new BoundaryIntersectionCheck(this.configuration)); -// this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); -// this.verifier.verify(flag -> -// { -// Assert.assertEquals(6, flag.getFlaggedObjects().size()); -// Assert.assertEquals(1, flag.getInstructions().split("\n").length); -// }); -// } - @Test public void testInvalidTwoCrossingItemsAtlas() { @@ -62,85 +42,6 @@ public void testInvalidTwoCrossingItemsAtlas() }); } -// //TODO remove -// @Test -// public void test(){ -// String area1 = "POLYGON((0 0, 3 0, 3 3, 3 0, 0 0))"; -// String area2 = "POLYGON((0 0, 2 0, 2 2, 2 0, 0 0))"; -// String area3 = "POLYGON((0 0, 3 1, 4 4, 1 3, 0 0))"; -// String line1 = "LINESTRING(1 1, 4 4)"; -// String line2 = "LINESTRING(1 4, 4 1)"; -// -//// BoundaryIntersectionCheck boundaryIntersectionCheck = new BoundaryIntersectionCheck(null); -// System.out.println(isCrossingNotTouching(area1, area2)); -// System.out.println(isCrossingNotTouching(area1, area3)); -// -// System.out.println("x"); -// } -// public boolean isCrossingNotTouching(final String wktFirst, -// final String wktSecond) -// { -// final WKTReader wktReader = new WKTReader(); -// try -// { -// final Geometry geometry1 = wktReader.read(wktFirst); -// final Geometry geometry2 = wktReader.read(wktSecond); -// if(!geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple()){ -// return false; -// } -// if(geometry1.intersects(geometry2)) -// { -// if(!this.isGeometryPairOfLineType(geometry1, geometry2)) -// { -// return this.isLineIntersectionNotTouch(geometry1, geometry2); -// } -// return this.isAreaIntersectionNotTouch(geometry1, geometry2); -// } -// } -// catch (final ParseException e) -// { -// return false; -// } -// return false; -// } -// -// private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) -// { -// return lineString.getGeometryType().equals("LineString") && lineString2.getGeometryType().equals("LineString"); -// } -// -// private boolean isLineIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) -// { -// return !geometry1.overlaps(geometry2); -// } -// -// private boolean isAreaIntersectionNotTouch(final Geometry geometry1, final Geometry geometry2) -// { -// return !(geometry1.covers(geometry2) || -// geometry1.coveredBy(geometry2) || -// geometry1.touches(geometry2)); -// } -// -// //TODO remove -// @Test -// public void intersectionTest() throws ParseException, IOException { -// FileInputStream fis = new FileInputStream("src/test/resources/area1"); -// String area1 = IOUtils.toString(fis, "UTF-8"); -//// String area1 = -// FileInputStream fis2 = new FileInputStream("src/test/resources/area2"); -// String area2 = IOUtils.toString(fis2, "UTF-8"); -//// String area2 = -//// String line1 = "LINESTRING(19.325022325433846 53.530197223167754,22.818674669183846 51.97440230490904,22.357248887933846 51.66200440966252)"; -//// String line2 = "LINESTRING(18.885569200433846 52.19044648242124,23.389963731683842 53.51713468341888)"; -// -// Geometry a1 = new WKTReader().read(area1); -// Geometry a2 = new WKTReader().read(area2); -//// Geometry l1 = new WKTReader().read(line1); -//// Geometry l2 = new WKTReader().read(line2); -// System.out.println(isCrossingNotTouching(area1, area2)); -// Assert.assertEquals(isCrossingNotTouching(area1, area2), false); -// } - @Test public void testInvalidTwoCrossingItemsWithEdgesAtlas() { From ae79a97c0f29489a7d0eb745503be49c991cffe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Racha=C5=84ski?= Date: Sun, 3 Jan 2021 21:54:13 +0100 Subject: [PATCH 36/36] Spotless java. --- .../BoundaryIntersectionCheck.java | 230 +++++++++--------- .../intersections/BoundaryPart.java | 1 - .../intersections/RelationBoundary.java | 20 +- .../BoundaryIntersectionCheckTestRule.java | 6 +- 4 files changed, 124 insertions(+), 133 deletions(-) diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java index 032205d8f..38f2e1108 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheck.java @@ -81,26 +81,19 @@ protected List getFallbackInstructions() return FALLBACK_INSTRUCTIONS; } - private void addInstruction(final Set instructions, - final BoundaryPart lineItem, - final long osmIdentifier, - final Coordinate[] intersectingPoints, - final String firstBoundaries, - final String secondBoundaries) + private void addInstruction(final Set instructions, final BoundaryPart lineItem, + final long osmIdentifier, final Coordinate[] intersectingPoints, + final String firstBoundaries, final String secondBoundaries) { - final String instruction = this.getLocalizedInstruction(INDEX, - firstBoundaries, - Long.toString(lineItem.getOsmIdentifier()), - secondBoundaries, - Long.toString(osmIdentifier), - this.coordinatesToList(intersectingPoints)); + final String instruction = this.getLocalizedInstruction(INDEX, firstBoundaries, + Long.toString(lineItem.getOsmIdentifier()), secondBoundaries, + Long.toString(osmIdentifier), this.coordinatesToList(intersectingPoints)); instructions.add(instruction); } private boolean checkAreaAsBoundary(final Area area, final Set boundaryTags) { - return area - .relations().stream() + return area.relations().stream() .anyMatch(relationToCheck -> BoundaryIntersectionCheck .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())) @@ -109,8 +102,7 @@ private boolean checkAreaAsBoundary(final Area area, final Set boundaryT private boolean checkLineItemAsBoundary(final LineItem lineItem, final Set boundaryTags) { - return lineItem - .relations().stream() + return lineItem.relations().stream() .anyMatch(relationToCheck -> BoundaryIntersectionCheck .isRelationTypeBoundaryWithBoundaryTag(relationToCheck) && boundaryTags.contains(relationToCheck.getTag(BOUNDARY).get())) @@ -127,45 +119,41 @@ private String coordinatesToList(final Coordinate[] locations) private Set getBoundaries(final LineItem currentLineItem) { final Set relations = currentLineItem.relations().stream() - .filter(relation -> relation instanceof MultiRelation) - .map(AtlasEntity::relations) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); + .filter(relation -> relation instanceof MultiRelation).map(AtlasEntity::relations) + .flatMap(Collection::stream).collect(Collectors.toSet()); relations.addAll(currentLineItem.relations()); - return relations.stream().filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) + return relations.stream() + .filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) .collect(Collectors.toSet()); } private Set getBoundaries(final Area area) { final Set relations = area.relations().stream() - .filter(relation -> relation instanceof MultiRelation) - .map(AtlasEntity::relations) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); + .filter(relation -> relation instanceof MultiRelation).map(AtlasEntity::relations) + .flatMap(Collection::stream).collect(Collectors.toSet()); relations.addAll(area.relations()); - return relations.stream().filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) + return relations.stream() + .filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) .collect(Collectors.toSet()); } private Set getBoundaryParts(final Relation relation) { - final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE, ItemType.LINE, ItemType.AREA); - return relationMemberLineItems - .stream().map(RelationMember::getEntity) - .map(entity -> - { - final String tag = entity.getTags().get(BOUNDARY); - final Set boundaryTags = entity.relations() - .stream() - .filter(currentRelation -> BOUNDARY.equals(currentRelation.getTag(TYPE).get())) - .map(currentRelation -> currentRelation.getTag(BOUNDARY).orElse(StringUtils.EMPTY)) - .collect(Collectors.toSet()); - boundaryTags.add(tag); - boundaryTags.remove(StringUtils.EMPTY); - return new BoundaryPart(entity, boundaryTags); - }) - .collect(Collectors.toSet()); + final RelationMemberList relationMemberLineItems = relation.membersOfType(ItemType.EDGE, + ItemType.LINE, ItemType.AREA); + return relationMemberLineItems.stream().map(RelationMember::getEntity).map(entity -> + { + final String tag = entity.getTags().get(BOUNDARY); + final Set boundaryTags = entity.relations().stream() + .filter(currentRelation -> BOUNDARY.equals(currentRelation.getTag(TYPE).get())) + .map(currentRelation -> currentRelation.getTag(BOUNDARY) + .orElse(StringUtils.EMPTY)) + .collect(Collectors.toSet()); + boundaryTags.add(tag); + boundaryTags.remove(StringUtils.EMPTY); + return new BoundaryPart(entity, boundaryTags); + }).collect(Collectors.toSet()); } private Geometry getGeometryForIntersection(final String wktFirst) throws ParseException @@ -180,8 +168,7 @@ private Geometry getGeometryForIntersection(final String wktFirst) throws ParseE return geometry1; } - private Coordinate[] getIntersectionPoints(final String wktFirst, - final String wktSecond) + private Coordinate[] getIntersectionPoints(final String wktFirst, final String wktSecond) { try { @@ -197,35 +184,38 @@ private Coordinate[] getIntersectionPoints(final String wktFirst, private List getLineItems(final LineItem lineItem) { - if(lineItem instanceof MultiLine) + if (lineItem instanceof MultiLine) { final List lines = new ArrayList<>(); - ((MultiLine) lineItem).getSubLines() - .forEach(lines::add); + ((MultiLine) lineItem).getSubLines().forEach(lines::add); return lines; } return Collections.singletonList(lineItem); } - private Predicate getPredicateForAreaSelection(final BoundaryPart boundaryPart, final Set boundaryTags) + private Predicate getPredicateForAreaSelection(final BoundaryPart boundaryPart, + final Set boundaryTags) { return areaToCheck -> { if (this.checkAreaAsBoundary(areaToCheck, boundaryTags)) { - return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), areaToCheck.toWkt()); + return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), + areaToCheck.toWkt()); } return false; }; } - private Predicate getPredicateForLineItemsSelection(final BoundaryPart boundaryPart, final Set boundaryTags) + private Predicate getPredicateForLineItemsSelection(final BoundaryPart boundaryPart, + final Set boundaryTags) { return lineItemToCheck -> { if (this.checkLineItemAsBoundary(lineItemToCheck, boundaryTags)) { - return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), lineItemToCheck.toWkt()); + return this.isCrossingNotTouching(boundaryPart.getWktGeometry(), + lineItemToCheck.toWkt()); } return false; }; @@ -234,12 +224,12 @@ private Predicate getPredicateForLineItemsSelection(final BoundaryPart private Map getRelationMap(final AtlasObject object) { final Map tagToRelation = new HashMap<>(); - if(object instanceof MultiRelation) + if (object instanceof MultiRelation) { - ((MultiRelation) object).relations() - .stream() + ((MultiRelation) object).relations().stream() .filter(BoundaryIntersectionCheck::isRelationTypeBoundaryWithBoundaryTag) - .forEach(relation -> tagToRelation.put(relation.getTag(BOUNDARY).get(), relation)); + .forEach(relation -> tagToRelation.put(relation.getTag(BOUNDARY).get(), + relation)); } tagToRelation.put(object.getTag(BOUNDARY).get(), (Relation) object); return tagToRelation; @@ -247,7 +237,8 @@ private Map getRelationMap(final AtlasObject object) private boolean isAnyGeometryInvalid(final Geometry geometry1, final Geometry geometry2) { - return !geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() || !geometry2.isSimple(); + return !geometry1.isValid() || !geometry1.isSimple() || !geometry2.isValid() + || !geometry2.isSimple(); } private boolean isCrossingNotTouching(final String wktFirst, final String wktSecond) @@ -257,11 +248,11 @@ private boolean isCrossingNotTouching(final String wktFirst, final String wktSec { final Geometry geometry1 = wktReader.read(wktFirst); final Geometry geometry2 = wktReader.read(wktSecond); - if(geometry1.equals(geometry2)) + if (geometry1.equals(geometry2)) { return false; } - if(this.isAnyGeometryInvalid(geometry1, geometry2)) + if (this.isAnyGeometryInvalid(geometry1, geometry2)) { return false; } @@ -275,54 +266,52 @@ private boolean isCrossingNotTouching(final String wktFirst, final String wktSec private boolean isGeometryPairOfLineType(final Geometry lineString, final Geometry lineString2) { - return lineString.getGeometryType().equals(Geometry.TYPENAME_LINESTRING) && lineString2.getGeometryType().equals(Geometry.TYPENAME_LINESTRING); + return lineString.getGeometryType().equals(Geometry.TYPENAME_LINESTRING) + && lineString2.getGeometryType().equals(Geometry.TYPENAME_LINESTRING); } private boolean isIntersectingNotTouching(final Geometry geometry1, final Geometry geometry2) { - return geometry1.intersects(geometry2) && - (geometry1.crosses(geometry2) || (geometry1.overlaps(geometry2) && !this.isGeometryPairOfLineType(geometry1, geometry2))); + return geometry1.intersects(geometry2) + && (geometry1.crosses(geometry2) || (geometry1.overlaps(geometry2) + && !this.isGeometryPairOfLineType(geometry1, geometry2))); } private String objectsToString(final Set objects) { - return objects - .stream() - .map(object -> Long.toString(object.getOsmIdentifier())) + return objects.stream().map(object -> Long.toString(object.getOsmIdentifier())) .collect(Collectors.joining(DELIMITER)); } private void processAreas(final RelationBoundary relationBoundary, - final Set instructions, - final Set objectsToFlag, - final Set matchedTags, - final BoundaryPart currentBoundaryPart, - final Iterable areasIntersecting, - final Set currentMatchedTags) + final Set instructions, final Set objectsToFlag, + final Set matchedTags, final BoundaryPart currentBoundaryPart, + final Iterable areasIntersecting, final Set currentMatchedTags) { areasIntersecting.forEach(area -> { - final Set matchingBoundaries = this.getBoundaries(area) - .stream() - .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).orElse(StringUtils.EMPTY))) - .filter(boundary -> !relationBoundary.containsRelationId(boundary.getOsmIdentifier())) + final Set matchingBoundaries = this.getBoundaries(area).stream() + .filter(boundary -> relationBoundary.getTagToRelation() + .containsKey(boundary.getTag(BOUNDARY).orElse(StringUtils.EMPTY))) + .filter(boundary -> !relationBoundary + .containsRelationId(boundary.getOsmIdentifier())) .collect(Collectors.toSet()); - if(!matchingBoundaries.isEmpty()) + if (!matchingBoundaries.isEmpty()) { - currentMatchedTags.addAll(matchingBoundaries - .stream() - .map(relation -> relation.getTag(BOUNDARY)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet())); + currentMatchedTags.addAll(matchingBoundaries.stream() + .map(relation -> relation.getTag(BOUNDARY)).filter(Optional::isPresent) + .map(Optional::get).collect(Collectors.toSet())); objectsToFlag.addAll(matchingBoundaries); - final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), - area.toWkt()); - final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); + final Coordinate[] intersectingPoints = this + .getIntersectionPoints(currentBoundaryPart.getWktGeometry(), area.toWkt()); + final String firstBoundaries = this.objectsToString( + relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); final String secondBoundaries = this.objectsToString(matchingBoundaries); - if(intersectingPoints.length != 0 && firstBoundaries.hashCode() < secondBoundaries.hashCode()) + if (intersectingPoints.length != 0 + && firstBoundaries.hashCode() < secondBoundaries.hashCode()) { - this.addInstruction(instructions, currentBoundaryPart, area.getOsmIdentifier(), intersectingPoints, firstBoundaries, secondBoundaries); + this.addInstruction(instructions, currentBoundaryPart, area.getOsmIdentifier(), + intersectingPoints, firstBoundaries, secondBoundaries); } } matchedTags.addAll(currentMatchedTags); @@ -330,41 +319,40 @@ private void processAreas(final RelationBoundary relationBoundary, } private void processLineItems(final RelationBoundary relationBoundary, - final Set instructions, - final Set objectsToFlag, - final Set matchedTags, - final BoundaryPart currentBoundaryPart, - final Iterable lineItemsIntersecting, - final Set currentMatchedTags) + final Set instructions, final Set objectsToFlag, + final Set matchedTags, final BoundaryPart currentBoundaryPart, + final Iterable lineItemsIntersecting, final Set currentMatchedTags) { lineItemsIntersecting.forEach(lineItem -> { - final Set matchingBoundaries = this.getBoundaries(lineItem) - .stream() - .filter(boundary -> relationBoundary.getTagToRelation().containsKey(boundary.getTag(BOUNDARY).get())) - .filter(boundary -> !relationBoundary.containsRelationId(boundary.getOsmIdentifier())) + final Set matchingBoundaries = this.getBoundaries(lineItem).stream() + .filter(boundary -> relationBoundary.getTagToRelation() + .containsKey(boundary.getTag(BOUNDARY).get())) + .filter(boundary -> !relationBoundary + .containsRelationId(boundary.getOsmIdentifier())) .collect(Collectors.toSet()); - if(!matchingBoundaries.isEmpty()) + if (!matchingBoundaries.isEmpty()) { - currentMatchedTags.addAll(matchingBoundaries - .stream() - .map(relation -> relation.getTag(BOUNDARY)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet())); + currentMatchedTags.addAll(matchingBoundaries.stream() + .map(relation -> relation.getTag(BOUNDARY)).filter(Optional::isPresent) + .map(Optional::get).collect(Collectors.toSet())); objectsToFlag.addAll(matchingBoundaries); final List lineItems = this.getLineItems(lineItem); lineItems.forEach(line -> { objectsToFlag.add(line); - final Coordinate[] intersectingPoints = this.getIntersectionPoints(currentBoundaryPart.getWktGeometry(), - line.toWkt()); - final String firstBoundaries = this.objectsToString(relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); + final Coordinate[] intersectingPoints = this.getIntersectionPoints( + currentBoundaryPart.getWktGeometry(), line.toWkt()); + final String firstBoundaries = this.objectsToString( + relationBoundary.getRelationsByBoundaryTags(currentMatchedTags)); final String secondBoundaries = this.objectsToString(matchingBoundaries); - if(intersectingPoints.length != 0 && firstBoundaries.hashCode() < secondBoundaries.hashCode()) + if (intersectingPoints.length != 0 + && firstBoundaries.hashCode() < secondBoundaries.hashCode()) { - this.addInstruction(instructions, currentBoundaryPart, line.getOsmIdentifier(), intersectingPoints, firstBoundaries, secondBoundaries); + this.addInstruction(instructions, currentBoundaryPart, + line.getOsmIdentifier(), intersectingPoints, firstBoundaries, + secondBoundaries); } }); } @@ -375,29 +363,35 @@ private void processLineItems(final RelationBoundary relationBoundary, private Optional processRelation(final AtlasObject object) { final Map tagToRelation = this.getRelationMap(object); - final RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, this.getBoundaryParts((Relation) object)); + final RelationBoundary relationBoundary = new RelationBoundary(tagToRelation, + this.getBoundaryParts((Relation) object)); final Set instructions = new HashSet<>(); final Set objectsToFlag = new HashSet<>(); final Set matchedTags = new HashSet<>(); - for(final BoundaryPart currentBoundaryPart : relationBoundary.getBoundaryParts()) + for (final BoundaryPart currentBoundaryPart : relationBoundary.getBoundaryParts()) { - final Iterable lineItemsIntersecting = object.getAtlas().lineItemsIntersecting(currentBoundaryPart.getBounds(), - this.getPredicateForLineItemsSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); - final Iterable areasIntersecting = object.getAtlas().areasIntersecting(currentBoundaryPart.getBounds(), - this.getPredicateForAreaSelection(currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); + final Iterable lineItemsIntersecting = object.getAtlas() + .lineItemsIntersecting(currentBoundaryPart.getBounds(), + this.getPredicateForLineItemsSelection(currentBoundaryPart, + relationBoundary.getTagToRelation().keySet())); + final Iterable areasIntersecting = object.getAtlas().areasIntersecting( + currentBoundaryPart.getBounds(), this.getPredicateForAreaSelection( + currentBoundaryPart, relationBoundary.getTagToRelation().keySet())); final Set currentMatchedTags = new HashSet<>(); - this.processLineItems(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, lineItemsIntersecting, currentMatchedTags); - this.processAreas(relationBoundary, instructions, objectsToFlag, matchedTags, currentBoundaryPart, areasIntersecting, currentMatchedTags); + this.processLineItems(relationBoundary, instructions, objectsToFlag, matchedTags, + currentBoundaryPart, lineItemsIntersecting, currentMatchedTags); + this.processAreas(relationBoundary, instructions, objectsToFlag, matchedTags, + currentBoundaryPart, areasIntersecting, currentMatchedTags); objectsToFlag.addAll(relationBoundary.getRelationsByBoundaryTags(matchedTags)); objectsToFlag.add(currentBoundaryPart.getAtlasEntity()); } - if(instructions.isEmpty()) + if (instructions.isEmpty()) { return Optional.empty(); } else - { + { final CheckFlag checkFlag = new CheckFlag(this.getTaskIdentifier(object)); instructions.forEach(checkFlag::addInstruction); checkFlag.addObjects(objectsToFlag); diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java index b5f1ed115..56dacf83a 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryPart.java @@ -5,7 +5,6 @@ import org.openstreetmap.atlas.geography.Rectangle; import org.openstreetmap.atlas.geography.atlas.items.AtlasEntity; - /** * @author srachanski */ diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java index cb878802a..6d938c290 100644 --- a/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/intersections/RelationBoundary.java @@ -11,11 +11,12 @@ */ public class RelationBoundary { - + private final Map tagToRelation; private final Set boundaryParts; - - public RelationBoundary(final Map tagToRelation, final Set boundaryParts) + + public RelationBoundary(final Map tagToRelation, + final Set boundaryParts) { this.tagToRelation = tagToRelation; this.boundaryParts = boundaryParts; @@ -23,9 +24,7 @@ public RelationBoundary(final Map tagToRelation, final Set id == osmIdentifier); } @@ -33,14 +32,11 @@ public Set getBoundaryParts() { return this.boundaryParts; } - + public Set getRelationsByBoundaryTags(final Set tags) { - return this.tagToRelation.keySet() - .stream() - .filter(tags::contains) - .map(this.tagToRelation::get) - .collect(Collectors.toSet()); + return this.tagToRelation.keySet().stream().filter(tags::contains) + .map(this.tagToRelation::get).collect(Collectors.toSet()); } public Map getTagToRelation() diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java index 2e2638bf9..feebebdf5 100644 --- a/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/intersections/BoundaryIntersectionCheckTestRule.java @@ -114,7 +114,8 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), @Node(coordinates = @Loc(value = COORD_20)) }, lines = { + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_20)) }, lines = { @Line(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_2), @Loc(value = COORD_3), @Loc(value = COORD_4), @Loc(value = COORD_1) }, id = LINE_ONE, tags = { "type=boundary", @@ -131,7 +132,8 @@ public class BoundaryIntersectionCheckTestRule extends CoreTestRule @TestAtlas(nodes = { @Node(coordinates = @Loc(value = COORD_1)), @Node(coordinates = @Loc(value = COORD_2)), @Node(coordinates = @Loc(value = COORD_3)), @Node(coordinates = @Loc(value = COORD_4)), @Node(coordinates = @Loc(value = COORD_5)), - @Node(coordinates = @Loc(value = COORD_6)), @Node(coordinates = @Loc(value = COORD_20)) }, edges = { + @Node(coordinates = @Loc(value = COORD_6)), + @Node(coordinates = @Loc(value = COORD_20)) }, edges = { @Edge(coordinates = { @Loc(value = COORD_1), @Loc(value = COORD_2), @Loc(value = COORD_3), @Loc(value = COORD_4), @Loc(value = COORD_1) }, id = EDGE_ONE),