- Timestamp:
- 2020-04-06T07:55:13+02:00 (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java
r16220 r16240 14 14 import java.util.HashSet; 15 15 import java.util.Iterator; 16 import java.util.LinkedHashSet; 16 17 import java.util.List; 17 18 import java.util.Map; … … 19 20 import java.util.Objects; 20 21 import java.util.Set; 22 import java.util.stream.Collectors; 21 23 22 24 import org.openstreetmap.josm.data.coor.EastNorth; … … 54 56 private final boolean isHighwayTest; 55 57 58 static final double DETOUR_FACTOR = 4; 59 56 60 protected abstract boolean isCandidate(OsmPrimitive p); 57 61 … … 248 252 return map; 249 253 } 254 if (s.w.hasTag(HIGHWAY, "platform")) 255 continue; 250 256 for (Node endnode : s.nearbyNodes(mindist)) { 251 257 Way parentWay = getWantedParentWay(endnode); 252 if (parentWay != null) { 253 if (!Objects.equals(OsmUtils.getLayer(s.w), OsmUtils.getLayer(parentWay))) { 254 continue; // ignore ways with different layer tag 255 } 256 257 // to handle intersections of 't' shapes and similar 258 if (!s.isConnectedTo(endnode)) { 259 if (parentWay.hasTag(HIGHWAY, "platform") || s.w.hasTag(HIGHWAY, "platform") 260 || s.barrierBetween(endnode)) { 261 continue; 262 } 263 addIfNewOrCloser(map, endnode, s); 264 } 258 if (parentWay != null && !parentWay.hasTag(HIGHWAY, "platform") 259 && Objects.equals(OsmUtils.getLayer(s.w), OsmUtils.getLayer(parentWay)) 260 // to handle intersections of 't' shapes and similar 261 && !s.isConnectedTo(endnode) && !s.obstacleBetween(endnode)) { 262 addIfNewOrCloser(map, endnode, s); 265 263 } 266 264 } … … 375 373 fillSearchNodes(endnodes); 376 374 if (!searchNodes.isEmpty()) { 377 maxLen = 4* mindist;375 maxLen = DETOUR_FACTOR * mindist; 378 376 if (isHighwayTest) { 379 377 addErrors(Severity.WARNING, getHighwayEndNodesNearOtherHighway(), tr("Way end node near other highway")); … … 386 384 boolean includeOther = isBeforeUpload ? ValidatorPrefHelper.PREF_OTHER_UPLOAD.get() : ValidatorPrefHelper.PREF_OTHER.get(); 387 385 if (minmiddledist > 0.0 && includeOther) { 388 maxLen = 4* minmiddledist;386 maxLen = DETOUR_FACTOR * minmiddledist; 389 387 fillSearchNodes(middlenodes); 390 388 addErrors(Severity.OTHER, getWayNodesNearOtherWay(), tr("Way node near other way")); … … 432 430 */ 433 431 boolean isConnectedTo(Node startNode) { 434 return isConnectedTo(startNode, new HashSet<>(), 0);432 return isConnectedTo(startNode, new LinkedHashSet<>(), 0, w); 435 433 } 436 434 … … 440 438 * @param visited set of visited nodes 441 439 * @param len length of the travelled route 440 * @param parent the previous parent way 442 441 * @return true if a reasonable connection was found 443 442 */ 444 private boolean isConnectedTo(Node node, Set<Node> visited, double len) { 445 if (n1 == node || n2 == node) { 446 return true; 447 } 443 private boolean isConnectedTo(Node node, LinkedHashSet<Node> visited, double len, Way parent) { 448 444 if (len > maxLen) { 449 445 return false; 450 446 } 447 if (n1 == node || n2 == node) { 448 Node uncon = visited.iterator().next(); 449 LatLon cl = ProjectionRegistry.getProjection().eastNorth2latlon(calcClosest(uncon)); 450 // calculate real detour length, closest point might be somewhere between n1 and n2 451 double detourLen = len + node.getCoor().greatCircleDistance(cl); 452 if (detourLen > maxLen) 453 return false; 454 // see #17914: flag also nodes which are very close 455 double directDist = getDist(uncon); 456 if (directDist <= 0.1) 457 return false; 458 return directDist > 0.5 || (visited.size() == 2 && directDist * 1.5 > detourLen); 459 } 451 460 if (visited != null) { 452 461 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; 469 } 462 List<Way> wantedParents = node.getParentWays().stream().filter(pw -> isWantedWay(pw)) 463 .collect(Collectors.toList()); 464 if (wantedParents.size() > 1 && wantedParents.indexOf(parent) != wantedParents.size() - 1) { 465 // we want to find a different way. so move known way to the end of the list 466 wantedParents.remove(parent); 467 wantedParents.add(parent); 468 } 469 470 for (final Way way : wantedParents) { 471 List<Node> nextNodes = new ArrayList<>(); 472 int pos = way.getNodes().indexOf(node); 473 if (pos > 0) { 474 nextNodes.add(way.getNode(pos - 1)); 475 } 476 if (pos + 1 < way.getNodesCount()) { 477 nextNodes.add(way.getNode(pos + 1)); 478 } 479 for (Node next : nextNodes) { 480 final boolean containsN = visited.contains(next); 481 visited.add(next); 482 if (!containsN && isConnectedTo(next, visited, 483 len + node.getCoor().greatCircleDistance(next.getCoor()), way)) { 484 return true; 470 485 } 471 486 } … … 475 490 } 476 491 492 private EastNorth calcClosest(Node n) { 493 return Geometry.closestPointToSegment(n1.getEastNorth(), n2.getEastNorth(), n.getEastNorth()); 494 } 495 477 496 double getDist(Node n) { 478 EastNorth coord = n.getEastNorth(); 479 if (coord == null) 480 return Double.NaN; 481 EastNorth closest = Geometry.closestPointToSegment(n1.getEastNorth(), n2.getEastNorth(), coord); 497 EastNorth closest = calcClosest(n); 482 498 return n.getCoor().greatCircleDistance(ProjectionRegistry.getProjection().eastNorth2latlon(closest)); 483 499 } … … 510 526 } 511 527 528 /** 529 * We know that any point near the line segment must be at 530 * least as close as the other end of the line, plus 531 * a little fudge for the distance away (dist) 532 * @param dist fudge to add 533 * @return collection of nearby nodes 534 */ 512 535 Collection<Node> nearbyNodes(double dist) { 513 /*514 * We know that any point near the line segment must be at515 * least as close as the other end of the line, plus516 * a little fudge for the distance away ('dist').517 */518 519 536 BBox bounds = this.getBounds(dist * (360.0d / (Ellipsoid.WGS84.a * 2 * Math.PI))); 520 537 List<Node> result = null; … … 535 552 } 536 553 537 private boolean barrierBetween(Node endnode) {554 private boolean obstacleBetween(Node endnode) { 538 555 EastNorth en = endnode.getEastNorth(); 539 EastNorth closest = Geometry.closestPointToSegment(n1.getEastNorth(), n2.getEastNorth(), en); 540 BBox bbox = new BBox(endnode.getCoor(), ProjectionRegistry.getProjection().eastNorth2latlon(closest)); 556 EastNorth closest = calcClosest(endnode); 557 LatLon llClosest = ProjectionRegistry.getProjection().eastNorth2latlon(closest); 558 // find obstacles between end node and way segment 559 BBox bbox = new BBox(endnode.getCoor(), llClosest); 541 560 for (Way nearbyWay : ds.searchWays(bbox)) { 542 if (nearbyWay != w && nearbyWay.isUsable() && nearbyWay.hasTag("barrier")561 if (nearbyWay != w && nearbyWay.isUsable() && isObstacle(nearbyWay) 543 562 && !endnode.getParentWays().contains(nearbyWay)) { 544 //make sure that the barrieris really between endnode and the highway segment, not just close to or around them563 //make sure that the obstacle is really between endnode and the highway segment, not just close to or around them 545 564 Iterator<Node> iter = nearbyWay.getNodes().iterator(); 546 565 EastNorth prev = iter.next().getEastNorth(); … … 556 575 return false; 557 576 } 577 578 private boolean isObstacle(Way w) { 579 return w.hasKey("barrier", "waterway") || isBuilding(w); 580 } 581 558 582 } 559 583
Note:
See TracChangeset
for help on using the changeset viewer.