// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.data.validation.tests; import static org.openstreetmap.josm.tools.I18n.tr; import java.util.HashSet; import java.util.Set; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.validation.Severity; import org.openstreetmap.josm.data.validation.Test; import org.openstreetmap.josm.data.validation.TestError; /** * Checks for self-intersecting ways. */ public class SelfIntersectingWay extends Test { protected static final int SELF_INTERSECT = 401; /** * Constructs a new {@code SelfIntersectingWay} test. */ public SelfIntersectingWay() { super(tr("Self-intersecting ways"), tr("This test checks for ways " + "that contain some of their nodes more than once.")); } @Override public void visit(Way w) { int last = w.getNodesCount(); if (last < 2) return; Set<Node> nodes = new HashSet<>(); nodes.add(w.firstNode()); int countFirst = 0; int countLast = 0; for (int i = 1; i < last; i++) { Node n = w.getNode(i); if (nodes.contains(n)) { boolean ok = false; if (n == w.firstNode()) { if (countFirst++ == 0) ok = true; } else if (i + 1 == last) { if (countLast++ == 0) ok = true; } if (!ok || countFirst + countLast > 1) { errors.add(TestError.builder(this, Severity.WARNING, SELF_INTERSECT) .message(tr("Self-intersecting ways")) .primitives(w) .highlight(n) .build()); break; } } else { nodes.add(n); } } } }