33 | | * Case 1: Only ways selected, align each ways taking care of intersection. |
34 | | * Case 2: Single node selected, align this node relative to the surrounding nodes. |
35 | | * Case 3: Single node and ways selected, align this node relative to the surrounding nodes only parts of selected ways. |
36 | | * Case 4: Only nodes selected, align these nodes respect to the line passing through the most distant nodes. |
| 33 | * <pre> |
| 34 | * Case 1: 1 or 2 ways selected and no nodes selected: align nodes of ways taking care of intersection. |
| 35 | * Case 2: Single node selected and no ways selected: align this node relative to all referrer ways (2 at most). |
| 36 | * Case 3: Single node and ways selected: align this node relative to selected ways. |
| 37 | * Case 4.1: Only nodes selected, part of a non-closed way: align these nodes on the line passing through the |
| 38 | * extremity nodes (most distant in the way sequence). See https://josm.openstreetmap.de/ticket/9605#comment:3 |
| 39 | * Case 4.2: Only nodes selected, part of a closed way: align these nodes on the line passing through the most distant |
| 40 | * nodes. |
| 41 | * Case 4.3: Only nodes selected, part of multiple ways: align these nodes on the line passing through the most distant |
| 42 | * nodes. |
| 43 | * </pre> |
73 | | * Compute 2 anchor points to align a set of nodes. |
74 | | * If all nodes are part of a same way anchor points are choose farthest relative to this way, |
75 | | * else choose farthest nodes. |
76 | | * @param nodes Nodes to be aligned |
77 | | * @param resultOut Array of size >= 2 |
| 80 | * Return 2 nodes making up the line along which provided nodes must be aligned. |
| 81 | * |
| 82 | * @param nodes Nodes to be aligned. |
| 83 | * @return A array of two nodes. |
95 | | if(waysRef.size() == 1) { |
96 | | // All nodes are part of the same way. See #9605 |
97 | | HashSet<Node> remainNodes = new HashSet<>(nodes); |
98 | | Way way = waysRef.iterator().next(); |
99 | | for(Node n: way.getNodes()) { |
100 | | if(!remainNodes.contains(n)) continue; |
101 | | if(nodea == null) nodea = n; |
102 | | if(remainNodes.size() == 1) { |
103 | | nodeb = remainNodes.iterator().next(); |
104 | | break; |
105 | | } |
106 | | remainNodes.remove(n); |
| 100 | |
| 101 | // Nodes belongs to multiple ways, return most distant nodes. |
| 102 | if (waysRef.size() != 1) |
| 103 | return nodeFurthestAppart(nodes); |
| 104 | |
| 105 | // All nodes are part of the same way. See #9605. |
| 106 | Way way = waysRef.iterator().next(); |
| 107 | |
| 108 | if (way.isClosed()) { |
| 109 | // Align these nodes on the line passing through the most distant nodes. |
| 110 | return nodeFurthestAppart(nodes); |
| 111 | } |
| 112 | |
| 113 | // The way is open, align nodes on the line passing through the extremity nodes (most distant in the way |
| 114 | // sequence). See #9605#comment:3. |
| 115 | Set<Node> remainNodes = new HashSet<>(nodes); |
| 116 | for (Node n : way.getNodes()) { |
| 117 | if (!remainNodes.contains(n)) |
| 118 | continue; |
| 119 | if (nodea == null) |
| 120 | nodea = n; |
| 121 | if (remainNodes.size() == 1) { |
| 122 | nodeb = remainNodes.iterator().next(); |
| 123 | break; |
108 | | } else { |
109 | | // Find from the selected nodes two that are the furthest apart. |
110 | | // Let's call them A and B. |
111 | | double distance = 0; |
112 | | for (int i = 0; i < nodes.size()-1; i++) { |
113 | | Node n = nodes.get(i); |
114 | | for (int j = i+1; j < nodes.size(); j++) { |
115 | | Node m = nodes.get(j); |
116 | | double dist = Math.sqrt(n.getEastNorth().distance(m.getEastNorth())); |
117 | | if (dist > distance) { |
118 | | nodea = n; |
119 | | nodeb = m; |
120 | | distance = dist; |
121 | | } |
| 125 | remainNodes.remove(n); |
| 126 | } |
| 127 | |
| 128 | return new Node[] { nodea, nodeb }; |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * Return the two nodes the most distant from the provided list. |
| 133 | * |
| 134 | * @param nodes List of nodes to analyze. |
| 135 | * @return An array containing the two most distant nodes. |
| 136 | */ |
| 137 | private Node[] nodeFurthestAppart(List<Node> nodes) { |
| 138 | Node node1 = null, node2 = null; |
| 139 | double minSqDistance = 0; |
| 140 | int nb; |
| 141 | |
| 142 | nb = nodes.size(); |
| 143 | for (int i = 0; i < nb - 1; i++) { |
| 144 | Node n = nodes.get(i); |
| 145 | for (int j = i + 1; j < nb; j++) { |
| 146 | Node m = nodes.get(j); |
| 147 | double sqDist = n.getEastNorth().distanceSq(m.getEastNorth()); |
| 148 | if (sqDist > minSqDistance) { |
| 149 | node1 = n; |
| 150 | node2 = m; |
| 151 | minSqDistance = sqDist; |
184 | | * Align nodes in case that only nodes are selected |
185 | | * |
186 | | * The general algorithm here is to find the two selected nodes |
187 | | * that are furthest apart, and then to align all other selected |
188 | | * nodes onto the straight line between these nodes. |
189 | | |
190 | | * @param nodes Nodes to be aligned |
191 | | * @return Command that perform action |
192 | | * @throws InvalidSelection |
| 214 | * Align nodes in case 3 or more nodes are selected. |
| 215 | * |
| 216 | * @param nodes Nodes to be aligned. |
| 217 | * @return Command that perform action. |
| 218 | * @throws InvalidSelection If the nodes have same coordinates. |