source: josm/trunk/src/org/openstreetmap/josm/command/MoveCommand.java@ 9231

Last change on this file since 9231 was 9231, checked in by Don-vip, 8 years ago

javadoc update

  • Property svn:eol-style set to native
File size: 9.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.command;
3
4import static org.openstreetmap.josm.tools.I18n.trn;
5
6import java.util.Collection;
7import java.util.Collections;
8import java.util.Iterator;
9import java.util.LinkedList;
10import java.util.List;
11
12import javax.swing.Icon;
13
14import org.openstreetmap.josm.data.coor.EastNorth;
15import org.openstreetmap.josm.data.coor.LatLon;
16import org.openstreetmap.josm.data.osm.Node;
17import org.openstreetmap.josm.data.osm.OsmPrimitive;
18import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
19import org.openstreetmap.josm.data.projection.Projections;
20import org.openstreetmap.josm.tools.ImageProvider;
21
22/**
23 * MoveCommand moves a set of OsmPrimitives along the map. It can be moved again
24 * to collect several MoveCommands into one command.
25 *
26 * @author imi
27 */
28public class MoveCommand extends Command {
29 /**
30 * The objects that should be moved.
31 */
32 private Collection<Node> nodes = new LinkedList<>();
33 /**
34 * Starting position, base command point, current (mouse-drag) position = startEN + (x,y) =
35 */
36 private EastNorth startEN;
37
38 /**
39 * x difference movement. Coordinates are in northern/eastern
40 */
41 private double x;
42 /**
43 * y difference movement. Coordinates are in northern/eastern
44 */
45 private double y;
46
47 private double backupX;
48 private double backupY;
49
50 /**
51 * List of all old states of the objects.
52 */
53 private final List<OldNodeState> oldState = new LinkedList<>();
54
55 /**
56 * Constructs a new {@code MoveCommand} to move a primitive.
57 * @param osm The primitive to move
58 * @param x X difference movement. Coordinates are in northern/eastern
59 * @param y Y difference movement. Coordinates are in northern/eastern
60 */
61 public MoveCommand(OsmPrimitive osm, double x, double y) {
62 this(Collections.singleton(osm), x, y);
63 }
64
65 /**
66 * Constructs a new {@code MoveCommand} to move a node.
67 * @param node The node to move
68 * @param position The new location (lat/lon)
69 */
70 public MoveCommand(Node node, LatLon position) {
71 this(Collections.singleton((OsmPrimitive) node), Projections.project(position).subtract(node.getEastNorth()));
72 }
73
74 /**
75 * Constructs a new {@code MoveCommand} to move a collection of primitives.
76 * @param objects The primitives to move
77 * @param offset The movement vector
78 */
79 public MoveCommand(Collection<OsmPrimitive> objects, EastNorth offset) {
80 this(objects, offset.getX(), offset.getY());
81 }
82
83 /**
84 * Constructs a new {@code MoveCommand} and assign the initial object set and movement vector.
85 * @param objects The primitives to move
86 * @param x X difference movement. Coordinates are in northern/eastern
87 * @param y Y difference movement. Coordinates are in northern/eastern
88 */
89 public MoveCommand(Collection<OsmPrimitive> objects, double x, double y) {
90 startEN = null;
91 saveCheckpoint(); // (0,0) displacement will be saved
92 this.x = x;
93 this.y = y;
94 this.nodes = AllNodesVisitor.getAllNodes(objects);
95 for (Node n : this.nodes) {
96 oldState.add(new OldNodeState(n));
97 }
98 }
99
100 /**
101 * Constructs a new {@code MoveCommand} to move a collection of primitives.
102 * @param objects The primitives to move
103 * @param start The starting position (northern/eastern)
104 * @param end The ending position (northern/eastern)
105 */
106 public MoveCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {
107 this(objects, end.getX()-start.getX(), end.getY()-start.getY());
108 startEN = start;
109 }
110
111 /**
112 * Constructs a new {@code MoveCommand} to move a primitive.
113 * @param p The primitive to move
114 * @param start The starting position (northern/eastern)
115 * @param end The ending position (northern/eastern)
116 */
117 public MoveCommand(OsmPrimitive p, EastNorth start, EastNorth end) {
118 this(Collections.singleton(p), end.getX()-start.getX(), end.getY()-start.getY());
119 startEN = start;
120 }
121
122 /**
123 * Move the same set of objects again by the specified vector. The vectors
124 * are added together and so the resulting will be moved to the previous
125 * vector plus this one.
126 *
127 * The move is immediately executed and any undo will undo both vectors to
128 * the original position the objects had before first moving.
129 *
130 * @param x X difference movement. Coordinates are in northern/eastern
131 * @param y Y difference movement. Coordinates are in northern/eastern
132 */
133 public void moveAgain(double x, double y) {
134 for (Node n : nodes) {
135 n.setEastNorth(n.getEastNorth().add(x, y));
136 }
137 this.x += x;
138 this.y += y;
139 }
140
141 /**
142 * Move again to the specified coordinates.
143 * @param x X coordinate
144 * @param y Y coordinate
145 * @see #moveAgain
146 */
147 public void moveAgainTo(double x, double y) {
148 moveAgain(x - this.x, y - this.y);
149 }
150
151 /**
152 * Change the displacement vector to have endpoint {@code currentEN}.
153 * starting point is startEN
154 * @param currentEN the new endpoint
155 */
156 public void applyVectorTo(EastNorth currentEN) {
157 if (startEN == null)
158 return;
159 x = currentEN.getX() - startEN.getX();
160 y = currentEN.getY() - startEN.getY();
161 updateCoordinates();
162 }
163
164 /**
165 * Changes base point of movement
166 * @param newDraggedStartPoint - new starting point after movement (where user clicks to start new drag)
167 */
168 public void changeStartPoint(EastNorth newDraggedStartPoint) {
169 startEN = new EastNorth(newDraggedStartPoint.getX()-x, newDraggedStartPoint.getY()-y);
170 }
171
172 /**
173 * Save curent displacement to restore in case of some problems
174 */
175 public final void saveCheckpoint() {
176 backupX = x;
177 backupY = y;
178 }
179
180 /**
181 * Restore old displacement in case of some problems
182 */
183 public void resetToCheckpoint() {
184 x = backupX;
185 y = backupY;
186 updateCoordinates();
187 }
188
189 private void updateCoordinates() {
190 Iterator<OldNodeState> it = oldState.iterator();
191 for (Node n : nodes) {
192 OldNodeState os = it.next();
193 if (os.getEastNorth() != null) {
194 n.setEastNorth(os.getEastNorth().add(x, y));
195 }
196 }
197 }
198
199 @Override
200 public boolean executeCommand() {
201 for (Node n : nodes) {
202 // in case #3892 happens again
203 if (n == null)
204 throw new AssertionError("null detected in node list");
205 EastNorth en = n.getEastNorth();
206 if (en != null) {
207 n.setEastNorth(en.add(x, y));
208 n.setModified(true);
209 }
210 }
211 return true;
212 }
213
214 @Override
215 public void undoCommand() {
216 Iterator<OldNodeState> it = oldState.iterator();
217 for (Node n : nodes) {
218 OldNodeState os = it.next();
219 n.setCoor(os.getLatlon());
220 n.setModified(os.isModified());
221 }
222 }
223
224 @Override
225 public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
226 for (OsmPrimitive osm : nodes) {
227 modified.add(osm);
228 }
229 }
230
231 @Override
232 public String getDescriptionText() {
233 return trn("Move {0} node", "Move {0} nodes", nodes.size(), nodes.size());
234 }
235
236 @Override
237 public Icon getDescriptionIcon() {
238 return ImageProvider.get("data", "node");
239 }
240
241 @Override
242 public Collection<Node> getParticipatingPrimitives() {
243 return nodes;
244 }
245
246 @Override
247 public int hashCode() {
248 final int prime = 31;
249 int result = super.hashCode();
250 long temp;
251 temp = Double.doubleToLongBits(backupX);
252 result = prime * result + (int) (temp ^ (temp >>> 32));
253 temp = Double.doubleToLongBits(backupY);
254 result = prime * result + (int) (temp ^ (temp >>> 32));
255 result = prime * result + ((nodes == null) ? 0 : nodes.hashCode());
256 result = prime * result + ((oldState == null) ? 0 : oldState.hashCode());
257 result = prime * result + ((startEN == null) ? 0 : startEN.hashCode());
258 temp = Double.doubleToLongBits(x);
259 result = prime * result + (int) (temp ^ (temp >>> 32));
260 temp = Double.doubleToLongBits(y);
261 result = prime * result + (int) (temp ^ (temp >>> 32));
262 return result;
263 }
264
265 @Override
266 public boolean equals(Object obj) {
267 if (this == obj)
268 return true;
269 if (!super.equals(obj))
270 return false;
271 if (getClass() != obj.getClass())
272 return false;
273 MoveCommand other = (MoveCommand) obj;
274 if (Double.doubleToLongBits(backupX) != Double.doubleToLongBits(other.backupX))
275 return false;
276 if (Double.doubleToLongBits(backupY) != Double.doubleToLongBits(other.backupY))
277 return false;
278 if (nodes == null) {
279 if (other.nodes != null)
280 return false;
281 } else if (!nodes.equals(other.nodes))
282 return false;
283 if (oldState == null) {
284 if (other.oldState != null)
285 return false;
286 } else if (!oldState.equals(other.oldState))
287 return false;
288 if (startEN == null) {
289 if (other.startEN != null)
290 return false;
291 } else if (!startEN.equals(other.startEN))
292 return false;
293 if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
294 return false;
295 if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
296 return false;
297 return true;
298 }
299}
Note: See TracBrowser for help on using the repository browser.