- Timestamp:
- 2008-11-25T00:08:42+01:00 (16 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/actions
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/AlignInCircleAction.java
r1084 r1090 1 // 1 //License: GPL. Copyright 2007 by Immanuel Scholz and others 2 2 package org.openstreetmap.josm.actions; 3 3 … … 24 24 /** 25 25 * Aligns all selected nodes within a circle. (Useful for roundabouts) 26 * 26 * 27 27 * @author Matthew Newton 28 * @author Petr Dlouhý 28 29 */ 29 30 public final class AlignInCircleAction extends JosmAction { 30 31 31 public AlignInCircleAction() { 32 super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."), 33 Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")), KeyEvent.VK_O, Shortcut.GROUP_EDIT), true); 34 } 35 36 public void actionPerformed(ActionEvent e) { 37 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 38 Collection<Node> nodes = new LinkedList<Node>(); 39 40 for (OsmPrimitive osm : sel) 41 if (osm instanceof Node) 42 nodes.add((Node)osm); 43 44 // special case if no single nodes are selected and exactly one way is: 45 // then use the way's nodes 46 if ((nodes.size() == 0) && (sel.size() == 1)) 47 for (OsmPrimitive osm : sel) 48 if (osm instanceof Way) 49 for (Node n : ((Way)osm).nodes) 50 { 51 if(!nodes.contains(n)) 52 nodes.add(n); 53 } 54 55 if (nodes.size() < 4) { 56 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least four nodes.")); 57 return; 58 } 59 60 // Get average position of all nodes 61 Node avn = new Node(new LatLon(0,0)); 62 avn.eastNorth = new EastNorth(0,0); 63 for (Node n : nodes) { 64 avn.eastNorth = new EastNorth(avn.eastNorth.east()+n.eastNorth.east(), avn.eastNorth.north()+n.eastNorth.north()); 65 } 66 avn.eastNorth = new EastNorth(avn.eastNorth.east()/nodes.size(), avn.eastNorth.north()/nodes.size()); 67 avn.coor = Main.proj.eastNorth2latlon(avn.eastNorth); 68 // Node "avn" now is central to all selected nodes. 69 70 // Now calculate the average distance to each node from the 71 // centre. This method is ok as long as distances are short 72 // relative to the distance from the N or S poles. 73 double distances[] = new double[nodes.size()]; 74 double avdist = 0, latd, lond; 75 double lonscale = Math.cos(avn.coor.lat() * Math.PI/180.0); 76 lonscale = lonscale * lonscale; 77 int i = 0; 78 for (Node n : nodes) { 79 latd = n.coor.lat() - avn.coor.lat(); 80 lond = n.coor.lon() - avn.coor.lon(); 81 distances[i] = Math.sqrt(latd * latd + lonscale * lond * lond); 82 avdist += distances[i++]; 83 } 84 avdist = avdist / nodes.size(); 85 86 Collection<Command> cmds = new LinkedList<Command>(); 87 // Move each node to that distance from the centre. 88 i = 0; 89 for (Node n : nodes) { 90 double dx = n.eastNorth.east() - avn.eastNorth.east(); 91 double dy = n.eastNorth.north() - avn.eastNorth.north(); 92 double dist = distances[i++]; 93 cmds.add(new MoveCommand(n, (dx * (avdist / dist)) - dx, (dy * (avdist / dist)) - dy)); 94 } 95 96 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Circle"), cmds)); 97 Main.map.repaint(); 98 } 32 public AlignInCircleAction() { 33 super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."), 34 Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")), 35 KeyEvent.VK_O, Shortcut.GROUP_EDIT), true); 36 } 37 38 public double determinant(double[][] mat) { 39 double result = 0; 40 41 if (mat.length == 1) { 42 result = mat[0][0]; 43 return result; 44 } 45 46 if (mat.length == 2) { 47 result = mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]; 48 return result; 49 } 50 51 for (int i = 0; i < mat[0].length; i++) { 52 double temp[][] = new double[mat.length - 1][mat[0].length - 1]; 53 for (int j = 1; j < mat.length; j++) { 54 for (int k = 0; k < mat[0].length; k++) { 55 if (k < i) { 56 temp[j - 1][k] = mat[j][k]; 57 } else if (k > i) { 58 temp[j - 1][k - 1] = mat[j][k]; 59 } 60 } 61 } 62 result += mat[0][i] * Math.pow(-1, (double) i) * determinant(temp); 63 } 64 return result; 65 } 66 67 public double distance(EastNorth n, EastNorth m) { 68 double easd, nord; 69 easd = n.east() - m.east(); 70 nord = n.north() - m.north(); 71 return Math.sqrt(easd * easd + nord * nord); 72 } 73 74 public EastNorth circumcenter(EastNorth i, EastNorth j, EastNorth k) { 75 // move to 0,0, to eliminate numeric errors 76 double ie = i.east() - i.east(); 77 double in = i.north() - i.north(); 78 double je = j.east() - i.east(); 79 double jn = j.north() - i.north(); 80 double ke = k.east() - i.east(); 81 double kn = k.north() - i.north(); 82 double[][] ma = { { ie, in, 1 }, { je, jn, 1 }, { ke, kn, 1 } }; 83 double[][] mbx = { { (ie * ie + in * in), in, 1 }, { (je * je + jn * jn), jn, 1 }, 84 { (ke * ke + kn * kn), kn, 1 } }; 85 double[][] mby = { { ie * ie + in * in, ie, 1 }, { je * je + jn * jn, je, 1 }, { ke * ke + kn * kn, ke, 1 } }; 86 double a = determinant(ma); 87 double bx = determinant(mbx); 88 double by = determinant(mby); 89 EastNorth result = new EastNorth(bx / (2 * a) + i.east(), -by / (2 * a) + i.north()); 90 91 Node n = new Node(Main.proj.eastNorth2latlon(result)); 92 if (n.coor.isOutSideWorld()) { 93 JOptionPane.showMessageDialog(Main.parent, tr("Some of the nodes are (almost) in the line")); 94 return null; 95 } 96 return result; 97 } 98 99 public class PolarCoor { 100 double radius; 101 double angle; 102 EastNorth origin = new EastNorth(0, 0); 103 double azimuth = 0; 104 105 PolarCoor(double radius, double angle) { 106 this(radius, angle, new EastNorth(0, 0), 0); 107 } 108 109 PolarCoor(double radius, double angle, EastNorth origin, double azimuth) { 110 this.radius = radius; 111 this.angle = angle; 112 this.origin = origin; 113 this.azimuth = azimuth; 114 } 115 116 PolarCoor(EastNorth en) { 117 this(en, new EastNorth(0, 0), 0); 118 } 119 120 PolarCoor(EastNorth en, EastNorth origin, double azimuth) { 121 radius = distance(en, origin); 122 angle = Math.atan2(en.north() - origin.north(), en.east() - origin.east()); 123 this.origin = origin; 124 this.azimuth = azimuth; 125 } 126 127 public EastNorth toEastNorth() { 128 return new EastNorth(radius * Math.cos(angle - azimuth) + origin.east(), radius * Math.sin(angle - azimuth) 129 + origin.north()); 130 } 131 } 132 133 public void actionPerformed(ActionEvent e) { 134 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 135 Collection<Node> nodes = new LinkedList<Node>(); 136 Collection<Way> ways = new LinkedList<Way>(); 137 Node center = null; 138 Node node = null; 139 double radius = 0; 140 boolean regular = false; 141 142 for (OsmPrimitive osm : sel) { 143 if (osm instanceof Node) 144 nodes.add((Node) osm); 145 else if (osm instanceof Way) 146 ways.add((Way) osm); 147 } 148 149 // special case if no single nodes are selected and exactly one way is: 150 // then use the way's nodes 151 if ((nodes.size() <= 2) && (ways.size() == 1)) { 152 Way way = (Way) ways.toArray()[0]; 153 154 // some more special combinations: 155 // When is selected node that is part of the way, then make a regular polygon, selected 156 // node doesn't move. 157 // I haven't got better idea, how to activate that function. 158 // 159 // When one way and one node is selected, set center to position of that node. 160 // When one more node, part of the way, is selected, set the radius equal to the 161 // distance between two nodes. 162 if (nodes.size() > 0) { 163 if (nodes.size() == 1 && way.nodes.contains((Node) nodes.toArray()[0])) { 164 node = (Node) nodes.toArray()[0]; 165 regular = true; 166 } else { 167 168 center = (Node) nodes.toArray()[way.nodes.contains((Node) nodes.toArray()[0]) ? 1 : 0]; 169 if (nodes.size() == 2) 170 radius = distance(((Node) nodes.toArray()[0]).eastNorth, ((Node) nodes.toArray()[1]).eastNorth); 171 } 172 nodes = new LinkedList<Node>(); 173 } 174 175 for (Node n : way.nodes) { 176 if (!nodes.contains(n)) 177 nodes.add(n); 178 } 179 } 180 181 if (nodes.size() < 4) { 182 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least four nodes.")); 183 return; 184 } 185 186 // Get average position of circumcircles of the triangles of all triplets of neighbour nodes 187 if (center == null) { 188 center = new Node(new LatLon(0, 0)); 189 Node n0, n1, n2, prvni, druhy; 190 n0 = (Node) nodes.toArray()[nodes.size() - 1]; 191 n1 = (Node) nodes.toArray()[nodes.size() - 2]; 192 for (Node n : nodes) { 193 n2 = n1; 194 n1 = n0; 195 n0 = n; 196 EastNorth cc = circumcenter(n0.eastNorth, n1.eastNorth, n2.eastNorth); 197 if (cc == null) 198 return; 199 center.eastNorth = new EastNorth(center.eastNorth.east() + cc.east(), center.eastNorth.north() 200 + cc.north()); 201 } 202 203 center.eastNorth = new EastNorth(center.eastNorth.east() / nodes.size(), center.eastNorth.north() 204 / nodes.size()); 205 center.coor = Main.proj.eastNorth2latlon(center.eastNorth); 206 } 207 208 // Node "center" now is central to all selected nodes. 209 210 // Now calculate the average distance to each node from the 211 // centre. This method is ok as long as distances are short 212 // relative to the distance from the N or S poles. 213 if (radius == 0) { 214 for (Node n : nodes) { 215 radius += distance(center.eastNorth, n.eastNorth); 216 } 217 radius = radius / nodes.size(); 218 } 219 220 Collection<Command> cmds = new LinkedList<Command>(); 221 222 PolarCoor pc; 223 224 if (regular) { // Make a regular polygon 225 double angle = Math.PI * 2 / nodes.size(); 226 pc = new PolarCoor(((Node) nodes.toArray()[0]).eastNorth, center.eastNorth, 0); 227 228 if (pc.angle > (new PolarCoor(((Node) nodes.toArray()[1]).eastNorth, center.eastNorth, 0).angle)) 229 angle *= -1; 230 231 pc.radius = radius; 232 for (Node n : nodes) { 233 EastNorth no = pc.toEastNorth(); 234 cmds.add(new MoveCommand(n, no.east() - n.eastNorth.east(), no.north() - n.eastNorth.north())); 235 pc.angle += angle; 236 } 237 } else { // Move each node to that distance from the centre. 238 for (Node n : nodes) { 239 pc = new PolarCoor(n.eastNorth, center.eastNorth, 0); 240 pc.radius = radius; 241 EastNorth no = pc.toEastNorth(); 242 cmds.add(new MoveCommand(n, no.east() - n.eastNorth.east(), no.north() - n.eastNorth.north())); 243 } 244 } 245 246 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Circle"), cmds)); 247 Main.map.repaint(); 248 } 99 249 } -
trunk/src/org/openstreetmap/josm/actions/OrthogonalizeAction.java
r1089 r1090 116 116 boolean use_dirnodes = false; 117 117 118 if (dirnodes.size() == 2) {118 if (dirnodes.size() == 2) { 119 119 // When selection contains two nodes, use the nodes to compute a direction 120 120 // to align all ways to
Note:
See TracChangeset
for help on using the changeset viewer.