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

Last change on this file since 749 was 749, checked in by stoecker, 16 years ago

Fixed Align circles in node in case of way usage. Closes bug #1389.

  • Property svn:eol-style set to native
File size: 3.3 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 for (Node n : ((Way)osm).nodes)
48 {
49 if(!nodes.contains(n))
50 nodes.add(n);
51 }
52
53 if (nodes.size() < 4) {
54 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least four nodes."));
55 return;
56 }
57
58 // Get average position of all nodes
59 Node avn = new Node(new LatLon(0,0));
60 avn.eastNorth = new EastNorth(0,0);
61 for (Node n : nodes) {
62 avn.eastNorth = new EastNorth(avn.eastNorth.east()+n.eastNorth.east(), avn.eastNorth.north()+n.eastNorth.north());
63 }
64 avn.eastNorth = new EastNorth(avn.eastNorth.east()/nodes.size(), avn.eastNorth.north()/nodes.size());
65 avn.coor = Main.proj.eastNorth2latlon(avn.eastNorth);
66 // Node "avn" now is central to all selected nodes.
67
68 // Now calculate the average distance to each node from the
69 // centre. This method is ok as long as distances are short
70 // relative to the distance from the N or S poles.
71 double distances[] = new double[nodes.size()];
72 double avdist = 0, latd, lond;
73 double lonscale = Math.cos(avn.coor.lat() * Math.PI/180.0);
74 lonscale = lonscale * lonscale;
75 int i = 0;
76 for (Node n : nodes) {
77 latd = n.coor.lat() - avn.coor.lat();
78 lond = n.coor.lon() - avn.coor.lon();
79 distances[i] = Math.sqrt(latd * latd + lonscale * lond * lond);
80 avdist += distances[i++];
81 }
82 avdist = avdist / nodes.size();
83
84 Collection<Command> cmds = new LinkedList<Command>();
85 // Move each node to that distance from the centre.
86 i = 0;
87 for (Node n : nodes) {
88 double dx = n.eastNorth.east() - avn.eastNorth.east();
89 double dy = n.eastNorth.north() - avn.eastNorth.north();
90 double dist = distances[i++];
91 cmds.add(new MoveCommand(n, (dx * (avdist / dist)) - dx, (dy * (avdist / dist)) - dy));
92 }
93
94 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
95 Main.map.repaint();
96 }
97}
Note: See TracBrowser for help on using the repository browser.