- Timestamp:
- 2019-12-24T11:01:03+01:00 (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java
r15428 r15610 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; … … 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. … … 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. … … 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 // resolution in numbers with large exponent not needed here.. 121 distSq = Double.longBitsToDouble(Double.doubleToLongBits(distSq) >> 32 << 32); 122 List<WaySegment> wslist = nearestMap.computeIfAbsent(distSq, k -> new LinkedList<>()); 123 wslist.add(ws); 124 } 125 Set<Way> seenWays = new HashSet<>(); 126 Double usedDist = null; 127 while (!nearestMap.isEmpty()) { 128 Entry<Double, List<WaySegment>> entry = nearestMap.pollFirstEntry(); 129 if (usedDist != null) { 130 double delta = entry.getKey() - usedDist; 131 if (delta > 1e-4) 132 break; 133 } 134 for (WaySegment ws : entry.getValue()) { 135 // only use the closest WaySegment of each way and ignore those that already contain the node 136 if (!ws.getFirstNode().equals(node) && !ws.getSecondNode().equals(node) 137 && !seenWays.contains(ws.way)) { 138 if (usedDist == null) 139 usedDist = entry.getKey(); 140 MultiMap<Integer, Node> innerMap = data.get(ws.way); 141 if (innerMap == null) { 142 innerMap = new MultiMap<>(); 143 data.put(ws.way, innerMap); 144 } 145 innerMap.put(ws.lowerIndex, node); 115 146 } 116 innerMap.put(ws.lowerIndex, node);117 147 seenWays.add(ws.way); 118 148 } … … 142 172 if (prevMove != null) { 143 173 if (!prevMove.equalsEpsilon(newPosition, 1e-4)) { 174 // very unlikely: node has same distance to multiple ways which are not nearly overlapping 144 175 new Notification(tr("Multiple target ways, no common point found. Nothing was changed.")) 145 176 .setIcon(JOptionPane.INFORMATION_MESSAGE)
Note:
See TracChangeset
for help on using the changeset viewer.