source: josm/trunk/src/org/openstreetmap/josm/command/RotateCommand.java@ 3275

Last change on this file since 3275 was 3262, checked in by bastiK, 14 years ago

extended command list dialog; added inspection panel

  • Property svn:eol-style set to native
File size: 4.5 KB
Line 
1package org.openstreetmap.josm.command;
2
3import static org.openstreetmap.josm.tools.I18n.trn;
4
5import java.util.Collection;
6import java.util.HashMap;
7import java.util.LinkedList;
8import java.util.Map;
9
10import javax.swing.JLabel;
11
12import org.openstreetmap.josm.data.coor.EastNorth;
13import org.openstreetmap.josm.data.coor.LatLon;
14import org.openstreetmap.josm.data.osm.Node;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
17import org.openstreetmap.josm.tools.ImageProvider;
18
19/**
20 * RotateCommand rotates a number of objects around their centre.
21 *
22 * @author Frederik Ramm <frederik@remote.org>
23 */
24public class RotateCommand extends Command {
25
26 /**
27 * The objects to rotate.
28 */
29 private Collection<Node> nodes = new LinkedList<Node>();
30
31 /**
32 * pivot point
33 */
34 private EastNorth pivot;
35
36 /**
37 * Small helper for holding the interesting part of the old data state of the
38 * objects.
39 */
40 public static class OldState {
41 LatLon latlon;
42 EastNorth eastNorth;
43 boolean modified;
44 }
45
46 /**
47 * angle of rotation starting click to pivot
48 */
49 private double startAngle;
50
51 /**
52 * computed rotation angle between starting click and current mouse pos
53 */
54 private double rotationAngle;
55
56 /**
57 * List of all old states of the objects.
58 */
59 private Map<Node, OldState> oldState = new HashMap<Node, OldState>();
60
61 /**
62 * Creates a RotateCommand.
63 * Assign the initial object set, compute pivot point and rotation angle.
64 * Computation of pivot point is done by the same rules that are used in
65 * the "align nodes in circle" action.
66 */
67 public RotateCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {
68
69 this.nodes = AllNodesVisitor.getAllNodes(objects);
70 pivot = new EastNorth(0,0);
71
72 for (Node n : this.nodes) {
73 OldState os = new OldState();
74 os.latlon = new LatLon(n.getCoor());
75 os.eastNorth = n.getEastNorth();
76 os.modified = n.isModified();
77 oldState.put(n, os);
78 pivot = pivot.add(os.eastNorth.east(), os.eastNorth.north());
79 }
80 pivot = new EastNorth(pivot.east()/this.nodes.size(), pivot.north()/this.nodes.size());
81
82 rotationAngle = Math.PI/2;
83 rotateAgain(start, end);
84 }
85
86 /**
87 * Rotate the same set of objects again, by the angle between given
88 * start and end nodes. Internally this is added to the existing
89 * rotation so a later undo will undo the whole rotation.
90 */
91 public void rotateAgain(EastNorth start, EastNorth end) {
92 // compute angle
93 startAngle = Math.atan2(start.east()-pivot.east(), start.north()-pivot.north());
94 double endAngle = Math.atan2(end.east()-pivot.east(), end.north()-pivot.north());
95 rotationAngle += startAngle - endAngle;
96 rotateNodes(false);
97 }
98
99 /**
100 * Helper for actually rotationg the nodes.
101 * @param setModified - true if rotated nodes should be flagged "modified"
102 */
103 private void rotateNodes(boolean setModified) {
104 for (Node n : nodes) {
105 double cosPhi = Math.cos(rotationAngle);
106 double sinPhi = Math.sin(rotationAngle);
107 EastNorth oldEastNorth = oldState.get(n).eastNorth;
108 double x = oldEastNorth.east() - pivot.east();
109 double y = oldEastNorth.north() - pivot.north();
110 double nx = sinPhi * x + cosPhi * y + pivot.east();
111 double ny = -cosPhi * x + sinPhi * y + pivot.north();
112 n.setEastNorth(new EastNorth(nx, ny));
113 if (setModified) {
114 n.setModified(true);
115 }
116 }
117 }
118
119 @Override public boolean executeCommand() {
120 rotateNodes(true);
121 return true;
122 }
123
124 @Override public void undoCommand() {
125 for (Node n : nodes) {
126 OldState os = oldState.get(n);
127 n.setCoor(os.latlon);
128 n.setModified(os.modified);
129 }
130 }
131
132 @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
133 for (OsmPrimitive osm : nodes) {
134 modified.add(osm);
135 }
136 }
137
138 @Override public JLabel getDescription() {
139 return new JLabel(trn("Rotate {0} node", "Rotate {0} nodes", nodes.size(), nodes.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL);
140 }
141
142 public Collection<Node> getRotatedNodes() {
143 return nodes;
144 }
145}
Note: See TracBrowser for help on using the repository browser.