source: josm/trunk/src/org/openstreetmap/josm/data/validation/tests/CrossingWays.java@ 12318

Last change on this file since 12318 was 11913, checked in by Don-vip, 7 years ago

sonar - squid:S1192 - String literals should not be duplicated

  • Property svn:eol-style set to native
File size: 10.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.validation.tests;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.geom.Point2D;
7import java.util.ArrayList;
8import java.util.HashMap;
9import java.util.List;
10import java.util.Map;
11import java.util.Objects;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.data.coor.EastNorth;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.data.osm.Relation;
17import org.openstreetmap.josm.data.osm.Way;
18import org.openstreetmap.josm.data.osm.WaySegment;
19import org.openstreetmap.josm.data.validation.OsmValidator;
20import org.openstreetmap.josm.data.validation.Severity;
21import org.openstreetmap.josm.data.validation.Test;
22import org.openstreetmap.josm.data.validation.TestError;
23import org.openstreetmap.josm.data.validation.util.ValUtil;
24import org.openstreetmap.josm.gui.progress.ProgressMonitor;
25
26/**
27 * Tests if there are segments that crosses in the same layer
28 *
29 * @author frsantos
30 */
31public abstract class CrossingWays extends Test {
32 protected static final int CROSSING_WAYS = 601;
33
34 static final String HIGHWAY = "highway";
35 static final String RAILWAY = "railway";
36 static final String WATERWAY = "waterway";
37
38 /** All way segments, grouped by cells */
39 private final Map<Point2D, List<WaySegment>> cellSegments = new HashMap<>(1000);
40 /** The already detected ways in error */
41 private final Map<List<Way>, List<WaySegment>> seenWays = new HashMap<>(50);
42
43 /**
44 * General crossing ways test.
45 */
46 public static class Ways extends CrossingWays {
47
48 /**
49 * Constructs a new crossing {@code Ways} test.
50 */
51 public Ways() {
52 super(tr("Crossing ways"));
53 }
54
55 @Override
56 public boolean isPrimitiveUsable(OsmPrimitive w) {
57 return super.isPrimitiveUsable(w)
58 && !isProposedOrAbandoned(w)
59 && (isHighway(w)
60 || w.hasKey(WATERWAY)
61 || isRailway(w)
62 || isCoastline(w)
63 || isBuilding(w));
64 }
65
66 @Override
67 boolean ignoreWaySegmentCombination(Way w1, Way w2) {
68 if (w1 == w2)
69 return false;
70 if (!Objects.equals(getLayer(w1), getLayer(w2))) {
71 return true;
72 }
73 if (w1.hasKey(HIGHWAY) && w2.hasKey(HIGHWAY) && !Objects.equals(w1.get("level"), w2.get("level"))) {
74 return true;
75 }
76 if (isSubwayOrTramOrRazed(w2)) {
77 return true;
78 }
79 if (isCoastline(w1) != isCoastline(w2)) {
80 return true;
81 }
82 if ((w1.hasTag(WATERWAY, "river", "stream", "canal", "drain", "ditch") && w2.hasTag(WATERWAY, "riverbank"))
83 || (w2.hasTag(WATERWAY, "river", "stream", "canal", "drain", "ditch") && w1.hasTag(WATERWAY, "riverbank"))) {
84 return true;
85 }
86 return isProposedOrAbandoned(w2);
87 }
88
89 @Override
90 String createMessage(Way w1, Way w2) {
91 if (isBuilding(w1)) {
92 return tr("Crossing buildings");
93 } else if (w1.hasKey(WATERWAY) && w2.hasKey(WATERWAY)) {
94 return tr("Crossing waterways");
95 } else if ((w1.hasKey(HIGHWAY) && w2.hasKey(WATERWAY))
96 || (w2.hasKey(HIGHWAY) && w1.hasKey(WATERWAY))) {
97 return tr("Crossing waterway/highway");
98 } else {
99 return tr("Crossing ways");
100 }
101 }
102 }
103
104 /**
105 * Crossing boundaries ways test.
106 */
107 public static class Boundaries extends CrossingWays {
108
109 /**
110 * Constructs a new crossing {@code Boundaries} test.
111 */
112 public Boundaries() {
113 super(tr("Crossing boundaries"));
114 }
115
116 @Override
117 public boolean isPrimitiveUsable(OsmPrimitive p) {
118 return super.isPrimitiveUsable(p) && p.hasKey("boundary")
119 && (!(p instanceof Relation) || (((Relation) p).isMultipolygon() && !((Relation) p).hasIncompleteMembers()));
120 }
121
122 @Override
123 boolean ignoreWaySegmentCombination(Way w1, Way w2) {
124 return !Objects.equals(w1.get("boundary"), w2.get("boundary"));
125 }
126
127 @Override
128 String createMessage(Way w1, Way w2) {
129 return tr("Crossing boundaries");
130 }
131
132 @Override
133 public void visit(Relation r) {
134 for (Way w : r.getMemberPrimitives(Way.class)) {
135 visit(w);
136 }
137 }
138 }
139
140 /**
141 * Crossing barriers ways test.
142 */
143 public static class Barrier extends CrossingWays {
144
145 /**
146 * Constructs a new crossing {@code Barrier} test.
147 */
148 public Barrier() {
149 super(tr("Crossing barriers"));
150 }
151
152 @Override
153 public boolean isPrimitiveUsable(OsmPrimitive p) {
154 return super.isPrimitiveUsable(p) && p.hasKey("barrier");
155 }
156
157 @Override
158 boolean ignoreWaySegmentCombination(Way w1, Way w2) {
159 return !Objects.equals(getLayer(w1), getLayer(w2));
160 }
161
162 @Override
163 String createMessage(Way w1, Way w2) {
164 return tr("Crossing barriers");
165 }
166 }
167
168 /**
169 * Self crossing ways test (for all the rest)
170 */
171 public static class SelfCrossing extends CrossingWays {
172 CrossingWays.Ways normalTest = new Ways();
173 CrossingWays.Barrier barrierTest = new Barrier();
174 CrossingWays.Boundaries boundariesTest = new Boundaries();
175
176 /**
177 * Constructs a new SelfIntersection test.
178 */
179 public SelfCrossing() {
180 super(tr("Self crossing"));
181 }
182
183 @Override
184 public boolean isPrimitiveUsable(OsmPrimitive p) {
185 return super.isPrimitiveUsable(p) && !(normalTest.isPrimitiveUsable(p) || barrierTest.isPrimitiveUsable(p)
186 || boundariesTest.isPrimitiveUsable(p));
187 }
188
189 @Override
190 boolean ignoreWaySegmentCombination(Way w1, Way w2) {
191 return w1 != w2; // should not happen
192 }
193
194 @Override
195 String createMessage(Way w1, Way w2) {
196 return tr("Self-crossing ways");
197 }
198 }
199
200 /**
201 * Constructs a new {@code CrossingWays} test.
202 * @param title The test title
203 * @since 6691
204 */
205 public CrossingWays(String title) {
206 super(title, tr("This test checks if two roads, railways, waterways or buildings crosses in the same layer, " +
207 "but are not connected by a node."));
208 }
209
210 @Override
211 public void startTest(ProgressMonitor monitor) {
212 super.startTest(monitor);
213 cellSegments.clear();
214 seenWays.clear();
215 }
216
217 @Override
218 public void endTest() {
219 super.endTest();
220 cellSegments.clear();
221 seenWays.clear();
222 }
223
224 static String getLayer(OsmPrimitive w) {
225 String layer1 = w.get("layer");
226 if ("0".equals(layer1)) {
227 layer1 = null; // 0 is default value for layer.
228 }
229 return layer1;
230 }
231
232 static boolean isCoastline(OsmPrimitive w) {
233 return w.hasTag("natural", "water", "coastline") || w.hasTag("landuse", "reservoir");
234 }
235
236 static boolean isHighway(OsmPrimitive w) {
237 return w.hasTagDifferent(HIGHWAY, "rest_area", "services");
238 }
239
240 static boolean isRailway(OsmPrimitive w) {
241 return w.hasKey(RAILWAY) && !isSubwayOrTramOrRazed(w);
242 }
243
244 static boolean isSubwayOrTramOrRazed(OsmPrimitive w) {
245 return w.hasTag(RAILWAY, "subway", "tram", "razed");
246 }
247
248 static boolean isProposedOrAbandoned(OsmPrimitive w) {
249 return w.hasTag(HIGHWAY, "proposed") || w.hasTag(RAILWAY, "proposed", "abandoned");
250 }
251
252 abstract boolean ignoreWaySegmentCombination(Way w1, Way w2);
253
254 abstract String createMessage(Way w1, Way w2);
255
256 @Override
257 public void visit(Way w) {
258 if (this instanceof SelfCrossing) {
259 // free memory, we are not interested in previous ways
260 cellSegments.clear();
261 seenWays.clear();
262 }
263
264 int nodesSize = w.getNodesCount();
265 for (int i = 0; i < nodesSize - 1; i++) {
266 final WaySegment es1 = new WaySegment(w, i);
267 final EastNorth en1 = es1.getFirstNode().getEastNorth();
268 final EastNorth en2 = es1.getSecondNode().getEastNorth();
269 if (en1 == null || en2 == null) {
270 Main.warn("Crossing ways test skipped "+es1);
271 continue;
272 }
273 for (List<WaySegment> segments : getSegments(cellSegments, en1, en2)) {
274 for (WaySegment es2 : segments) {
275 List<Way> prims;
276 List<WaySegment> highlight;
277
278 if (!es1.intersects(es2) || ignoreWaySegmentCombination(es1.way, es2.way)) {
279 continue;
280 }
281
282 prims = new ArrayList<>();
283 prims.add(es1.way);
284 if (es1.way != es2.way)
285 prims.add(es2.way);
286 if ((highlight = seenWays.get(prims)) == null) {
287 highlight = new ArrayList<>();
288 highlight.add(es1);
289 highlight.add(es2);
290
291 final String message = createMessage(es1.way, es2.way);
292 errors.add(TestError.builder(this, Severity.WARNING, CROSSING_WAYS)
293 .message(message)
294 .primitives(prims)
295 .highlightWaySegments(highlight)
296 .build());
297 seenWays.put(prims, highlight);
298 } else {
299 highlight.add(es1);
300 highlight.add(es2);
301 }
302 }
303 segments.add(es1);
304 }
305 }
306 }
307
308 /**
309 * Returns all the cells this segment crosses. Each cell contains the list
310 * of segments already processed
311 * @param cellSegments map with already collected way segments
312 * @param n1 The first EastNorth
313 * @param n2 The second EastNorth
314 * @return A list with all the cells the segment crosses
315 */
316 public static List<List<WaySegment>> getSegments(Map<Point2D, List<WaySegment>> cellSegments, EastNorth n1, EastNorth n2) {
317
318 List<List<WaySegment>> cells = new ArrayList<>();
319 for (Point2D cell : ValUtil.getSegmentCells(n1, n2, OsmValidator.getGridDetail())) {
320 List<WaySegment> segments = cellSegments.get(cell);
321 if (segments == null) {
322 segments = new ArrayList<>();
323 cellSegments.put(cell, segments);
324 }
325 cells.add(segments);
326 }
327 return cells;
328 }
329}
Note: See TracBrowser for help on using the repository browser.