source: josm/trunk/src/org/openstreetmap/josm/actions/AlignInCircleAction.java@ 729

Last change on this file since 729 was 655, checked in by ramack, 16 years ago

patch by bruce89, closes #812; thanks bruce

  • Property svn:eol-style set to native
File size: 3.2 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.awt.event.KeyEvent;
8import java.util.Collection;
9import java.util.LinkedList;
10
11import javax.swing.JOptionPane;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.command.Command;
15import org.openstreetmap.josm.command.MoveCommand;
16import org.openstreetmap.josm.command.SequenceCommand;
17import org.openstreetmap.josm.data.coor.EastNorth;
18import org.openstreetmap.josm.data.coor.LatLon;
19import org.openstreetmap.josm.data.osm.Node;
20import org.openstreetmap.josm.data.osm.OsmPrimitive;
21import org.openstreetmap.josm.data.osm.Way;
22
23/**
24 * Aligns all selected nodes within a circle. (Useful for roundabouts)
25 *
26 * @author Matthew Newton
27 */
28public final class AlignInCircleAction extends JosmAction {
29
30 public AlignInCircleAction() {
31 super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."), KeyEvent.VK_O, 0, true);
32 }
33
34 public void actionPerformed(ActionEvent e) {
35 Collection<OsmPrimitive> sel = Main.ds.getSelected();
36 Collection<Node> nodes = new LinkedList<Node>();
37
38 for (OsmPrimitive osm : sel)
39 if (osm instanceof Node)
40 nodes.add((Node)osm);
41
42 // special case if no single nodes are selected and exactly one way is:
43 // then use the way's nodes
44 if ((nodes.size() == 0) && (sel.size() == 1))
45 for (OsmPrimitive osm : sel)
46 if (osm instanceof Way)
47 nodes.addAll(((Way)osm).nodes);
48
49 if (nodes.size() < 4) {
50 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least four nodes."));
51 return;
52 }
53
54 // Get average position of all nodes
55 Node avn = new Node(new LatLon(0,0));
56 for (Node n : nodes) {
57 avn.eastNorth = new EastNorth(avn.eastNorth.east()+n.eastNorth.east(), avn.eastNorth.north()+n.eastNorth.north());
58 avn.coor = Main.proj.eastNorth2latlon(avn.eastNorth);
59 }
60 avn.eastNorth = new EastNorth(avn.eastNorth.east()/nodes.size(), avn.eastNorth.north()/nodes.size());
61 avn.coor = Main.proj.eastNorth2latlon(avn.eastNorth);
62 // Node "avn" now is central to all selected nodes.
63
64 // Now calculate the average distance to each node from the
65 // centre. This method is ok as long as distances are short
66 // relative to the distance from the N or S poles.
67 double distances[] = new double[nodes.size()];
68 double avdist = 0, latd, lond;
69 double lonscale = Math.cos(avn.coor.lat() * Math.PI/180.0);
70 lonscale = lonscale * lonscale;
71 int i = 0;
72 for (Node n : nodes) {
73 latd = n.coor.lat() - avn.coor.lat();
74 lond = n.coor.lon() - avn.coor.lon();
75 distances[i] = Math.sqrt(latd * latd + lonscale * lond * lond);
76 avdist += distances[i++];
77 }
78 avdist = avdist / nodes.size();
79
80 Collection<Command> cmds = new LinkedList<Command>();
81 // Move each node to that distance from the centre.
82 i = 0;
83 for (Node n : nodes) {
84 double dx = n.eastNorth.east() - avn.eastNorth.east();
85 double dy = n.eastNorth.north() - avn.eastNorth.north();
86 double dist = distances[i++];
87 cmds.add(new MoveCommand(n, (dx * (avdist / dist)) - dx, (dy * (avdist / dist)) - dy));
88 }
89
90 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
91 Main.map.repaint();
92 }
93}
Note: See TracBrowser for help on using the repository browser.