001// License: GPL. See LICENSE file for details. 002package org.openstreetmap.josm.data.validation.tests; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.util.Arrays; 007import java.util.Collections; 008import java.util.Iterator; 009 010import org.openstreetmap.josm.command.ChangeCommand; 011import org.openstreetmap.josm.command.Command; 012import org.openstreetmap.josm.data.osm.Node; 013import org.openstreetmap.josm.data.osm.OsmPrimitive; 014import org.openstreetmap.josm.data.osm.Way; 015import org.openstreetmap.josm.data.validation.Severity; 016import org.openstreetmap.josm.data.validation.Test; 017import org.openstreetmap.josm.data.validation.TestError; 018 019/** 020 * Checks for ways with identical consecutive nodes. 021 * @since 3669 022 */ 023public class DuplicatedWayNodes extends Test { 024 protected static final int DUPLICATE_WAY_NODE = 501; 025 026 /** 027 * Constructs a new {@code DuplicatedWayNodes} test. 028 */ 029 public DuplicatedWayNodes() { 030 super(tr("Duplicated way nodes"), 031 tr("Checks for ways with identical consecutive nodes.")); 032 } 033 034 @Override 035 public void visit(Way w) { 036 if (!w.isUsable()) return; 037 038 Node lastN = null; 039 for (Node n : w.getNodes()) { 040 if (lastN == null) { 041 lastN = n; 042 continue; 043 } 044 if (lastN == n) { 045 errors.add(new TestError(this, Severity.ERROR, tr("Duplicated way nodes"), DUPLICATE_WAY_NODE, 046 Arrays.asList(w), Arrays.asList(n))); 047 break; 048 } 049 lastN = n; 050 } 051 } 052 053 @Override 054 public Command fixError(TestError testError) { 055 // primitives list can be empty if all primitives have been purged 056 Iterator<? extends OsmPrimitive> it = testError.getPrimitives().iterator(); 057 if (it.hasNext()) { 058 Way w = (Way) it.next(); 059 Way wnew = new Way(w); 060 wnew.setNodes(null); 061 Node lastN = null; 062 for (Node n : w.getNodes()) { 063 if (lastN == null) { 064 wnew.addNode(n); 065 } else if (n == lastN) { 066 // Skip this node 067 } else { 068 wnew.addNode(n); 069 } 070 lastN = n; 071 } 072 if (wnew.getNodesCount() < 2) 073 // Empty way, delete 074 return deletePrimitivesIfNeeded(Collections.singleton(w)); 075 else 076 return new ChangeCommand(w, wnew); 077 } 078 return null; 079 } 080 081 @Override 082 public boolean isFixable(TestError testError) { 083 return testError.getTester() instanceof DuplicatedWayNodes; 084 } 085}