Changeset 19197 in josm
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/command/SplitWayCommand.java
r18539 r19197 46 46 import org.openstreetmap.josm.tools.CheckParameterUtil; 47 47 import org.openstreetmap.josm.tools.Logging; 48 48 49 /** 49 50 * Splits a way into multiple ways (all identical except for their node list). 50 * 51 * <p> 51 52 * Ways are just split at the selected nodes. The nodes remain in their 52 53 * original order. Selected nodes at the end of a way are ignored. … … 77 78 private final List<Way> newWays; 78 79 80 private static final String RESTRICTION = "restriction"; 79 81 /** Map<Restriction type, type to treat it as> */ 80 82 private static final Map<String, String> relationSpecialTypes = new HashMap<>(); 81 83 static { 82 relationSpecialTypes.put( "restriction", "restriction");83 relationSpecialTypes.put("destination_sign", "restriction");84 relationSpecialTypes.put("connectivity", "restriction");84 relationSpecialTypes.put(RESTRICTION, RESTRICTION); 85 relationSpecialTypes.put("destination_sign", RESTRICTION); 86 relationSpecialTypes.put("connectivity", RESTRICTION); 85 87 } 86 88 … … 167 169 * Splits the nodes of {@code wayToSplit} into a list of node sequences 168 170 * which are separated at the nodes in {@code splitPoints}. 169 * 171 * <p> 170 172 * This method displays warning messages if {@code wayToSplit} and/or 171 173 * {@code splitPoints} aren't consistent. 172 * 174 * <p> 173 175 * Returns null, if building the split chunks fails. 174 176 * … … 250 252 * Splits the way {@code way} into chunks of {@code wayChunks} and replies 251 253 * the result of this process in an instance of {@link SplitWayCommand}. 252 * 254 * <p> 253 255 * Note that changes are not applied to the data yet. You have to 254 256 * submit the command first, i.e. {@code UndoRedoHandler.getInstance().add(result)}. … … 463 465 if (rm.getMember() == way) { 464 466 boolean insert = true; 465 if (relationSpecialTypes.containsKey(type) && "restriction".equals(relationSpecialTypes.get(type))) {467 if (relationSpecialTypes.containsKey(type) && RESTRICTION.equals(relationSpecialTypes.get(type))) { 466 468 RelationInformation rValue = treatAsRestriction(r, rm, c, newWays, way, changedWayNodes); 467 469 if (rValue.warnme) warnings.add(WarningType.GENERIC); … … 715 717 Direction direction = relationAnalysis.getDirection(); 716 718 717 int position = -1;718 719 for (int i = 0; i < relation.getMembersCount(); i++) { 719 720 // search for identical member (can't use indexOf() as it uses equals() 720 721 if (rm == relation.getMember(i)) { 721 position = i;722 addSortedWays(i, indexOfWayToKeep, direction, newWays, relation); 722 723 break; 723 }724 }725 726 // sanity check727 if (position < 0) {728 throw new AssertionError("Relation member not found");729 }730 731 int j = position;732 final List<Way> waysToAddBefore = newWays.subList(0, indexOfWayToKeep);733 for (Way wayToAdd : waysToAddBefore) {734 RelationMember em = new RelationMember(rm.getRole(), wayToAdd);735 j++;736 if (direction == Direction.BACKWARDS) {737 relation.addMember(position + 1, em);738 } else {739 relation.addMember(j - 1, em);740 }741 }742 final List<Way> waysToAddAfter = newWays.subList(indexOfWayToKeep, newWays.size());743 for (Way wayToAdd : waysToAddAfter) {744 RelationMember em = new RelationMember(rm.getRole(), wayToAdd);745 j++;746 if (direction == Direction.BACKWARDS) {747 relation.addMember(position, em);748 } else {749 relation.addMember(j, em);750 724 } 751 725 } … … 779 753 newWays 780 754 ); 755 } 756 757 /** 758 * Ad ways in a sorted manner 759 * @param position The position of the relation member we are operating on 760 * @param indexOfWayToKeep The index of the way that is keeping history if it were in {@code newWays} 761 * @param direction The direction of the ways 762 * @param newWays The ways that are being added to the relation 763 * @param relation The relation we are operating on 764 */ 765 private static void addSortedWays(final int position, final int indexOfWayToKeep, final Direction direction, 766 final List<Way> newWays, final Relation relation) { 767 // sanity check 768 if (position < 0) { 769 throw new AssertionError("Relation member not found"); 770 } 771 final RelationMember rm = relation.getMember(position); 772 final boolean reverse = direction == Direction.BACKWARDS || needToReverseSplit(position, indexOfWayToKeep, relation, newWays); 773 final List<Way> waysToAddBefore = newWays.subList(0, indexOfWayToKeep); 774 int j = position; 775 for (Way wayToAdd : waysToAddBefore) { 776 RelationMember em = new RelationMember(rm.getRole(), wayToAdd); 777 j++; 778 if (reverse) { 779 relation.addMember(position + 1, em); 780 } else { 781 relation.addMember(j - 1, em); 782 } 783 } 784 final List<Way> waysToAddAfter = newWays.subList(indexOfWayToKeep, newWays.size()); 785 for (Way wayToAdd : waysToAddAfter) { 786 RelationMember em = new RelationMember(rm.getRole(), wayToAdd); 787 j++; 788 if (reverse) { 789 relation.addMember(position, em); 790 } else { 791 relation.addMember(j, em); 792 } 793 } 794 } 795 796 /** 797 * This is only strictly necessary when we are splitting a route where it starts to loop back. 798 * Example: way1 -> way2 -> way2 -> way1 799 * 800 * @param position The position of the original way in the relation 801 * @param indexOfWayToKeep The index of the way to keep in relation to {@code newWays} 802 * @param relation The relation we are working on 803 * @param newWays The ways that are being added 804 * @return {@code true} if we need to reverse the direction of the ways 805 */ 806 private static boolean needToReverseSplit(final int position, int indexOfWayToKeep, final Relation relation, final List<Way> newWays) { 807 final RelationMember rm = relation.getMember(position); 808 if (!rm.isWay()) { 809 return false; 810 } 811 final RelationMember previous = position <= 0 ? null : relation.getMember(position - 1); 812 final RelationMember next = position + 1 >= relation.getMembersCount() ? null : relation.getMember(position + 1); 813 final Way first = indexOfWayToKeep == 0 ? rm.getWay() : newWays.get(0); 814 final Way last = indexOfWayToKeep == newWays.size() ? rm.getWay() : newWays.get(newWays.size() - 1); 815 if (previous != null && previous.isWay() && previous.getWay().isUsable()) { 816 final Way compare = previous.getWay(); 817 if (!(compare.isFirstLastNode(first.firstNode()) || compare.isFirstLastNode(first.lastNode()))) { 818 return true; 819 } 820 } 821 if (next != null && next.isWay() && next.getWay().isUsable()) { 822 final Way compare = next.getWay(); 823 return !(compare.isFirstLastNode(last.firstNode()) || compare.isFirstLastNode(last.lastNode())); 824 } 825 return false; 781 826 } 782 827 … … 833 878 switch (type) { 834 879 case "connectivity": 835 case "restriction":880 case RESTRICTION: 836 881 return r.findRelationMembers("via"); 837 882 case "destination_sign": … … 849 894 * Splits the way {@code way} at the nodes in {@code atNodes} and replies 850 895 * the result of this process in an instance of {@link SplitWayCommand}. 851 * 896 * <p> 852 897 * Note that changes are not applied to the data yet. You have to 853 898 * submit the command first, i.e. {@code UndoRedoHandler.getInstance().add(result)}. 854 * 899 * <p> 855 900 * Replies null if the way couldn't be split at the given nodes. 856 901 * -
trunk/test/unit/org/openstreetmap/josm/command/SplitWayCommandTest.java
r18870 r19197 468 468 dataSet.setSelected(splitNode); 469 469 // Sanity check (preconditions -- the route should be well-formed already) 470 WayConnectionTypeCalculator connectionTypeCalculator = new WayConnectionTypeCalculator(); 471 List<WayConnectionType> links = connectionTypeCalculator.updateLinks(route, route.getMembers()); 472 assertAll("All links should be connected (forward)", 473 links.subList(0, links.size() - 2).stream().map(link -> () -> assertTrue(link.linkNext))); 474 assertAll("All links should be connected (backward)", 475 links.subList(1, links.size() - 1).stream().map(link -> () -> assertTrue(link.linkPrev))); 470 assertWellFormedRoute(route); 476 471 final Optional<SplitWayCommand> result = SplitWayCommand.splitWay( 477 472 splitWay, … … 479 474 new ArrayList<>(), 480 475 Strategy.keepLongestChunk(), 481 // This split requires additional downloads but problem occur ed before the download476 // This split requires additional downloads but problem occurred before the download 482 477 SplitWayCommand.WhenRelationOrderUncertain.SPLIT_ANYWAY 483 478 ); … … 485 480 result.get().executeCommand(); 486 481 // Actual check 487 connectionTypeCalculator = new WayConnectionTypeCalculator(); 488 links = connectionTypeCalculator.updateLinks(route, route.getMembers()); 482 assertWellFormedRoute(route); 483 } 484 485 @Test 486 void testTicket21856DoublePoints() { 487 final Way incomplete = new Way(1082474948, 10); 488 final Way way1 = TestUtils.newWay("highway=residential", new Node(new LatLon(47.9971473, 8.1274441)), 489 new Node(new LatLon(48.0011535, 8.1363531))); 490 final Way way2 = TestUtils.newWay("highway=residential", new Node(new LatLon(48.0012294, 8.136414)), 491 new Node(new LatLon(48.0042513, 8.1378392))); 492 final Way splitWay = TestUtils.newWay("highway=residential", new Node(new LatLon(48.0011817, 8.1363763)), 493 new Node(new LatLon(48.0012086, 8.1363974))); 494 final Relation ptRelation = TestUtils.newRelation("type=route route=bus public_transport:version=2", 495 new RelationMember("", incomplete), new RelationMember("", way1), 496 new RelationMember("", splitWay), new RelationMember("", splitWay), 497 new RelationMember("", way1), new RelationMember("", incomplete)); 498 final List<Node> splitLocations = splitWay.getNodes(); 499 final DataSet ds = new DataSet(); 500 way1.setOsmId(289122842, 10); 501 way2.setOsmId(30239125, 18); 502 splitWay.setOsmId(1082474946, 1); 503 ds.addPrimitiveRecursive(way1); 504 ds.addPrimitiveRecursive(way2); 505 ds.addPrimitiveRecursive(splitWay); 506 ds.addPrimitiveRecursive(incomplete); 507 ds.addPrimitive(ptRelation); 508 splitWay.addNode(0, way1.lastNode()); 509 splitWay.addNode(way2.firstNode()); 510 511 ds.setSelected(splitLocations); 512 assertWellFormedRoute(ptRelation); 513 final Optional<SplitWayCommand> result = SplitWayCommand.splitWay( 514 splitWay, 515 SplitWayCommand.buildSplitChunks(splitWay, splitLocations), 516 new ArrayList<>(), 517 Strategy.keepLongestChunk(), 518 SplitWayCommand.WhenRelationOrderUncertain.SPLIT_ANYWAY 519 ); 520 assertTrue(result.isPresent()); 521 result.get().executeCommand(); 522 // Actual check 523 assertWellFormedRoute(ptRelation); 524 } 525 526 @Test 527 void testTicket21856DoublePointsRouteMiddle() { 528 final Way incomplete = new Way(1082474948, 10); 529 final Way way1 = TestUtils.newWay("highway=residential", new Node(new LatLon(47.9971473, 8.1274441)), 530 new Node(new LatLon(48.0011535, 8.1363531))); 531 final Way way2 = TestUtils.newWay("highway=residential", new Node(new LatLon(48.0012294, 8.136414)), 532 new Node(new LatLon(48.0042513, 8.1378392))); 533 final Way splitWay = TestUtils.newWay("highway=residential", new Node(new LatLon(48.0011817, 8.1363763)), 534 new Node(new LatLon(48.0012086, 8.1363974))); 535 final Relation ptRelation = TestUtils.newRelation("type=route route=bus public_transport:version=2", 536 new RelationMember("", incomplete), new RelationMember("", way1), 537 new RelationMember("", splitWay), new RelationMember("", way2), 538 new RelationMember("", way2), new RelationMember("", splitWay), 539 new RelationMember("", way1), new RelationMember("", incomplete)); 540 final List<Node> splitLocations = splitWay.getNodes(); 541 final DataSet ds = new DataSet(); 542 way1.setOsmId(289122842, 10); 543 way2.setOsmId(30239125, 18); 544 splitWay.setOsmId(1082474946, 1); 545 ds.addPrimitiveRecursive(way1); 546 ds.addPrimitiveRecursive(way2); 547 ds.addPrimitiveRecursive(splitWay); 548 ds.addPrimitiveRecursive(incomplete); 549 ds.addPrimitive(ptRelation); 550 splitWay.addNode(0, way1.lastNode()); 551 splitWay.addNode(way2.firstNode()); 552 553 ds.setSelected(splitLocations); 554 assertWellFormedRoute(ptRelation); 555 final Optional<SplitWayCommand> result = SplitWayCommand.splitWay( 556 splitWay, 557 SplitWayCommand.buildSplitChunks(splitWay, splitLocations), 558 new ArrayList<>(), 559 Strategy.keepLongestChunk(), 560 SplitWayCommand.WhenRelationOrderUncertain.SPLIT_ANYWAY 561 ); 562 assertTrue(result.isPresent()); 563 result.get().executeCommand(); 564 // Actual check 565 assertWellFormedRoute(ptRelation); 566 } 567 568 569 private static void assertWellFormedRoute(Relation route) { 570 WayConnectionTypeCalculator connectionTypeCalculator = new WayConnectionTypeCalculator(); 571 List<WayConnectionType> links = connectionTypeCalculator.updateLinks(route, route.getMembers()); 572 // NONE is the default, and is most often found on incomplete ways 573 links.removeIf(link -> link.direction == WayConnectionType.Direction.NONE); 489 574 assertAll("All links should be connected (forward)", 490 575 links.subList(0, links.size() - 2).stream().map(link -> () -> assertTrue(link.linkNext)));
Note:
See TracChangeset
for help on using the changeset viewer.