source: josm/trunk/src/org/openstreetmap/josm/data/validation/tests/OverlappingWays.java@ 6872

Last change on this file since 6872 was 6872, checked in by Don-vip, 10 years ago

fix #9695 - ignore barrier in overlapping ways test

  • Property svn:eol-style set to native
File size: 8.8 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.Arrays;
8import java.util.Collection;
9import java.util.Collections;
10import java.util.Comparator;
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.List;
14import java.util.Map;
15import java.util.Set;
16import java.util.TreeSet;
17
18import org.openstreetmap.josm.data.osm.Node;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.OsmUtils;
21import org.openstreetmap.josm.data.osm.Relation;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.data.osm.WaySegment;
24import org.openstreetmap.josm.data.preferences.CollectionProperty;
25import org.openstreetmap.josm.data.validation.Severity;
26import org.openstreetmap.josm.data.validation.Test;
27import org.openstreetmap.josm.data.validation.TestError;
28import org.openstreetmap.josm.gui.progress.ProgressMonitor;
29import org.openstreetmap.josm.tools.MultiMap;
30import org.openstreetmap.josm.tools.Pair;
31import org.openstreetmap.josm.tools.Predicates;
32import org.openstreetmap.josm.tools.Utils;
33
34/**
35 * Tests if there are overlapping ways.
36 *
37 * @author frsantos
38 */
39public class OverlappingWays extends Test {
40
41 /** Bag of all way segments */
42 private MultiMap<Pair<Node,Node>, WaySegment> nodePairs;
43
44 protected static final int OVERLAPPING_HIGHWAY = 101;
45 protected static final int OVERLAPPING_RAILWAY = 102;
46 protected static final int OVERLAPPING_WAY = 103;
47 protected static final int OVERLAPPING_HIGHWAY_AREA = 111;
48 protected static final int OVERLAPPING_RAILWAY_AREA = 112;
49 protected static final int OVERLAPPING_WAY_AREA = 113;
50 protected static final int OVERLAPPING_AREA = 120;
51 protected static final int DUPLICATE_WAY_SEGMENT = 121;
52
53 protected static final CollectionProperty IGNORED_KEYS = new CollectionProperty(
54 "overlapping-ways.ignored-keys", Arrays.asList("barrier", "building"));
55
56 /** Constructor */
57 public OverlappingWays() {
58 super(tr("Overlapping ways"),
59 tr("This test checks that a connection between two nodes "
60 + "is not used by more than one way."));
61 }
62
63 @Override
64 public void startTest(ProgressMonitor monitor) {
65 super.startTest(monitor);
66 nodePairs = new MultiMap<Pair<Node,Node>, WaySegment>(1000);
67 }
68
69 private boolean parentMultipolygonConcernsArea(OsmPrimitive p) {
70 for (Relation r : OsmPrimitive.getFilteredList(p.getReferrers(), Relation.class)) {
71 if (r.concernsArea() ) {
72 return true;
73 }
74 }
75 return false;
76 }
77
78 @Override
79 public void endTest() {
80 Map<List<Way>, Set<WaySegment>> seenWays = new HashMap<List<Way>, Set<WaySegment>>(500);
81
82 Collection<TestError> preliminaryErrors = new ArrayList<TestError>();
83 for (Set<WaySegment> duplicated : nodePairs.values()) {
84 int ways = duplicated.size();
85
86 if (ways > 1) {
87 List<OsmPrimitive> prims = new ArrayList<OsmPrimitive>();
88 List<Way> currentWays = new ArrayList<Way>();
89 Collection<WaySegment> highlight;
90 int highway = 0;
91 int railway = 0;
92 int area = 0;
93
94 for (WaySegment ws : duplicated) {
95 if (ws.way.get("highway") != null) {
96 highway++;
97 } else if (ws.way.get("railway") != null) {
98 railway++;
99 }
100 Boolean ar = OsmUtils.getOsmBoolean(ws.way.get("area"));
101 if (ar != null && ar) {
102 area++;
103 }
104 if (ws.way.concernsArea() || parentMultipolygonConcernsArea(ws.way)) {
105 area++;
106 ways--;
107 }
108
109 prims.add(ws.way);
110 currentWays.add(ws.way);
111 }
112 /* These ways not seen before
113 * If two or more of the overlapping ways are
114 * highways or railways mark a separate error
115 */
116 if ((highlight = seenWays.get(currentWays)) == null) {
117 String errortype;
118 int type;
119
120 if (area > 0) {
121 if (ways == 0 || duplicated.size() == area) {
122 errortype = tr("Areas share segment");
123 type = OVERLAPPING_AREA;
124 } else if (highway == ways) {
125 errortype = tr("Highways share segment with area");
126 type = OVERLAPPING_HIGHWAY_AREA;
127 } else if (railway == ways) {
128 errortype = tr("Railways share segment with area");
129 type = OVERLAPPING_RAILWAY_AREA;
130 } else {
131 errortype = tr("Ways share segment with area");
132 type = OVERLAPPING_WAY_AREA;
133 }
134 }
135 else if (highway == ways) {
136 errortype = tr("Overlapping highways");
137 type = OVERLAPPING_HIGHWAY;
138 } else if (railway == ways) {
139 errortype = tr("Overlapping railways");
140 type = OVERLAPPING_RAILWAY;
141 } else {
142 errortype = tr("Overlapping ways");
143 type = OVERLAPPING_WAY;
144 }
145
146 preliminaryErrors.add(new TestError(this,
147 type < OVERLAPPING_HIGHWAY_AREA ? Severity.WARNING : Severity.OTHER,
148 errortype, type, prims, duplicated));
149 seenWays.put(currentWays, duplicated);
150 } else { /* way seen, mark highlight layer only */
151 for (WaySegment ws : duplicated) {
152 highlight.add(ws);
153 }
154 }
155 }
156 }
157
158 // see ticket #9598 - only report if at least 3 segments are shared
159 for (TestError error : preliminaryErrors) {
160 if (error.getHighlighted().size() / error.getPrimitives().size() >= 3) {
161 boolean ignore = false;
162 for (String ignoredKey : IGNORED_KEYS.get()) {
163 if (Utils.exists(error.getPrimitives(), Predicates.hasKey(ignoredKey))) {
164 ignore = true;
165 break;
166 }
167 }
168 if (!ignore) {
169 errors.add(error);
170 }
171 }
172 }
173
174 super.endTest();
175 nodePairs = null;
176 }
177
178 protected static Set<WaySegment> checkDuplicateWaySegment(Way w) {
179 // test for ticket #4959
180 Set<WaySegment> segments = new TreeSet<WaySegment>(new Comparator<WaySegment>() {
181 @Override
182 public int compare(WaySegment o1, WaySegment o2) {
183 final List<Node> n1 = Arrays.asList(o1.getFirstNode(), o1.getSecondNode());
184 final List<Node> n2 = Arrays.asList(o2.getFirstNode(), o2.getSecondNode());
185 Collections.sort(n1);
186 Collections.sort(n2);
187 final int first = n1.get(0).compareTo(n2.get(0));
188 final int second = n1.get(1).compareTo(n2.get(1));
189 return first != 0 ? first : second;
190 }
191 });
192 final Set<WaySegment> duplicateWaySegments = new HashSet<WaySegment>();
193
194 for (int i = 0; i < w.getNodesCount() - 1; i++) {
195 final WaySegment segment = new WaySegment(w, i);
196 final boolean wasInSet = !segments.add(segment);
197 if (wasInSet) {
198 duplicateWaySegments.add(segment);
199 }
200 }
201 if (duplicateWaySegments.size() > 1) {
202 return duplicateWaySegments;
203 } else {
204 return null;
205 }
206 }
207
208 @Override
209 public void visit(Way w) {
210
211 final Set<WaySegment> duplicateWaySegment = checkDuplicateWaySegment(w);
212 if (duplicateWaySegment != null) {
213 errors.add(new TestError(this, Severity.ERROR, tr("Way contains segment twice"),
214 DUPLICATE_WAY_SEGMENT, Collections.singleton(w), duplicateWaySegment));
215 return;
216 }
217
218 Node lastN = null;
219 int i = -2;
220 for (Node n : w.getNodes()) {
221 i++;
222 if (lastN == null) {
223 lastN = n;
224 continue;
225 }
226 nodePairs.put(Pair.sort(new Pair<Node,Node>(lastN, n)),
227 new WaySegment(w, i));
228 lastN = n;
229 }
230 }
231}
Note: See TracBrowser for help on using the repository browser.