Ticket #5257: 5257.patch

File 5257.patch, 6.4 KB (added by simon04, 10 months ago)
  • src/org/openstreetmap/josm/data/validation/tests/WronglyOrderedWays.java

     
    33 
    44import static org.openstreetmap.josm.tools.I18n.tr; 
    55 
    6 import java.util.ArrayList; 
    7 import java.util.List; 
     6import java.util.Collections; 
    87 
    9 import org.openstreetmap.josm.data.osm.OsmPrimitive; 
    108import org.openstreetmap.josm.data.osm.Way; 
    119import org.openstreetmap.josm.data.validation.Severity; 
    1210import org.openstreetmap.josm.data.validation.Test; 
    1311import org.openstreetmap.josm.data.validation.TestError; 
    14 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 
     12import org.openstreetmap.josm.tools.Geometry; 
    1513 
    1614/** 
    1715 * Check cyclic ways for errors 
     
    3331    } 
    3432 
    3533    @Override 
    36     public void startTest(ProgressMonitor monitor) { 
    37         super.startTest(monitor); 
    38     } 
    39  
    40     @Override 
    41     public void endTest() { 
    42         super.endTest(); 
    43     } 
    44  
    45     @Override 
    4634    public void visit(Way w) { 
    47         String errortype = ""; 
    48         int type; 
    4935 
    50         if (!w.isUsable()) 
     36        if (!w.isUsable() || !w.isClosed()) 
    5137            return; 
    52         if (w.getNodesCount() <= 0) 
    53             return; 
    5438 
    5539        String natural = w.get("natural"); 
    56         if (natural == null) 
     40        if (natural == null) { 
    5741            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 { 
    6949            return; 
     50        } 
    7051 
    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    } 
    8153 
    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))); 
    9456    } 
    9557} 
  • src/org/openstreetmap/josm/tools/Geometry.java

     
    1414import org.openstreetmap.josm.command.ChangeCommand; 
    1515import org.openstreetmap.josm.command.Command; 
    1616import org.openstreetmap.josm.data.coor.EastNorth; 
     17import org.openstreetmap.josm.data.coor.LatLon; 
    1718import org.openstreetmap.josm.data.osm.BBox; 
    1819import org.openstreetmap.josm.data.osm.Node; 
    1920import org.openstreetmap.josm.data.osm.NodePositionComparator; 
     
    220221     * @return true if first vector is clockwise before second vector. 
    221222     */ 
    222223    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()); 
    229225    } 
    230226 
    231227    /** 
     
    526522        return 6367000 * c; 
    527523    } 
    528524 
     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        } 
    529541 
     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    } 
    530553}