Ticket #7239: multijoin3.diff
File multijoin3.diff, 8.0 KB (added by , 11 years ago) |
---|
-
src/org/openstreetmap/josm/actions/JoinNodeWayAction.java
diff --git a/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java b/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java index 9453f6c..3f2623c 100644
a b import org.openstreetmap.josm.tools.Shortcut; 18 18 19 19 import java.awt.event.ActionEvent; 20 20 import java.awt.event.KeyEvent; 21 import java.util.Comparator; 21 22 import java.util.Collection; 22 23 import java.util.Collections; 23 24 import java.util.LinkedList; 24 25 import java.util.List; 25 26 import java.util.Map; 27 import java.util.HashMap; 26 28 import java.util.Set; 27 29 import java.util.SortedSet; 28 30 import java.util.TreeSet; … … public class JoinNodeWayAction extends JosmAction { 65 67 if (!isEnabled()) 66 68 return; 67 69 Collection<Node> selectedNodes = getCurrentDataSet().getSelectedNodes(); 68 // Allow multiple selected nodes too?69 if (selectedNodes.size() != 1) return;70 71 final Node node = selectedNodes.iterator().next();72 73 70 Collection<Command> cmds = new LinkedList<>(); 71 Map<Way, MultiMap<Integer, Node>> data = new HashMap<>(); 74 72 75 73 // If the user has selected some ways, only join the node to these. 76 74 boolean restrictToSelectedWays = 77 75 !getCurrentDataSet().getSelectedWays().isEmpty(); 78 76 79 List<WaySegment> wss = Main.map.mapView.getNearestWaySegments( 80 Main.map.mapView.getPoint(node), OsmPrimitive.isSelectablePredicate); 81 MultiMap<Way, Integer> insertPoints = new MultiMap<>(); 82 for (WaySegment ws : wss) { 83 // Maybe cleaner to pass a "isSelected" predicate to getNearestWaySegments, but this is less invasive. 84 if (restrictToSelectedWays && !ws.way.isSelected()) { 85 continue; 86 } 77 // Planning phase: decide where we'll insert the nodes and put it all in "data" 78 for (Node node : selectedNodes) { 79 List<WaySegment> wss = Main.map.mapView.getNearestWaySegments( 80 Main.map.mapView.getPoint(node), OsmPrimitive.isSelectablePredicate); 81 82 MultiMap<Way, Integer> insertPoints = new MultiMap<>(); 83 for (WaySegment ws : wss) { 84 // Maybe cleaner to pass a "isSelected" predicate to getNearestWaySegments, but this is less invasive. 85 if (restrictToSelectedWays && !ws.way.isSelected()) { 86 continue; 87 } 87 88 88 if (ws.getFirstNode() != node && ws.getSecondNode() != node) { 89 insertPoints.put(ws.way, ws.lowerIndex); 89 if (ws.getFirstNode() != node && ws.getSecondNode() != node) { 90 insertPoints.put(ws.way, ws.lowerIndex); 91 } 92 } 93 for (Map.Entry<Way, Set<Integer>> entry : insertPoints.entrySet()) { 94 final Way w = entry.getKey(); 95 final Set<Integer> insertPointsForWay = entry.getValue(); 96 for (int i : pruneSuccs(insertPointsForWay)) { 97 MultiMap<Integer, Node> innerMap; 98 if (!data.containsKey(w)) { 99 innerMap = new MultiMap<>(); 100 } else { 101 innerMap = data.get(w); 102 } 103 innerMap.put(i, node); 104 data.put(w, innerMap); 105 } 90 106 } 91 107 } 92 108 93 for (Map.Entry<Way, Set<Integer>> entry : insertPoints.entrySet()) { 109 // Execute phase: traverse the structure "data" and finally put the nodes into place 110 for (Map.Entry<Way, MultiMap<Integer, Node>> entry : data.entrySet()) { 94 111 final Way w = entry.getKey(); 95 final Set<Integer> insertPointsForWay = entry.getValue(); 96 if (insertPointsForWay.isEmpty()) { 97 continue; 98 } 112 final MultiMap<Integer, Node> innerEntry = entry.getValue(); 113 114 List<Integer> segmentIndexes = new LinkedList<Integer>(); 115 segmentIndexes.addAll(innerEntry.keySet()); 116 Collections.sort(segmentIndexes, Collections.reverseOrder()); 99 117 100 List<Node> nodesToAdd = w.getNodes(); 101 for (int i : pruneSuccsAndReverse(insertPointsForWay)) { 118 List<Node> wayNodes = w.getNodes(); 119 for (Integer segmentIndex : segmentIndexes) { 120 final Set<Node> nodesInSegment = innerEntry.get(segmentIndex); 102 121 if (joinWayToNode) { 103 EastNorth newPosition = Geometry.closestPointToSegment( 104 w.getNode(i).getEastNorth(), w.getNode(i + 1).getEastNorth(), node.getEastNorth()); 105 cmds.add(new MoveCommand(node, Projections.inverseProject(newPosition))); 122 for (Node node : nodesInSegment) { 123 EastNorth newPosition = Geometry.closestPointToSegment(w.getNode(segmentIndex).getEastNorth(), 124 w.getNode(segmentIndex+1).getEastNorth(), 125 node.getEastNorth()); 126 cmds.add(new MoveCommand(node, Projections.inverseProject(newPosition))); 127 } 106 128 } 107 nodesToAdd.add(i + 1, node); 129 List<Node> nodesToAdd = new LinkedList<Node>(); 130 nodesToAdd.addAll(nodesInSegment); 131 Collections.sort(nodesToAdd, new nodeDistanceToRefNodeComparator(w.getNode(segmentIndex), w.getNode(segmentIndex+1), !joinWayToNode)); 132 wayNodes.addAll(segmentIndex + 1, nodesToAdd); 108 133 } 109 134 Way wnew = new Way(w); 110 wnew.setNodes( nodesToAdd);135 wnew.setNodes(wayNodes); 111 136 cmds.add(new ChangeCommand(w, wnew)); 112 137 } 138 113 139 if (cmds.isEmpty()) return; 114 140 Main.main.undoRedo.add(new SequenceCommand(getValue(NAME).toString(), cmds)); 115 141 Main.map.repaint(); 116 142 } 117 143 118 private static SortedSet<Integer> pruneSuccs AndReverse(Collection<Integer> is) {119 SortedSet<Integer> is2 = new TreeSet<>( Collections.reverseOrder());144 private static SortedSet<Integer> pruneSuccs(Collection<Integer> is) { 145 SortedSet<Integer> is2 = new TreeSet<>(); 120 146 for (int i : is) { 121 147 if (!is2.contains(i - 1) && !is2.contains(i + 1)) { 122 148 is2.add(i); … … public class JoinNodeWayAction extends JosmAction { 125 151 return is2; 126 152 } 127 153 154 // Sorts collinear nodes by their distance to a common reference node. 155 private class nodeDistanceToRefNodeComparator implements Comparator<Node> { 156 private EastNorth refPoint; 157 private EastNorth refPoint2; 158 private boolean projectToSegment; 159 nodeDistanceToRefNodeComparator(Node referenceNode) { 160 refPoint = referenceNode.getEastNorth(); 161 projectToSegment = false; 162 } 163 nodeDistanceToRefNodeComparator(Node referenceNode, Node referenceNode2, boolean projectFirst) { 164 refPoint = referenceNode.getEastNorth(); 165 refPoint2 = referenceNode2.getEastNorth(); 166 projectToSegment = projectFirst; 167 } 168 public int compare(Node first, Node second) { 169 EastNorth firstPosition = first.getEastNorth(); 170 EastNorth secondPosition = second.getEastNorth(); 171 172 if (projectToSegment) { 173 firstPosition = Geometry.closestPointToSegment(refPoint, refPoint2, firstPosition); 174 secondPosition = Geometry.closestPointToSegment(refPoint, refPoint2, secondPosition); 175 } 176 177 double distanceFirst = firstPosition.distance(refPoint); 178 double distanceSecond = secondPosition.distance(refPoint); 179 double difference = distanceFirst - distanceSecond; 180 181 if (difference > 0.0) return 1; 182 if (difference < 0.0) return -1; 183 return 0; 184 } 185 } 186 128 187 @Override 129 188 protected void updateEnabledState() { 130 189 if (getCurrentDataSet() == null) {