Ticket #17914: 17914.patch

File 17914.patch, 6.8 KB (added by GerdP, 5 years ago)

Work in progress

  • src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java

     
    1313import java.util.HashMap;
    1414import java.util.HashSet;
    1515import java.util.Iterator;
     16import java.util.LinkedHashSet;
    1617import java.util.List;
    1718import java.util.Map;
    1819import java.util.Map.Entry;
    1920import java.util.Objects;
    2021import java.util.Set;
     22import java.util.stream.Collectors;
    2123
    2224import org.openstreetmap.josm.data.coor.EastNorth;
    2325import org.openstreetmap.josm.data.coor.LatLon;
     
    5355    private final int code;
    5456    private final boolean isHighwayTest;
    5557
     58    static final double DETOUR_FACTOR = 4;
     59
    5660    protected abstract boolean isCandidate(OsmPrimitive p);
    5761
    5862    protected boolean isWantedWay(Way w) {
     
    374378        }
    375379        fillSearchNodes(endnodes);
    376380        if (!searchNodes.isEmpty()) {
    377             maxLen = 4 * mindist;
     381            maxLen = DETOUR_FACTOR * mindist;
    378382            if (isHighwayTest) {
    379383                addErrors(Severity.WARNING, getHighwayEndNodesNearOtherHighway(), tr("Way end node near other highway"));
    380384            } else {
     
    385389        /* the following two should use a shorter distance */
    386390        boolean includeOther = isBeforeUpload ? ValidatorPrefHelper.PREF_OTHER_UPLOAD.get() : ValidatorPrefHelper.PREF_OTHER.get();
    387391        if (minmiddledist > 0.0 && includeOther) {
    388             maxLen = 4 * minmiddledist;
     392            maxLen = DETOUR_FACTOR * minmiddledist;
    389393            fillSearchNodes(middlenodes);
    390394            addErrors(Severity.OTHER, getWayNodesNearOtherWay(), tr("Way node near other way"));
    391395            fillSearchNodes(othernodes);
     
    431435         * @return true if a reasonable connection was found
    432436         */
    433437        boolean isConnectedTo(Node startNode) {
    434             return isConnectedTo(startNode, new HashSet<>(), 0);
     438            return isConnectedTo(startNode, new LinkedHashSet<>(), 0, w);
    435439        }
    436440
    437441        /**
     
    439443         * @param node the given node
    440444         * @param visited set of visited nodes
    441445         * @param len length of the travelled route
     446         * @param parent the previous parent way
    442447         * @return true if a reasonable connection was found
    443448         */
    444         private boolean isConnectedTo(Node node, Set<Node> visited, double len) {
     449        private boolean isConnectedTo(Node node, Set<Node> visited, double len, Way parent) {
     450            if (len > maxLen) {
     451                return false;
     452            }
    445453            if (n1 == node || n2 == node) {
    446454                return true;
    447455            }
    448             if (len > maxLen) {
    449                 return false;
    450             }
    451456            if (visited != null) {
    452457                visited.add(node);
    453                 for (final Way way : node.getParentWays()) {
    454                     if (isWantedWay(way)) {
    455                         List<Node> nextNodes = new ArrayList<>();
    456                         int pos = way.getNodes().indexOf(node);
    457                         if (pos > 0) {
    458                             nextNodes.add(way.getNode(pos - 1));
    459                         }
    460                         if (pos + 1 < way.getNodesCount()) {
    461                             nextNodes.add(way.getNode(pos + 1));
    462                         }
    463                         for (Node next : nextNodes) {
    464                             final boolean containsN = visited.contains(next);
    465                             visited.add(next);
    466                             if (!containsN && isConnectedTo(next, visited,
    467                                     len + node.getCoor().greatCircleDistance(next.getCoor()))) {
    468                                 return true;
     458                List<Way> wantedParents = node.getParentWays().stream().filter(p -> isWantedWay(p))
     459                        .collect(Collectors.toList());
     460                if (wantedParents.size() > 1 && wantedParents.indexOf(parent) != wantedParents.size() - 1) {
     461                    // we want to find a different way. so move known way to the end of the list
     462                    wantedParents.remove(parent);
     463                    wantedParents.add(parent);
     464                }
     465
     466                for (final Way way : wantedParents) {
     467                    List<Node> nextNodes = new ArrayList<>();
     468                    int pos = way.getNodes().indexOf(node);
     469                    if (pos > 0) {
     470                        nextNodes.add(way.getNode(pos - 1));
     471                    }
     472                    if (pos + 1 < way.getNodesCount()) {
     473                        nextNodes.add(way.getNode(pos + 1));
     474                    }
     475                    for (Node next : nextNodes) {
     476                        final boolean containsN = visited.contains(next);
     477                        visited.add(next);
     478                        if (!containsN) {
     479                            double lastLen = node.getCoor().greatCircleDistance(next.getCoor());
     480                            if (isConnectedTo(next, visited, len + lastLen, way)) {
     481                                Node uncon = visited.iterator().next();
     482                                EastNorth cl = calcClosest(uncon);
     483                                double detourLen = len + lastLen + next.getCoor()
     484                                        .greatCircleDistance(ProjectionRegistry.getProjection().eastNorth2latlon(cl));
     485                                if (detourLen > maxLen)
     486                                    return false;
     487                                double directDist = getDist(uncon);
     488                                return directDist > 0.1 && (visited.size() > 2 || DETOUR_FACTOR * directDist > detourLen);
    469489                            }
    470490                        }
    471491                    }
     
    474494            return false;
    475495        }
    476496
    477         double getDist(Node n) {
     497        private EastNorth calcClosest(Node n) {
    478498            EastNorth coord = n.getEastNorth();
    479499            if (coord == null)
    480                 return Double.NaN;
    481             EastNorth closest = Geometry.closestPointToSegment(n1.getEastNorth(), n2.getEastNorth(), coord);
    482             return n.getCoor().greatCircleDistance(ProjectionRegistry.getProjection().eastNorth2latlon(closest));
     500                return null;
     501            return Geometry.closestPointToSegment(n1.getEastNorth(), n2.getEastNorth(), coord);
    483502        }
    484503
     504        double getDist(Node n) {
     505            EastNorth closest = calcClosest(n);
     506            return closest != null
     507                    ? n.getCoor().greatCircleDistance(ProjectionRegistry.getProjection().eastNorth2latlon(closest))
     508                    : Double.NaN;
     509        }
     510
    485511        private boolean nearby(Node n, double dist) {
    486512            if (w.containsNode(n))
    487513                return false;