Changeset 10991 in josm for trunk/src/org
- Timestamp:
- 2016-09-11T02:15:50+02:00 (8 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/tests/Coastlines.java
r10448 r10991 8 8 import java.util.Collection; 9 9 import java.util.Collections; 10 import java.util.HashSet; 10 11 import java.util.Iterator; 11 12 import java.util.LinkedList; 12 13 import java.util.List; 13 14 import org.openstreetmap.josm.Main; 14 import java.util.Set; 15 15 16 import org.openstreetmap.josm.command.ChangeCommand; 16 17 import org.openstreetmap.josm.command.Command; … … 21 22 import org.openstreetmap.josm.data.validation.Test; 22 23 import org.openstreetmap.josm.data.validation.TestError; 23 import org.openstreetmap.josm.gui.layer.OsmDataLayer;24 24 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 25 import org.openstreetmap.josm.tools.Geometry; 25 26 26 27 /** … … 29 30 * @author frsantos 30 31 * @author Teemu Koskinen 32 * @author Gerd Petermann 31 33 */ 32 34 public class Coastlines extends Test { … … 35 37 protected static final int REVERSED_COASTLINE = 902; 36 38 protected static final int UNCONNECTED_COASTLINE = 903; 37 38 private List<Way> coastlines; 39 40 private Area downloadedArea; 39 protected static final int WRONG_ORDER_COASTLINE = 904; 40 41 private List<Way> coastlineWays; 41 42 42 43 /** … … 49 50 @Override 50 51 public void startTest(ProgressMonitor monitor) { 51 52 52 super.startTest(monitor); 53 54 OsmDataLayer layer = Main.getLayerManager().getEditLayer(); 55 56 if (layer != null) { 57 downloadedArea = layer.data.getDataSourceArea(); 58 } 59 60 coastlines = new LinkedList<>(); 53 coastlineWays = new LinkedList<>(); 61 54 } 62 55 63 56 @Override 64 57 public void endTest() { 65 for (Way c1 : coastlines) { 66 Node head = c1.firstNode(); 67 Node tail = c1.lastNode(); 68 69 if (c1.getNodesCount() == 0 || 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; 58 checkConnections(); 59 checkDirection(); 60 coastlineWays = null; 61 super.endTest(); 62 } 63 64 /** 65 * Check connections between coastline ways. 66 * The nodes of a coastline way have to fullfil these rules: 67 * 1) the first node must be connected to the last node of a coastline way (which might be the same way) 68 * 2) the last node must be connected to the first node of a coastline way (which might be the same way) 69 * 3) all other nodes must not be connected to a coastline way 70 * 4) the number of referencing coastline ways must be 1 or 2 71 * Nodes outside the download area are special cases, we may not know enough about the connected ways. 72 */ 73 private void checkConnections() { 74 Area downloadedArea = null; 75 for (Way w : coastlineWays) { 76 if (downloadedArea == null) { 77 downloadedArea = w.getDataSet().getDataSourceArea(); 78 } 79 int numNodes = w.getNodesCount(); 80 for (int i = 0; i < numNodes; i++) { 81 Node n = w.getNode(i); 82 List<OsmPrimitive> refs = n.getReferrers(); 83 Set<Way> connectedWays = new HashSet<>(); 84 for (OsmPrimitive p : refs) { 85 if (p != w && isCoastline(p)) { 86 connectedWays.add((Way) p); 87 } 88 } 89 if (i == 0) { 90 if (connectedWays.isEmpty() && n != w.lastNode() && n.getCoor().isIn(downloadedArea)) { 91 addError(UNCONNECTED_COASTLINE, w, null, n); 92 } 93 if (connectedWays.size() == 1 && n != connectedWays.iterator().next().lastNode()) { 94 checkIfReversed(w, connectedWays.iterator().next(), n); 95 } 96 if (connectedWays.size() == 1 && w.isClosed() && connectedWays.iterator().next().isClosed()) { 97 addError(UNORDERED_COASTLINE, w, connectedWays, n); 98 } 99 } else if (i == numNodes - 1) { 100 if (connectedWays.isEmpty() && n != w.firstNode() && n.getCoor().isIn(downloadedArea)) { 101 addError(UNCONNECTED_COASTLINE, w, null, n); 102 } 103 if (connectedWays.size() == 1 && n != connectedWays.iterator().next().firstNode()) { 104 checkIfReversed(w, connectedWays.iterator().next(), n); 105 } 106 } else if (!connectedWays.isEmpty()) { 107 addError(UNORDERED_COASTLINE, w, connectedWays, n); 108 } 109 } 110 } 111 } 112 113 /** 114 * Check if two or more coastline ways form a closed clockwise way 115 */ 116 private void checkDirection() { 117 HashSet<Way> done = new HashSet<>(); 118 for (Way w : coastlineWays) { 119 if (done.contains(w)) 120 continue; 121 List<Way> visited = new ArrayList<>(); 122 done.add(w); 123 visited.add(w); 124 List<Node> nodes = new ArrayList<>(w.getNodes()); 125 Way curr = w; 126 while (nodes.get(0) != nodes.get(nodes.size()-1)) { 127 boolean foundContinuation = false; 128 for (OsmPrimitive p : curr.lastNode().getReferrers()) { 129 if (p != curr && isCoastline(p)) { 130 Way other = (Way) p; 131 if (done.contains(other)) 132 continue; 133 if (other.firstNode() == curr.lastNode()) { 134 foundContinuation = true; 135 curr = other; 136 done.add(curr); 137 visited.add(curr); 138 nodes.remove(nodes.size()-1); // remove duplicate connection node 139 nodes.addAll(curr.getNodes()); 140 break; 126 141 } 127 142 } 128 143 } 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<>(); 147 primitives.add(c1); 148 149 if (headWays == 0 || tailWays == 0) { 150 List<OsmPrimitive> highlight = new ArrayList<>(); 151 152 if (headWays == 0 && head.getCoor().isIn(downloadedArea)) { 153 highlight.add(head); 154 } 155 if (tailWays == 0 && tail.getCoor().isIn(downloadedArea)) { 156 highlight.add(tail); 157 } 158 159 if (!highlight.isEmpty()) { 160 errors.add(new TestError(this, Severity.ERROR, tr("Unconnected coastline"), 161 UNCONNECTED_COASTLINE, primitives, highlight)); 162 } 163 } 164 165 boolean unordered = false; 166 boolean reversed = headWays == 1 && headReversed && tailWays == 1 && tailReversed; 167 168 if (headWays > 1 || tailWays > 1) { 169 unordered = true; 170 } else if (headUnordered || tailUnordered) { 171 unordered = true; 172 } else if (reversed && next == prev) { 173 unordered = true; 174 } else if ((headReversed || tailReversed) && headReversed != tailReversed) { 175 unordered = true; 176 } 177 178 if (unordered) { 179 List<OsmPrimitive> highlight = new ArrayList<>(); 180 181 if (headWays > 1 || headUnordered || headReversed || reversed) { 182 highlight.add(head); 183 } 184 if (tailWays > 1 || tailUnordered || tailReversed || reversed) { 185 highlight.add(tail); 186 } 187 188 errors.add(new TestError(this, Severity.ERROR, tr("Unordered coastline"), 189 UNORDERED_COASTLINE, primitives, highlight)); 190 } else if (reversed) { 191 errors.add(new TestError(this, Severity.ERROR, tr("Reversed coastline"), 192 REVERSED_COASTLINE, primitives)); 193 } 194 } 195 196 coastlines = null; 197 downloadedArea = null; 198 199 super.endTest(); 144 if (!foundContinuation) 145 break; 146 } 147 // simple closed ways are reported by WronglyOrderedWays 148 if (visited.size() > 1 && nodes.get(0) == nodes.get(nodes.size()-1) && Geometry.isClockwise(nodes)) { 149 errors.add(new TestError(this, Severity.WARNING, tr("Reversed coastline: land not on left side"), 150 WRONG_ORDER_COASTLINE, visited)); 151 } 152 } 153 } 154 155 /** 156 * Check if a reversed way would fit, if yes, add fixable "reversed" error, "unordered" else 157 * @param w way that might be reversed 158 * @param other other way that is connected to w 159 * @param n1 node at which w and other are connected 160 */ 161 private void checkIfReversed(Way w, Way other, Node n1) { 162 boolean headFixedWithReverse = false; 163 boolean tailFixedWithReverse = false; 164 int otherCoastlineWays = 0; 165 Way connectedToFirst = null; 166 for (int i = 0; i < 2; i++) { 167 Node n = (i == 0) ? w.firstNode() : w.lastNode(); 168 List<OsmPrimitive> refs = n.getReferrers(); 169 for (OsmPrimitive p : refs) { 170 if (p != w && isCoastline(p)) { 171 Way cw = (Way) p; 172 if (i == 0 && cw.firstNode() == n) { 173 headFixedWithReverse = true; 174 connectedToFirst = cw; 175 } else if (i == 1 && cw.lastNode() == n) { 176 if (cw != connectedToFirst) 177 tailFixedWithReverse = true; 178 } else 179 otherCoastlineWays++; 180 } 181 } 182 } 183 if (otherCoastlineWays == 0 && headFixedWithReverse && tailFixedWithReverse) 184 addError(REVERSED_COASTLINE, w, null, null); 185 else 186 addError(UNORDERED_COASTLINE, w, Collections.singletonList(other), n1); 187 } 188 189 /** 190 * Add error if not already done 191 * @param errCode the error code 192 * @param w the way that is in error 193 * @param otherWays collection of other ways in error or null 194 * @param n the node to be highlighted or null 195 */ 196 private void addError(int errCode, Way w, Collection<Way> otherWays, Node n) { 197 String msg; 198 switch (errCode) { 199 case UNCONNECTED_COASTLINE: 200 msg = tr("Unconnected coastline"); 201 break; 202 case UNORDERED_COASTLINE: 203 msg = tr("Unordered coastline"); 204 break; 205 case REVERSED_COASTLINE: 206 msg = tr("Reversed coastline"); 207 break; 208 default: 209 msg = tr("invalid coastline"); // should not happen 210 } 211 Set<OsmPrimitive> primitives = new HashSet<>(); 212 primitives.add(w); 213 if (otherWays != null) 214 primitives.addAll(otherWays); 215 // check for repeated error 216 for (TestError e : errors) { 217 if (e.getCode() != errCode) 218 continue; 219 if (errCode != REVERSED_COASTLINE && !e.getHighlighted().contains(n)) 220 continue; 221 if (e.getPrimitives().size() != primitives.size()) 222 continue; 223 if (!e.getPrimitives().containsAll(primitives)) 224 continue; 225 return; // we already know this error 226 } 227 if (errCode != REVERSED_COASTLINE) 228 errors.add(new TestError(this, Severity.ERROR, msg, errCode, primitives, Collections.singletonList(n))); 229 else 230 errors.add(new TestError(this, Severity.ERROR, msg, errCode, primitives)); 200 231 } 201 232 … … 206 237 207 238 if (isCoastline(way)) { 208 coastline s.add(way);239 coastlineWays.add(way); 209 240 } 210 241 } -
trunk/src/org/openstreetmap/josm/gui/DefaultNameFormatter.java
r10748 r10991 136 136 } 137 137 138 /** 139 * Formats a name for an {@link OsmPrimitive}. 140 * 141 * @param osm the primitive 142 * @return the name 143 * @since 10991 144 */ 145 public String format(OsmPrimitive osm) { 146 if (osm instanceof Node) { 147 return format((Node) osm); 148 } else if (osm instanceof Way) { 149 return format((Way) osm); 150 } else if (osm instanceof Relation) { 151 return format((Relation) osm); 152 } 153 return null; 154 } 155 138 156 @Override 139 157 public String format(Node node) {
Note:
See TracChangeset
for help on using the changeset viewer.