source: josm/trunk/src/org/openstreetmap/josm/data/validation/tests/DuplicateWay.java@ 3669

Last change on this file since 3669 was 3669, checked in by bastiK, 14 years ago

add validator plugin to josm core. Original author: Francisco R. Santos (frsantos); major contributions by bilbo, daeron, delta_foxtrot, imi, jttt, jrreid, gabriel, guggis, pieren, rrankin, skela, stoecker, stotz and others

  • Property svn:eol-style set to native
File size: 6.3 KB
Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.data.validation.tests;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.Collection;
7import java.util.HashSet;
8import java.util.LinkedList;
9import java.util.List;
10import java.util.Map;
11import java.util.Vector;
12
13import org.openstreetmap.josm.command.ChangeCommand;
14import org.openstreetmap.josm.command.Command;
15import org.openstreetmap.josm.command.DeleteCommand;
16import org.openstreetmap.josm.command.SequenceCommand;
17import org.openstreetmap.josm.data.coor.LatLon;
18import org.openstreetmap.josm.data.osm.Node;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.Relation;
21import org.openstreetmap.josm.data.osm.RelationMember;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.data.validation.Severity;
24import org.openstreetmap.josm.data.validation.Test;
25import org.openstreetmap.josm.data.validation.TestError;
26import org.openstreetmap.josm.data.validation.util.Bag;
27import org.openstreetmap.josm.gui.progress.ProgressMonitor;
28
29/**
30 * Tests if there are duplicate ways
31 */
32public class DuplicateWay extends Test
33{
34
35 private static class WayPair {
36 public List<LatLon> coor;
37 public Map<String, String> keys;
38 public WayPair(List<LatLon> _coor,Map<String, String> _keys) {
39 coor=_coor;
40 keys=_keys;
41 }
42 @Override
43 public int hashCode() {
44 return coor.hashCode()+keys.hashCode();
45 }
46 @Override
47 public boolean equals(Object obj) {
48 if (!(obj instanceof WayPair)) return false;
49 WayPair wp = (WayPair) obj;
50 return wp.coor.equals(coor) && wp.keys.equals(keys);
51 }
52 }
53
54 protected static int DUPLICATE_WAY = 1401;
55
56 /** Bag of all ways */
57 Bag<WayPair, OsmPrimitive> ways;
58
59 /**
60 * Constructor
61 */
62 public DuplicateWay()
63 {
64 super(tr("Duplicated ways")+".",
65 tr("This test checks that there are no ways with same tags and same node coordinates."));
66 }
67
68
69 @Override
70 public void startTest(ProgressMonitor monitor)
71 {
72 super.startTest(monitor);
73 ways = new Bag<WayPair, OsmPrimitive>(1000);
74 }
75
76 @Override
77 public void endTest()
78 {
79 super.endTest();
80 for(List<OsmPrimitive> duplicated : ways.values() )
81 {
82 if( duplicated.size() > 1)
83 {
84 TestError testError = new TestError(this, Severity.ERROR, tr("Duplicated ways"), DUPLICATE_WAY, duplicated);
85 errors.add( testError );
86 }
87 }
88 ways = null;
89 }
90
91 @Override
92 public void visit(Way w)
93 {
94 if( !w.isUsable() )
95 return;
96 List<Node> wNodes=w.getNodes();
97 Vector<LatLon> wLat=new Vector<LatLon>(wNodes.size());
98 for(int i=0;i<wNodes.size();i++) {
99 wLat.add(wNodes.get(i).getCoor());
100 }
101 Map<String, String> wkeys=w.getKeys();
102 wkeys.remove("created_by");
103 WayPair wKey=new WayPair(wLat,wkeys);
104 ways.add(wKey, w);
105 }
106
107 /**
108 * Fix the error by removing all but one instance of duplicate ways
109 */
110 @Override
111 public Command fixError(TestError testError)
112 {
113 Collection<? extends OsmPrimitive> sel = testError.getPrimitives();
114 HashSet<Way> ways = new HashSet<Way>();
115
116 for (OsmPrimitive osm : sel)
117 if (osm instanceof Way)
118 ways.add((Way)osm);
119
120 if( ways.size() < 2 )
121 return null;
122
123 long idToKeep = 0;
124 Way wayToKeep = ways.iterator().next();
125 // Only one way will be kept - the one with lowest positive ID, if such exist
126 // or one "at random" if no such exists. Rest of the ways will be deleted
127 for (Way w: ways) {
128 if (!w.isNew()) {
129 if (idToKeep == 0 || w.getId() < idToKeep) {
130 idToKeep = w.getId();
131 wayToKeep = w;
132 }
133 }
134 }
135
136 // Find the way that is member of one or more relations. (If any)
137 Way wayWithRelations = null;
138 List<Relation> relations = null;
139 for (Way w : ways) {
140 List<Relation> rel = OsmPrimitive.getFilteredList(w.getReferrers(), Relation.class);
141 if (!rel.isEmpty()) {
142 if (wayWithRelations != null)
143 throw new AssertionError("Cannot fix duplicate Ways: More than one way is relation member.");
144 wayWithRelations = w;
145 relations = rel;
146 }
147 }
148
149 Collection<Command> commands = new LinkedList<Command>();
150
151 // Fix relations.
152 if (wayWithRelations != null && wayToKeep != wayWithRelations) {
153 for (Relation rel : relations) {
154 Relation newRel = new Relation(rel);
155 for (int i = 0; i < newRel.getMembers().size(); ++i) {
156 RelationMember m = newRel.getMember(i);
157 if (wayWithRelations.equals(m.getMember())) {
158 newRel.setMember(i, new RelationMember(m.getRole(), wayToKeep));
159 }
160 }
161 commands.add(new ChangeCommand(rel, newRel));
162 }
163 }
164
165 //Delete all ways in the list
166 //Note: nodes are not deleted, these can be detected and deleted at next pass
167 ways.remove(wayToKeep);
168 commands.add(new DeleteCommand(ways));
169 return new SequenceCommand(tr("Delete duplicate ways"), commands);
170 }
171
172 @Override
173 public boolean isFixable(TestError testError)
174 {
175 if (!(testError.getTester() instanceof DuplicateWay))
176 return false;
177
178 // We fix it only if there is no more than one way that is relation member.
179 Collection<? extends OsmPrimitive> sel = testError.getPrimitives();
180 HashSet<Way> ways = new HashSet<Way>();
181
182 for (OsmPrimitive osm : sel)
183 if (osm instanceof Way)
184 ways.add((Way)osm);
185
186 if (ways.size() < 2)
187 return false;
188
189 int waysWithRelations = 0;
190 for (Way w : ways) {
191 List<Relation> rel = OsmPrimitive.getFilteredList(w.getReferrers(), Relation.class);
192 if (!rel.isEmpty()) {
193 ++waysWithRelations;
194 }
195 }
196 return (waysWithRelations <= 1);
197 }
198}
Note: See TracBrowser for help on using the repository browser.