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