source: josm/trunk/src/org/openstreetmap/josm/data/validation/tests/Coastlines.java@ 3775

Last change on this file since 3775 was 3698, checked in by bastiK, 13 years ago

fixed #5701 - validator: false error "unconnected coastline" reported before upload

  • Property svn:eol-style set to native
File size: 8.0 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.awt.geom.Area;
7import java.util.ArrayList;
8import java.util.Collection;
9import java.util.Collections;
10import java.util.LinkedList;
11import java.util.List;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.command.ChangeCommand;
15import org.openstreetmap.josm.command.Command;
16import org.openstreetmap.josm.data.osm.OsmPrimitive;
17import org.openstreetmap.josm.data.osm.Node;
18import org.openstreetmap.josm.data.osm.Way;
19import org.openstreetmap.josm.data.validation.Severity;
20import org.openstreetmap.josm.data.validation.Test;
21import org.openstreetmap.josm.data.validation.TestError;
22import org.openstreetmap.josm.gui.layer.OsmDataLayer;
23import org.openstreetmap.josm.gui.progress.ProgressMonitor;
24
25/**
26 * Check coastlines for errors
27 *
28 * @author frsantos
29 * @author Teemu Koskinen
30 */
31public class Coastlines extends Test {
32
33 protected static int UNORDERED_COASTLINE = 901;
34 protected static int REVERSED_COASTLINE = 902;
35 protected static int UNCONNECTED_COASTLINE = 903;
36
37 private List<Way> coastlines;
38
39 private Area downloadedArea = null;
40
41 /**
42 * Constructor
43 */
44 public Coastlines() {
45 super(tr("Coastlines."),
46 tr("This test checks that coastlines are correct."));
47 }
48
49 @Override
50 public void startTest(ProgressMonitor monitor) {
51
52 super.startTest(monitor);
53
54 OsmDataLayer layer = Main.map.mapView.getEditLayer();
55
56 if (layer != null) {
57 downloadedArea = layer.data.getDataSourceArea();
58 }
59
60 coastlines = new LinkedList<Way>();
61 }
62
63 @Override
64 public void endTest() {
65 for (Way c1 : coastlines) {
66 Node head = c1.firstNode();
67 Node tail = c1.lastNode();
68
69 if (head.equals(tail)) {
70 continue;
71 }
72
73 int headWays = 0;
74 int tailWays = 0;
75 boolean headReversed = false;
76 boolean tailReversed = false;
77 boolean headUnordered = false;
78 boolean tailUnordered = false;
79 Way next = null;
80 Way prev = null;
81
82 for (Way c2 : coastlines) {
83 if (c1 == c2) {
84 continue;
85 }
86
87 if (c2.containsNode(head)) {
88 headWays++;
89 next = c2;
90
91 if (head.equals(c2.firstNode())) {
92 headReversed = true;
93 } else if (!head.equals(c2.lastNode())) {
94 headUnordered = true;
95 }
96 }
97
98 if (c2.containsNode(tail)) {
99 tailWays++;
100 prev = c2;
101
102 if (tail.equals(c2.lastNode())) {
103 tailReversed = true;
104 } else if (!tail.equals(c2.firstNode())) {
105 tailUnordered = true;
106 }
107 }
108 }
109
110 // To avoid false positives on upload (only modified primitives
111 // are visited), we have to check possible connection to ways
112 // that are not in the set of validated primitives.
113 if (headWays == 0) {
114 Collection<OsmPrimitive> refs = head.getReferrers();
115 for (OsmPrimitive ref : refs) {
116 if (ref != c1 && isCoastline(ref)) {
117 // ref cannot be in <code>coastlines</code>, otherwise we would
118 // have picked it up already
119 headWays++;
120 next = (Way) ref;
121
122 if (head.equals(next.firstNode())) {
123 headReversed = true;
124 } else if (!head.equals(next.lastNode())) {
125 headUnordered = true;
126 }
127 }
128 }
129 }
130 if (tailWays == 0) {
131 Collection<OsmPrimitive> refs = tail.getReferrers();
132 for (OsmPrimitive ref : refs) {
133 if (ref != c1 && isCoastline(ref)) {
134 tailWays++;
135 prev = (Way) ref;
136
137 if (tail.equals(prev.lastNode())) {
138 tailReversed = true;
139 } else if (!tail.equals(prev.firstNode())) {
140 tailUnordered = true;
141 }
142 }
143 }
144 }
145
146 List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
147 primitives.add(c1);
148
149 if (headWays == 0 || tailWays == 0) {
150 List<OsmPrimitive> highlight = new ArrayList<OsmPrimitive>();
151
152 System.out.println("Unconnected coastline: " + c1.getId());
153 if (headWays == 0 && (downloadedArea == null || downloadedArea.contains(head.getCoor()))) {
154 System.out.println("headways: " +headWays+ " node: " + head.toString());
155 highlight.add(head);
156 }
157 if (tailWays == 0 && (downloadedArea == null || downloadedArea.contains(tail.getCoor()))) {
158 System.out.println("tailways: " +tailWays+ " tail: " + tail.toString());
159 highlight.add(tail);
160 }
161
162 if (highlight.size() > 0) {
163 errors.add(new TestError(this, Severity.ERROR, tr("Unconnected coastline"),
164 UNCONNECTED_COASTLINE, primitives, highlight));
165 }
166 }
167
168 boolean unordered = false;
169 boolean reversed = headWays == 1 && headReversed && tailWays == 1 && tailReversed;
170
171 if (headWays > 1 || tailWays > 1) {
172 unordered = true;
173 } else if (headUnordered || tailUnordered) {
174 unordered = true;
175 } else if (reversed && next == prev) {
176 unordered = true;
177 }
178
179 if (unordered) {
180 List<OsmPrimitive> highlight = new ArrayList<OsmPrimitive>();
181
182 System.out.println("Unordered coastline: " + c1.toString());
183 if (headWays > 1 || headUnordered || reversed) {
184 System.out.println("head: " + head.toString());
185 highlight.add(head);
186 }
187 if (tailWays > 1 || tailUnordered || reversed) {
188 System.out.println("tail: " + tail.toString());
189 highlight.add(tail);
190 }
191
192 errors.add(new TestError(this, Severity.ERROR, tr("Unordered coastline"),
193 UNORDERED_COASTLINE, primitives, highlight));
194 }
195 else if (reversed) {
196 errors.add(new TestError(this, Severity.ERROR, tr("Reversed coastline"),
197 REVERSED_COASTLINE, primitives));
198 }
199 }
200
201 coastlines = null;
202 downloadedArea = null;
203
204 super.endTest();
205 }
206
207 @Override
208 public void visit(Way way) {
209 if (!way.isUsable())
210 return;
211
212 if (isCoastline(way)) {
213 coastlines.add(way);
214 }
215 }
216
217 private static boolean isCoastline(OsmPrimitive osm) {
218 return osm instanceof Way && "coastline".equals(osm.get("natural"));
219 }
220
221 @Override
222 public Command fixError(TestError testError) {
223 if (isFixable(testError)) {
224 Way way = (Way) testError.getPrimitives().iterator().next();
225 Way newWay = new Way(way);
226
227 List<Node> nodesCopy = newWay.getNodes();
228 Collections.reverse(nodesCopy);
229 newWay.setNodes(nodesCopy);
230
231 return new ChangeCommand(way, newWay);
232 }
233 return null;
234 }
235
236 @Override
237 public boolean isFixable(TestError testError) {
238 if (testError.getTester() instanceof Coastlines)
239 return (testError.getCode() == REVERSED_COASTLINE);
240
241 return false;
242 }
243}
Note: See TracBrowser for help on using the repository browser.