001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.validation.tests; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.util.HashSet; 007import java.util.Set; 008 009import org.openstreetmap.josm.data.osm.Node; 010import org.openstreetmap.josm.data.osm.Way; 011import org.openstreetmap.josm.data.validation.Severity; 012import org.openstreetmap.josm.data.validation.Test; 013import org.openstreetmap.josm.data.validation.TestError; 014 015/** 016 * Checks for self-intersecting ways. 017 */ 018public class SelfIntersectingWay extends Test { 019 020 protected static final int SELF_INTERSECT = 401; 021 022 /** 023 * Constructs a new {@code SelfIntersectingWay} test. 024 */ 025 public SelfIntersectingWay() { 026 super(tr("Self-intersecting ways"), 027 tr("This test checks for ways " + 028 "that contain some of their nodes more than once.")); 029 } 030 031 @Override 032 public void visit(Way w) { 033 int last = w.getNodesCount(); 034 if (last < 2) 035 return; 036 Set<Node> nodes = new HashSet<>(); 037 nodes.add(w.firstNode()); 038 int countFirst = 0; 039 int countLast = 0; 040 for (int i = 1; i < last; i++) { 041 Node n = w.getNode(i); 042 if (nodes.contains(n)) { 043 boolean ok = false; 044 if (n == w.firstNode()) { 045 if (countFirst++ == 0) 046 ok = true; 047 } else if (i + 1 == last) { 048 if (countLast++ == 0) 049 ok = true; 050 } 051 if (!ok || countFirst + countLast > 1) { 052 errors.add(TestError.builder(this, Severity.WARNING, SELF_INTERSECT) 053 .message(tr("Self-intersecting ways")) 054 .primitives(w) 055 .highlight(n) 056 .build()); 057 break; 058 } 059 } else { 060 nodes.add(n); 061 } 062 } 063 } 064}