Changeset 14779 in josm for trunk


Ignore:
Timestamp:
2019-02-10T16:03:37+01:00 (6 years ago)
Author:
GerdP
Message:

see #16803: revert r14777,r14775, and r14772: too many side effects, patch needs more review

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/validation/tests/Highways.java

    r14777 r14779  
    99import java.util.HashMap;
    1010import java.util.HashSet;
    11 import java.util.Iterator;
    1211import java.util.List;
    1312import java.util.Locale;
    1413import java.util.Map;
    1514import java.util.Set;
     15import java.util.stream.Collectors;
    1616
    1717import org.openstreetmap.josm.command.ChangePropertyCommand;
     
    2323import org.openstreetmap.josm.data.validation.Test;
    2424import org.openstreetmap.josm.data.validation.TestError;
    25 import org.openstreetmap.josm.tools.Geometry;
    2625import org.openstreetmap.josm.tools.Logging;
    2726import org.openstreetmap.josm.tools.Utils;
     
    4342    protected static final String SOURCE_MAXSPEED = "source:maxspeed";
    4443
    45     /** threshold value for angles between two highway segments. */
    46     private static final int MIN_ANGLE_NOT_SHARP = 60;
    47 
    48     // CHECKSTYLE.OFF: SingleSpaceSeparator
    49     private static final Set<String> LINK_TO_HIGHWAYS = new HashSet<>(Arrays.asList(
    50             "motorway",  "motorway_link",
    51             "trunk",     "trunk_link",
    52             "primary",   "primary_link",
    53             "secondary", "secondary_link",
    54             "tertiary",  "tertiary_link"
    55             ));
    56 
    5744    /**
    5845     * Classified highways in order of importance
    5946     */
     47    // CHECKSTYLE.OFF: SingleSpaceSeparator
    6048    private static final List<String> CLASSIFIED_HIGHWAYS = Arrays.asList(
    6149            "motorway",  "motorway_link",
     
    6957    // CHECKSTYLE.ON: SingleSpaceSeparator
    7058
    71 
    7259    private static final Set<String> KNOWN_SOURCE_MAXSPEED_CONTEXTS = new HashSet<>(Arrays.asList(
    7360            "urban", "rural", "zone", "zone20", "zone:20", "zone30", "zone:30", "zone40",
     
    11299            if (w.isClosed() && w.hasTag(HIGHWAY, CLASSIFIED_HIGHWAYS) && w.hasTag("junction", "roundabout")
    113100                    && IN_DOWNLOADED_AREA_STRICT.test(w)) {
    114                 // TODO: find out how to handle split roundabouts (see #12841)
     101                // TODO: find out how to handle splitted roundabouts (see #12841)
    115102                testWrongRoundabout(w);
    116103            }
     
    178165    public static boolean isHighwayLinkOkay(final Way way) {
    179166        final String highway = way.get(HIGHWAY);
    180         if (highway == null || !highway.endsWith("_link")) {
     167        if (highway == null || !highway.endsWith("_link")
     168                || !IN_DOWNLOADED_AREA.test(way.getNode(0)) || !IN_DOWNLOADED_AREA.test(way.getNode(way.getNodesCount()-1))) {
    181169            return true;
    182170        }
    183171
    184         // check if connected to a high class road where the link must match the higher class
    185         String highClass = null;
    186         for (int i = 0; i < way.getNodesCount(); i++) {
    187             Node n = way.getNode(i);
    188             if (!IN_DOWNLOADED_AREA.test(n))
    189                 return true;
    190             Set<Way> otherWays = new HashSet<>();
    191             otherWays.addAll(Utils.filteredCollection(n.getReferrers(), Way.class));
    192             if (otherWays.size() == 1)
    193                 continue;
    194             Iterator<Way> iter = otherWays.iterator();
    195             while (iter.hasNext()) {
    196                 Way w = iter.next();
    197                 final String hw2 = w.get(HIGHWAY);
    198                 if (way == w || w.getNodesCount() < 2 || !w.isUsable() || hw2 == null)
    199                     iter.remove();
    200                 else {
    201                     if ("motorway".equals(hw2)) {
    202                         highClass = "motorway";
    203                         break;
    204                     } else if ("trunk".equals(hw2))
    205                         highClass = "trunk";
    206                 }
    207             }
    208         }
    209 
    210         if (highClass != null && !highway.equals(highClass + "_link")) {
    211             return false;
    212         }
    213 
    214         for (int i = 0; i < way.getNodesCount(); i++) {
    215             Node n = way.getNode(i);
    216             Set<Way> otherWays = new HashSet<>();
    217             otherWays.addAll(Utils.filteredCollection(n.getReferrers(), Way.class));
    218             if (otherWays.size() == 1)
    219                 continue;
    220             otherWays.removeIf(w -> w == way || !w.hasTag("highway") || !highway.startsWith(w.get(HIGHWAY)) || !LINK_TO_HIGHWAYS.contains(w.get(HIGHWAY)));
    221             if (otherWays.isEmpty())
    222                 continue;
    223 
    224             //TODO: ignore ways which are not allowed because of turn restrictions, oneway attributes or access rules?
    225             HashSet<Way> sameTag = new HashSet<>();
    226             for (Way ow : otherWays) {
    227                 if (highway.equals(ow.get(HIGHWAY)))
    228                     sameTag.add(ow);
    229                 else
    230                     return true;
    231             }
    232             // we have way(s) with the same _link tag, ignore those with a sharp angle
    233             final int pos = i;
    234             sameTag.removeIf(w -> isSharpAngle(way, pos, w));
    235             if (!sameTag.isEmpty())
    236                 return true;
    237         }
    238         return false;
    239 
    240     }
    241 
    242     /**
    243      * Check if the two given connected ways form a sharp angle.
    244      * @param way 1st way
    245      * @param nodePos node position of connecting node in 1st way
    246      * @param otherWay the 2nd way
    247      * @return true if angle is sharp or way cannot be travelled because of oneway attributes
    248      */
    249     private static boolean isSharpAngle(Way way, int nodePos, Way otherWay) {
    250         Node n = way.getNode(nodePos);
    251         int oneway = way.isOneway();
    252         if (oneway == 0 && "roundabout".equals(way.get("junction"))) {
    253             oneway = 1;
    254         }
    255 
    256         if (oneway != 1) {
    257             Node prev = getPrevNode(way, nodePos);
    258             if (prev != null && !onlySharpAngle(n, prev, otherWay))
    259                 return false;
    260         }
    261         if (oneway != -1) {
    262             Node next = getNextNode(way, nodePos);
    263             if (next != null && !onlySharpAngle(n, next, otherWay))
    264                 return false;
    265         }
    266         return true;
    267     }
    268 
    269     private static Node getNextNode(Way way, int nodePos) {
    270         if (nodePos + 1 >= way.getNodesCount()) {
    271             if (way.isClosed())
    272                 return way.getNode(1);
    273             return null;
     172        final Set<OsmPrimitive> referrers = new HashSet<>();
     173
     174        if (way.isClosed()) {
     175            // for closed way we need to check all adjacent ways
     176            for (Node n: way.getNodes()) {
     177                referrers.addAll(n.getReferrers());
     178            }
    274179        } else {
    275             return way.getNode(nodePos + 1);
    276         }
    277     }
    278 
    279     private static Node getPrevNode(Way way, int nodePos) {
    280         if (nodePos == 0) {
    281             if (way.isClosed())
    282                 return way.getNode(way.getNodesCount() - 2);
    283             return null;
    284         } else {
    285             return way.getNode(nodePos - 1);
    286         }
    287     }
    288 
    289     private static boolean onlySharpAngle(Node common, Node from, Way toWay) {
    290         int oneway = toWay.isOneway();
    291         if (oneway == 0 && "roundabout".equals(toWay.get("junction"))) {
    292             oneway = 1;
    293         }
    294 
    295         for (int i = 0; i < toWay.getNodesCount(); i++) {
    296             if (common == toWay.getNode(i)) {
    297 
    298                 if (oneway != 1) {
    299                     Node to = getNextNode(toWay, i);
    300                     if (to != null && !isSharpAngle(from, common, to))
    301                         return false;
    302                 }
    303                 if (oneway != -1) {
    304                     Node to = getPrevNode(toWay, i);
    305                     if (to != null && !isSharpAngle(from, common, to))
    306                         return false;
    307                 }
    308                 break;
    309             }
    310         }
    311         return true;
    312     }
    313 
    314     /**
    315      * Returns true if angle of a corner defined with 3 point coordinates is &lt; MIN_ANGLE_NOT_SHARP
    316      *
    317      * @param n1 first node
    318      * @param n2 Common node
    319      * @param n3 third node
    320      * @return true if angle is below value given in MIN_ANGLE_NOT_SHARP
    321      */
    322 
    323     private static boolean isSharpAngle(Node n1, Node n2, Node n3) {
    324         double angle = Geometry.getNormalizedAngleInDegrees(
    325                 Geometry.getCornerAngle(n1.getEastNorth(), n2.getEastNorth(), n3.getEastNorth()));
    326         return angle < MIN_ANGLE_NOT_SHARP;
     180            referrers.addAll(way.firstNode().getReferrers());
     181            referrers.addAll(way.lastNode().getReferrers());
     182        }
     183
     184        // Find ways of same class (exact class of class_link)
     185        List<Way> sameClass = Utils.filteredCollection(referrers, Way.class).stream().filter(
     186                otherWay -> !way.equals(otherWay) && otherWay.hasTag(HIGHWAY, highway, highway.replaceAll("_link$", "")))
     187                .collect(Collectors.toList());
     188        if (sameClass.size() > 1) {
     189            // It is possible to have a class_link between 2 segments of same class
     190            // in roundabout designs that physically separate a specific turn from the main roundabout
     191            // But if we have more than a single adjacent class, and one of them is a roundabout, that's an error
     192            for (Way w : sameClass) {
     193                if (w.hasTag("junction", "roundabout")) {
     194                    return false;
     195                }
     196            }
     197        }
     198        // Link roads should always at least one adjacent segment of same class
     199        return !sameClass.isEmpty();
    327200    }
    328201
  • trunk/test/unit/org/openstreetmap/josm/data/validation/tests/HighwaysTest.java

    r14772 r14779  
    117117                fail(test.getErrors().get(0).getMessage());
    118118            }
     119            Way w1 = ways.stream().filter(w -> 28508494 == w.getId()).findFirst().get();
     120            Way w2 = ways.stream().filter(w -> 28508493 == w.getId()).findFirst().get();
     121            test.visit(w1);
     122            test.visit(w2);
     123            assertEquals(2, test.getErrors().size());
    119124        }
    120125    }
Note: See TracChangeset for help on using the changeset viewer.