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; 014import org.openstreetmap.josm.data.validation.tests.CrossingWays.SelfCrossing; 015 016/** 017 * Checks for self-intersecting ways. 018 */ 019public class SelfIntersectingWay extends Test { 020 021 protected static final int SELF_INTERSECT = 401; 022 023 /** 024 * Constructs a new {@code SelfIntersectingWay} test. 025 */ 026 public SelfIntersectingWay() { 027 super(tr("Self-intersecting ways"), 028 tr("This test checks for ways " + 029 "that contain some of their nodes more than once.")); 030 } 031 032 @Override 033 public void visit(Way w) { 034 int last = w.getNodesCount(); 035 if (last < 2) 036 return; 037 Set<Node> nodes = new HashSet<>(); 038 nodes.add(w.firstNode()); 039 int countFirst = 0; 040 int countLast = 0; 041 for (int i = 1; i < last; i++) { 042 Node n = w.getNode(i); 043 if (nodes.contains(n)) { 044 boolean ok = false; 045 if (n == w.firstNode()) { 046 if (countFirst++ == 0) 047 ok = true; 048 } else if (i + 1 == last) { 049 if (countLast++ == 0) 050 ok = true; 051 } 052 if (!ok || countFirst + countLast > 1) { 053 errors.add(TestError.builder(this, Severity.WARNING, SELF_INTERSECT) 054 .message(tr("Self-intersecting ways")) 055 .primitives(w) 056 .highlight(n) 057 .build()); 058 break; 059 } 060 } else { 061 nodes.add(n); 062 } 063 } 064 } 065 066 /** 067 * Check if the given way is self-intersecting 068 * @param way the way to check 069 * @return {@code true} if way contains some nodes more than once 070 * @see SelfCrossing 071 * @since 17386 072 */ 073 public static boolean isSelfIntersecting(Way way) { 074 SelfIntersectingWay test = new SelfIntersectingWay(); 075 test.visit(way); 076 return !test.errors.isEmpty(); 077 } 078}