| 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. |