Ticket #5257: 5257.patch
File 5257.patch, 6.4 KB (added by , 14 years ago) |
---|
-
src/org/openstreetmap/josm/data/validation/tests/WronglyOrderedWays.java
3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.util.ArrayList; 7 import java.util.List; 6 import java.util.Collections; 8 7 9 import org.openstreetmap.josm.data.osm.OsmPrimitive;10 8 import org.openstreetmap.josm.data.osm.Way; 11 9 import org.openstreetmap.josm.data.validation.Severity; 12 10 import org.openstreetmap.josm.data.validation.Test; 13 11 import org.openstreetmap.josm.data.validation.TestError; 14 import org.openstreetmap.josm. gui.progress.ProgressMonitor;12 import org.openstreetmap.josm.tools.Geometry; 15 13 16 14 /** 17 15 * Check cyclic ways for errors … … 33 31 } 34 32 35 33 @Override 36 public void startTest(ProgressMonitor monitor) {37 super.startTest(monitor);38 }39 40 @Override41 public void endTest() {42 super.endTest();43 }44 45 @Override46 34 public void visit(Way w) { 47 String errortype = "";48 int type;49 35 50 if (!w.isUsable() )36 if (!w.isUsable() || !w.isClosed()) 51 37 return; 52 if (w.getNodesCount() <= 0)53 return;54 38 55 39 String natural = w.get("natural"); 56 if (natural == null) 40 if (natural == null) { 57 41 return; 58 59 if (natural.equals("coastline")) { 60 errortype = tr("Reversed coastline: land not on left side"); 61 type= WRONGLY_ORDERED_COAST; 62 } else if (natural.equals("water")) { 63 errortype = tr("Reversed water: land not on left side"); 64 type= WRONGLY_ORDERED_WATER; 65 } else if (natural.equals("land")) { 66 errortype = tr("Reversed land: land not on left side"); 67 type= WRONGLY_ORDERED_LAND; 68 } else 42 } else if ("coastline".equals(natural) && Geometry.isClockwise(w)) { 43 reportError(w, tr("Reversed coastline: land not on left side"), WRONGLY_ORDERED_COAST); 44 } else if ("water".equals(natural) && !Geometry.isClockwise(w)) { 45 reportError(w, tr("Reversed water: land not on left side"), WRONGLY_ORDERED_WATER); 46 } else if ("land".equals(natural) && Geometry.isClockwise(w)) { 47 reportError(w, tr("Reversed land: land not on left side"), WRONGLY_ORDERED_LAND); 48 } else { 69 49 return; 50 } 70 51 71 /** 72 * Test the directionality of the way 73 * 74 * Assuming a closed non-looping way, compute twice the area 75 * of the polygon using the formula 2*a = sum (Xn * Yn+1 - Xn+1 * Yn) 76 * If the area is negative the way is ordered in a clockwise direction 77 * 78 */ 79 if (w.getNode(0) == w.getNode(w.getNodesCount()-1)) { 80 double area2 = 0; 52 } 81 53 82 for (int node = 1; node < w.getNodesCount(); node++) { 83 area2 += (w.getNode(node-1).getCoor().lon() * w.getNode(node).getCoor().lat() 84 - w.getNode(node).getCoor().lon() * w.getNode(node-1).getCoor().lat()); 85 } 86 87 if (((natural.equals("coastline") || natural.equals("land")) && area2 < 0.) 88 || (natural.equals("water") && area2 > 0.)) { 89 List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>(); 90 primitives.add(w); 91 errors.add( new TestError(this, Severity.OTHER, errortype, type, primitives) ); 92 } 93 } 54 private void reportError(Way w, String msg, int type) { 55 errors.add(new TestError(this, Severity.OTHER, msg, type, Collections.singletonList(w))); 94 56 } 95 57 } -
src/org/openstreetmap/josm/tools/Geometry.java
14 14 import org.openstreetmap.josm.command.ChangeCommand; 15 15 import org.openstreetmap.josm.command.Command; 16 16 import org.openstreetmap.josm.data.coor.EastNorth; 17 import org.openstreetmap.josm.data.coor.LatLon; 17 18 import org.openstreetmap.josm.data.osm.BBox; 18 19 import org.openstreetmap.josm.data.osm.Node; 19 20 import org.openstreetmap.josm.data.osm.NodePositionComparator; … … 220 221 * @return true if first vector is clockwise before second vector. 221 222 */ 222 223 public static boolean angleIsClockwise(Node commonNode, Node firstNode, Node secondNode) { 223 double dy1 = (firstNode.getEastNorth().getY() - commonNode.getEastNorth().getY()); 224 double dy2 = (secondNode.getEastNorth().getY() - commonNode.getEastNorth().getY()); 225 double dx1 = (firstNode.getEastNorth().getX() - commonNode.getEastNorth().getX()); 226 double dx2 = (secondNode.getEastNorth().getX() - commonNode.getEastNorth().getX()); 227 228 return dy1 * dx2 - dx1 * dy2 > 0; 224 return angleIsClockwise(commonNode.getEastNorth(), firstNode.getEastNorth(), secondNode.getEastNorth()); 229 225 } 230 226 231 227 /** … … 526 522 return 6367000 * c; 527 523 } 528 524 525 /** 526 * Determines whether a way is oriented clockwise. 527 * 528 * Internals: Assuming a closed non-looping way, compute twice the area 529 * of the polygon using the formula {@code 2 * area = sum (X[n] * Y[n+1] - X[n+1] * Y[n])}. 530 * If the area is negative the way is ordered in a clockwise direction. 531 * 532 * @param w the way to be checked. 533 * @return true if and only if way is oriented clockwise. 534 * @throws IllegalArgumentException if way is not closed (see {@see Way#isClosed}). 535 * @see http://paulbourke.net/geometry/polyarea/ 536 */ 537 public static boolean isClockwise(Way w) { 538 if (!w.isClosed()) { 539 throw new IllegalArgumentException("Way must be closed to check orientation."); 540 } 529 541 542 double area2 = 0.; 543 int nodesCount = w.getNodesCount(); 544 545 for (int node = 1; node <= /*sic! consider last-first as well*/ nodesCount; node++) { 546 LatLon coorPrev = w.getNode(node - 1).getCoor(); 547 LatLon coorCurr = w.getNode(node % nodesCount).getCoor(); 548 area2 += coorPrev.lon() * coorCurr.lat(); 549 area2 -= coorCurr.lon() * coorPrev.lat(); 550 } 551 return area2 < 0; 552 } 530 553 }