- Timestamp:
- 2014-12-20T03:37:42+01:00 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/AlignInLineAction.java
r7025 r7850 12 12 import java.util.HashSet; 13 13 import java.util.List; 14 import java.util.Map; 15 import java.util.Set; 14 16 15 17 import javax.swing.JOptionPane; … … 27 29 28 30 /** 29 * Aligns all selected nodes into a straight line (useful for 30 * roads that should be straight, but have side roads and 31 * Aligns all selected nodes into a straight line (useful for roads that should be straight, but have side roads and 31 32 * therefore need multiple nodes) 32 33 * 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. 34 * <pre> 35 * Case 1: 1 or 2 ways selected and no nodes selected: align nodes of ways taking care of intersection. 36 * Case 2: Single node selected and no ways selected: align this node relative to all referrer ways (2 at most). 37 * Case 3: Single node and ways selected: align this node relative to selected ways. 38 * Case 4.1: Only nodes selected, part of a non-closed way: align these nodes on the line passing through the 39 * extremity nodes (most distant in the way sequence). See https://josm.openstreetmap.de/ticket/9605#comment:3 40 * Case 4.2: Only nodes selected, part of a closed way: align these nodes on the line passing through the most distant 41 * nodes. 42 * Case 4.3: Only nodes selected, part of multiple ways: align these nodes on the line passing through the most distant 43 * nodes. 44 * </pre> 37 45 * 38 46 * @author Matthew Newton … … 71 79 72 80 /** 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 78 */ 79 private void nodePairFurthestApart(List<Node> nodes, Node[] resultOut) { 80 if(resultOut.length < 2) 81 throw new IllegalArgumentException(); 82 81 * Return 2 nodes making up the line along which provided nodes must be aligned. 82 * 83 * @param nodes Nodes to be aligned. 84 * @return A array of two nodes. 85 */ 86 private Node[] nodePairFurthestApart(List<Node> nodes) { 83 87 Node nodea = null; 84 88 Node nodeb = null; 85 89 86 // Intersection of all ways referred by each node 87 HashSet<Way> waysRef = null; 90 // Detect if selected nodes are on the same way. 91 92 // Get ways passing though all selected nodes. 93 Set<Way> waysRef = null; 88 94 for(Node n: nodes) { 89 95 Collection<Way> ref = OsmPrimitive.getFilteredList(n.getReferrers(), Way.class); … … 93 99 waysRef.retainAll(ref); 94 100 } 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; 101 102 // Nodes belongs to multiple ways, return most distant nodes. 103 if (waysRef.size() != 1) 104 return nodeFurthestAppart(nodes); 105 106 // All nodes are part of the same way. See #9605. 107 Way way = waysRef.iterator().next(); 108 109 if (way.isClosed()) { 110 // Align these nodes on the line passing through the most distant nodes. 111 return nodeFurthestAppart(nodes); 112 } 113 114 // The way is open, align nodes on the line passing through the extremity nodes (most distant in the way 115 // sequence). See #9605#comment:3. 116 Set<Node> remainNodes = new HashSet<>(nodes); 117 for (Node n : way.getNodes()) { 118 if (!remainNodes.contains(n)) 119 continue; 120 if (nodea == null) 121 nodea = n; 122 if (remainNodes.size() == 1) { 123 nodeb = remainNodes.iterator().next(); 124 break; 125 } 126 remainNodes.remove(n); 127 } 128 129 return new Node[] { nodea, nodeb }; 130 } 131 132 /** 133 * Return the two nodes the most distant from the provided list. 134 * 135 * @param nodes List of nodes to analyze. 136 * @return An array containing the two most distant nodes. 137 */ 138 private Node[] nodeFurthestAppart(List<Node> nodes) { 139 Node node1 = null, node2 = null; 140 double minSqDistance = 0; 141 int nb; 142 143 nb = nodes.size(); 144 for (int i = 0; i < nb - 1; i++) { 145 Node n = nodes.get(i); 146 for (int j = i + 1; j < nb; j++) { 147 Node m = nodes.get(j); 148 double sqDist = n.getEastNorth().distanceSq(m.getEastNorth()); 149 if (sqDist > minSqDistance) { 150 node1 = n; 151 node2 = m; 152 minSqDistance = sqDist; 105 153 } 106 remainNodes.remove(n); 107 } 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 } 122 } 123 } 124 } 125 resultOut[0] = nodea; 126 resultOut[1] = nodeb; 154 } 155 } 156 157 return new Node[] { node1, node2 }; 127 158 } 128 159 … … 161 192 cmd = alignSingleNode(selectedNodes.get(0), lines); 162 193 } 163 // / More than 3 nodes selected -> align those nodes194 // More than 3 nodes and way(s) selected -> align selected nodes. Don't care of way(s). 164 195 else if(selectedNodes.size() >= 3) { 165 196 cmd = alignOnlyNodes(selectedNodes); … … 182 213 183 214 /** 184 * Align nodes in case that only nodes are selected215 * Align nodes in case 3 or more nodes are selected. 185 216 * 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 217 * @param nodes Nodes to be aligned. 218 * @return Command that perform action. 219 * @throws InvalidSelection If the nodes have same coordinates. 193 220 */ 194 221 private Command alignOnlyNodes(List<Node> nodes) throws InvalidSelection { 195 Node[] anchors = new Node[2]; // oh, java I love you so much.. 196 // use the nodes furthest apart as anchors 197 nodePairFurthestApart(nodes, anchors); 222 // Choose nodes used as anchor points for projection. 223 Node[] anchors = nodePairFurthestApart(nodes); 198 224 Collection<Command> cmds = new ArrayList<>(nodes.size()); 199 225 Line line = new Line(anchors[0], anchors[1]); … … 212 238 private Command alignMultiWay(Collection<Way> ways) throws InvalidSelection { 213 239 // Collect all nodes and compute line equation 214 HashSet<Node> nodes = new HashSet<>();215 HashMap<Way, Line> lines = new HashMap<>();240 Set<Node> nodes = new HashSet<>(); 241 Map<Way, Line> lines = new HashMap<>(); 216 242 for(Way w: ways) { 217 243 if(w.firstNode() == w.lastNode()) … … 250 276 */ 251 277 private List<Line> getInvolvedLines(Node node, List<Way> refWays) throws InvalidSelection { 252 ArrayList<Line> lines = new ArrayList<>();253 ArrayList<Node> neighbors = new ArrayList<>();278 List<Line> lines = new ArrayList<>(); 279 List<Node> neighbors = new ArrayList<>(); 254 280 for(Way way: refWays) { 255 281 List<Node> nodes = way.getNodes();
Note:
See TracChangeset
for help on using the changeset viewer.