Ticket #18420: 18420.patch
File 18420.patch, 5.5 KB (added by , 5 years ago) |
---|
-
src/org/openstreetmap/josm/actions/JoinNodeWayAction.java
12 12 import java.util.Comparator; 13 13 import java.util.HashMap; 14 14 import java.util.HashSet; 15 import java.util.LinkedHashMap; 15 16 import java.util.LinkedList; 16 17 import java.util.List; 17 18 import java.util.Map; 19 import java.util.Map.Entry; 18 20 import java.util.Set; 21 import java.util.TreeMap; 19 22 20 23 import javax.swing.JOptionPane; 21 24 … … 90 93 DataSet ds = getLayerManager().getEditDataSet(); 91 94 Collection<Node> selectedNodes = ds.getSelectedNodes(); 92 95 Collection<Command> cmds = new LinkedList<>(); 93 Map<Way, MultiMap<Integer, Node>> data = new HashMap<>();96 Map<Way, MultiMap<Integer, Node>> data = new LinkedHashMap<>(); 94 97 95 98 // If the user has selected some ways, only join the node to these. 96 99 boolean restrictToSelectedWays = !ds.getSelectedWays().isEmpty(); … … 99 102 MapView mapView = MainApplication.getMap().mapView; 100 103 for (Node node : selectedNodes) { 101 104 List<WaySegment> wss = mapView.getNearestWaySegments(mapView.getPoint(node), OsmPrimitive::isSelectable); 102 Set<Way> seenWays = new HashSet<>(); 105 // we cannot trust the order of elements in wss because it was calculated based on rounded position value of node 106 TreeMap<Double, List<WaySegment>> nearestMap = new TreeMap<>(); 107 EastNorth en = node.getEastNorth(); 103 108 for (WaySegment ws : wss) { 104 109 // Maybe cleaner to pass a "isSelected" predicate to getNearestWaySegments, but this is less invasive. 105 110 if (restrictToSelectedWays && !ws.way.isSelected()) { 106 111 continue; 107 112 } 108 // only use the closest WaySegment of each way and ignore those that already contain the node 109 if (!ws.getFirstNode().equals(node) && !ws.getSecondNode().equals(node) 110 && !seenWays.contains(ws.way)) { 111 MultiMap<Integer, Node> innerMap = data.get(ws.way); 112 if (innerMap == null) { 113 innerMap = new MultiMap<>(); 114 data.put(ws.way, innerMap); 113 /* perpendicular distance squared 114 * loose some precision to account for possible deviations in the calculation above 115 * e.g. if identical (A and B) come about reversed in another way, values may differ 116 * -- zero out least significant 32 dual digits of mantissa.. 117 */ 118 double distSq = en.distanceSq(Geometry.closestPointToSegment(ws.getFirstNode().getEastNorth(), 119 ws.getSecondNode().getEastNorth(), en)); 120 distSq = Double.longBitsToDouble(Double.doubleToLongBits(distSq) >> 32 << 32); // resolution in numbers with large exponent not needed here.. 121 List<WaySegment> wslist = nearestMap.computeIfAbsent(distSq, k -> new LinkedList<>()); 122 wslist.add(ws); 123 } 124 Set<Way> seenWays = new HashSet<>(); 125 Double usedDist = null; 126 while (!nearestMap.isEmpty()) { 127 Entry<Double, List<WaySegment>> entry = nearestMap.pollFirstEntry(); 128 if (usedDist != null) { 129 double delta = entry.getKey() - usedDist; 130 if (delta > 1e-4) 131 break; 132 } 133 for (WaySegment ws : entry.getValue()) { 134 // only use the closest WaySegment of each way and ignore those that already contain the node 135 if (!ws.getFirstNode().equals(node) && !ws.getSecondNode().equals(node) 136 && !seenWays.contains(ws.way)) { 137 if (usedDist == null) 138 usedDist = entry.getKey(); 139 MultiMap<Integer, Node> innerMap = data.get(ws.way); 140 if (innerMap == null) { 141 innerMap = new MultiMap<>(); 142 data.put(ws.way, innerMap); 143 } 144 innerMap.put(ws.lowerIndex, node); 115 145 } 116 innerMap.put(ws.lowerIndex, node);117 146 seenWays.add(ws.way); 118 147 } 119 148 } … … 141 170 EastNorth prevMove = movedNodes.get(node); 142 171 if (prevMove != null) { 143 172 if (!prevMove.equalsEpsilon(newPosition, 1e-4)) { 173 // very unlikely: node has same distance to multiple ways which are not nearly overlapping 144 174 new Notification(tr("Multiple target ways, no common point found. Nothing was changed.")) 145 175 .setIcon(JOptionPane.INFORMATION_MESSAGE) 146 176 .show(); … … 166 196 } 167 197 168 198 if (cmds.isEmpty()) return; 199 if (joinWayToNode && selectedNodes.size() > movedNodes.size()) { 200 new Notification(tr("Not all selected nodes were moved.")) 201 .setIcon(JOptionPane.INFORMATION_MESSAGE) 202 .show(); 203 } 169 204 UndoRedoHandler.getInstance().add(new SequenceCommand(getValue(NAME).toString(), cmds)); 170 205 } 171 206