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

Last change on this file since 4043 was 4043, checked in by stoecker, 13 years ago

fix #6153 - spelling fixes

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