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

Last change on this file since 6722 was 6722, checked in by simon04, 10 years ago

fix #9577 - Remove automatic fix for "Way contains segment twice"

Since we highlight duplicate segments since r6694, it seems easier/safer to let the user manually fix this (rare?) error.

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