1
2
3
4
5
6
7 package nl.tudelft.simulation.dsol.gui.editor2D.actions;
8
9 import java.awt.geom.Point2D;
10 import java.lang.reflect.Constructor;
11 import java.rmi.RemoteException;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15
16 import nl.tudelft.simulation.dsol.animation.Editable;
17 import nl.tudelft.simulation.dsol.animation.D2.EditableRenderable2DInterface;
18 import nl.tudelft.simulation.dsol.animation.D2.Renderable2DInterface;
19 import nl.tudelft.simulation.dsol.gui.DSOLApplicationInterface;
20 import nl.tudelft.simulation.dsol.gui.editor2D.Editor2DPanel;
21 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
22 import nl.tudelft.simulation.language.d3.CartesianPoint;
23 import nl.tudelft.simulation.language.d3.DirectedPoint;
24 import nl.tudelft.simulation.language.reflection.ClassUtil;
25 import nl.tudelft.simulation.logger.Logger;
26
27 /***
28 * Utility methods to select, create, edit and delete editables
29 * <p>
30 * (c) copyright 2002-2005 <a href="http://www.simulation.tudelft.nl">Delft
31 * University of Technology </a>, the Netherlands. <br>
32 * See for project information <a
33 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a> <br>
34 * License of use: <a href="http://www.gnu.org/copyleft/lesser.html">Lesser
35 * General Public License (LGPL) </a>, no warranty.
36 *
37 * @version $Revision$ $Date$
38 * @author <a href="http://www.tbm.tudelft.nl/webstaf/royc/index.htm">Roy Chin
39 * </a>
40 */
41 public final class EditorUtilities
42 {
43
44 /*** the default offset value in x and y dirextion for new points */
45 public static final int DEFAULT_OFFSET = 8;
46
47 /*** a hidden constructor */
48 private EditorUtilities()
49 {
50
51 }
52
53 /***
54 * determine the selected object
55 *
56 * @param worldCoordinate point in world coordinates
57 * @param panel the editable animation panel
58 * @return the selected renderable
59 */
60 public static Renderable2DInterface selectEditable(
61 final Point2D worldCoordinate, final Editor2DPanel panel)
62 {
63
64 Renderable2DInterface selected = EditorUtilities.determineSelected(
65 worldCoordinate, panel);
66 if (selected == null)
67 {
68 panel.setSelectedEditableRenderable(null);
69 } else
70 {
71 try
72 {
73 if (selected instanceof EditableRenderable2DInterface)
74 {
75 panel
76 .setSelectedEditableRenderable((EditableRenderable2DInterface) selected);
77 }
78 } catch (ClassCastException exception)
79 {
80 Logger.warning(EditorUtilities.class, "selectEditable",
81 exception);
82 }
83 }
84 return selected;
85 }
86
87 /***
88 * instantiate a new editable
89 *
90 * @param worldCoordinate point in world coordinates
91 * @param application the application
92 * @param panel the editable animation panel
93 */
94 public static void instantiateNewEditable(final Point2D worldCoordinate,
95 final DSOLApplicationInterface application,
96 final Editor2DPanel panel)
97 {
98 panel.setSelectedEditableRenderable(null);
99 Class editableClass = panel.getSelectedRenderableClass();
100
101
102 try
103 {
104
105 Class[] argsClass = new Class[]{SimulatorInterface.class,
106 DirectedPoint.class};
107 Object[] args = new Object[]{
108 application.getExperiment().getSimulator(),
109 new DirectedPoint(worldCoordinate.getX(), worldCoordinate
110 .getY(), 0)};
111 Constructor constructor = ClassUtil.resolveConstructor(
112 editableClass, argsClass);
113 constructor.newInstance(args);
114 } catch (Exception exception)
115 {
116 Logger.warning(EditorUtilities.class, "instantiateNewEditable",
117 exception);
118 }
119 }
120
121 /***
122 * move the selected control point
123 *
124 * @param target the editableRenderable which is moved.
125 * @param worldCoordinate point in world coordinates where to move to
126 * @param panel the Editor2D panel
127 */
128 public static void moveSelectedPoint(
129 final EditableRenderable2DInterface target,
130 final Point2D worldCoordinate, final Editor2DPanel panel)
131 {
132 try
133 {
134 Editable editable = (Editable) target.getSource();
135 CartesianPoint[] vertices = editable.getVertices();
136
137 if (target.allowEditPoints())
138 {
139
140 CartesianPoint[] newPos = new CartesianPoint[vertices.length];
141 for (int i = 0; i < vertices.length; i++)
142 {
143 newPos[i] = new CartesianPoint();
144 if (vertices[i] == panel.getSelectedPoint())
145 {
146 CartesianPoint coord = EditorUtilities
147 .convertToLocalCoordinates(new CartesianPoint(
148 worldCoordinate.getX(), worldCoordinate
149 .getY(), 0), editable
150 .getLocation());
151
152 newPos[i].x = coord.x;
153 newPos[i].y = coord.y;
154 newPos[i].z = vertices[i].z;
155 } else
156 {
157 newPos[i].x = vertices[i].x;
158 newPos[i].y = vertices[i].y;
159 newPos[i].z = vertices[i].z;
160 }
161 }
162
163
164 editable.setVertices(newPos);
165 }
166 } catch (RemoteException exception)
167 {
168 Logger.warning(EditorUtilities.class, "moveSelectedPoint",
169 exception);
170 }
171 }
172
173 /***
174 * move the object
175 *
176 * @param target the target editable renderable
177 * @param newCoordinate Point in world coordinates where to move to
178 * @param oldCoordinate Point in world coordinates where the mouse was the
179 * last iteration, because we move relative to this coordinate
180 */
181 public static void moveEditable(final EditableRenderable2DInterface target,
182 final Point2D newCoordinate, final Point2D oldCoordinate)
183 {
184 try
185 {
186 Editable editable = (Editable) target.getSource();
187 if (editable != null)
188 {
189 if (target.allowMove())
190 {
191 double dx = newCoordinate.getX() - oldCoordinate.getX();
192 double dy = newCoordinate.getY() - oldCoordinate.getY();
193 DirectedPoint location = editable.getLocation();
194 location.x += dx;
195 location.y += dy;
196 }
197 }
198 } catch (RemoteException exception)
199 {
200 Logger.warning(EditorUtilities.class, "moveEditable", exception);
201 }
202 }
203
204 /***
205 * rotate the editable
206 *
207 * @param target the target editable renderable
208 * @param newCoordinate point in world coordinates where to rotate to
209 * @param oldCoordinate Point in world coordinates where the mouse was the
210 * last iteration, because we move relative to this coordinate
211 * @param centerCoordinate the center of rotation in world coordinates
212 */
213 public static void rotateEditable(
214 final EditableRenderable2DInterface target,
215 final Point2D newCoordinate, final Point2D centerCoordinate,
216 final Point2D oldCoordinate)
217 {
218 try
219 {
220 Editable editable = (Editable) target.getSource();
221 if (editable != null)
222 {
223 if (target.allowRotate())
224 {
225 double dx = newCoordinate.getX() - oldCoordinate.getX();
226 double dy = newCoordinate.getY() - oldCoordinate.getY();
227 double dxR = oldCoordinate.getX() - centerCoordinate.getX();
228 double dyR = oldCoordinate.getY() - centerCoordinate.getY();
229 double dxR2 = newCoordinate.getX()
230 - centerCoordinate.getX();
231 double dyR2 = newCoordinate.getY()
232 - centerCoordinate.getY();
233 double distY = Math.sqrt(dx * dx + dy * dy);
234 double distX = Math.sqrt(dxR * dxR + dyR * dyR);
235 int factor = 1;
236 if (Math.atan2(dyR, dxR) > Math.atan2(dyR2, dxR2))
237 {
238 factor = -1;
239 }
240
241 double angle = factor * Math.atan2(distY, distX);
242
243
244 DirectedPoint location = editable.getLocation();
245 double dxP = location.x - centerCoordinate.getX();
246 double dyP = location.y - centerCoordinate.getY();
247 double distanceP = Math.sqrt(dxP * dxP + dyP * dyP);
248 double angleP = Math.atan2(dyP, dxP);
249 location.x = centerCoordinate.getX() + distanceP
250 * Math.cos(angle + angleP);
251 location.y = centerCoordinate.getY() + distanceP
252 * Math.sin(angle + angleP);
253 location.setRotZ(angle + location.getRotZ());
254 }
255 }
256 } catch (RemoteException exception)
257 {
258 Logger.warning(EditorUtilities.class, "rotateEditable", exception);
259 }
260 }
261
262 /***
263 * delete the selected editable
264 *
265 * @param target the target editable renderable
266 * @param panel the editable animation panel
267 */
268 public static void deleteEditable(
269 final EditableRenderable2DInterface target,
270 final Editor2DPanel panel)
271 {
272 Editable editable = (Editable) target.getSource();
273 if (editable != null)
274 {
275 try
276 {
277 if (target.allowDelete())
278 {
279 target.destroy();
280 panel.setSelectedEditableRenderable(null);
281 panel.setSelectedPoint(null);
282 panel.repaint();
283 }
284 } catch (RemoteException exception)
285 {
286 Logger.warning(EditorUtilities.class, "deleteEditable",
287 exception);
288 }
289 }
290 }
291
292 /***
293 * add a point behind the last point of the editable
294 *
295 * @param target the target editable renderable
296 * @param panel the animation panel
297 */
298 public static void addPointToEditable(
299 final EditableRenderable2DInterface target,
300 final Editor2DPanel panel)
301 {
302 try
303 {
304
305
306 double delta = EditorUtilities.DEFAULT_OFFSET
307 * Renderable2DInterface.Util.getScale(panel.getExtent(),
308 panel.getSize());
309
310 Editable editable = (Editable) target.getSource();
311 CartesianPoint[] vertices = editable.getVertices();
312
313
314 if ((target.allowAddOrDeletePoints())
315 && (vertices.length < target.getMaxNumberOfPoints()))
316 {
317 CartesianPoint[] newPos = new CartesianPoint[vertices.length + 1];
318 for (int i = 0; i < newPos.length; i++)
319 {
320 newPos[i] = new CartesianPoint();
321 if (i == (newPos.length - 1))
322 {
323 newPos[i].x = vertices[i - 1].x + delta;
324 newPos[i].y = vertices[i - 1].y + delta;
325 newPos[i].z = vertices[i - 1].z;
326 } else
327 {
328 newPos[i].x = vertices[i].x;
329 newPos[i].y = vertices[i].y;
330 newPos[i].z = vertices[i].z;
331 }
332 }
333 editable.setVertices(newPos);
334 panel.repaint();
335 }
336 } catch (RemoteException exception)
337 {
338 Logger.warning(EditorUtilities.class, "addPointToEditable",
339 exception);
340 }
341 }
342
343 /***
344 * determine selected object as the mouse CartesianPoint. This is the
345 * topmost target when objects overlap.
346 *
347 * @param worldCoordinate the selected point in world coordinates
348 * @param panel the editable animation panel
349 * @return a renderable if there is one at the selected point
350 */
351 public static Renderable2DInterface determineSelected(
352 final Point2D worldCoordinate, final Editor2DPanel panel)
353 {
354 Renderable2DInterface selected = null;
355 Renderable2DInterface previous = panel.getSelectedEditableRenderable();
356 List targets = EditorUtilities.determineTargets(worldCoordinate, panel);
357
358 if (previous != null)
359 {
360
361 int index = -1;
362 for (int i = 0; i < targets.size(); i++)
363 {
364 if (previous == (Renderable2DInterface) targets.get(i))
365 {
366 index = i;
367 }
368 }
369 if (index >= 0)
370 {
371 if (index + 1 < targets.size())
372 {
373 selected = (Renderable2DInterface) targets.get(index + 1);
374 } else
375 {
376 selected = (Renderable2DInterface) targets.get(0);
377 }
378 } else if (targets.size() > 0)
379 {
380 selected = (Renderable2DInterface) targets.get(0);
381 }
382 } else
383 {
384 try
385 {
386 double zValue = -Double.MAX_VALUE;
387 for (Iterator i = targets.iterator(); i.hasNext();)
388 {
389 Renderable2DInterface next = (Renderable2DInterface) i
390 .next();
391
392 double z = next.getSource().getLocation().z;
393 if (z > zValue)
394 {
395 zValue = z;
396 selected = next;
397 }
398
399 }
400 } catch (RemoteException exception)
401 {
402 Logger.warning(EditorUtilities.class, "determineSelected",
403 exception);
404 }
405
406 }
407
408 return selected;
409 }
410
411 /***
412 * determine the targeted objects at the mouse CartesianPoint
413 *
414 * @param worldCoordinate point in world coordinates
415 * @param panel the editable animation panel
416 * @return targeted objects
417 */
418 public static List determineTargets(final Point2D worldCoordinate,
419 final Editor2DPanel panel)
420 {
421 List targets = new ArrayList();
422 try
423 {
424 for (Iterator i = panel.getElements().iterator(); i.hasNext();)
425 {
426 Renderable2DInterface renderable = (Renderable2DInterface) i
427 .next();
428 if (renderable.contains(worldCoordinate, panel.getExtent(),
429 panel.getSize()))
430 {
431 targets.add(renderable);
432 }
433 }
434 } catch (Exception exception)
435 {
436 Logger
437 .warning(EditorUtilities.class, "determineTargets",
438 exception);
439 }
440 return targets;
441 }
442
443 /***
444 * converts a coordinate in local coordinates to global coordinates note:
445 * this works only for 2D
446 *
447 * @param point point in local coordinates
448 * @param location location vector
449 * @return point in global coordinates
450 */
451 public static CartesianPoint convertToGlobalCoordinates(
452 final CartesianPoint point, final DirectedPoint location)
453 {
454 CartesianPoint global = new CartesianPoint();
455
456 double angle = Math.atan2(point.y, point.x);
457 double length = Math.sqrt(point.x * point.x + point.y * point.y);
458 double rotation = location.getRotZ() + angle;
459 global.x = length * Math.cos(rotation);
460 global.y = length * Math.sin(rotation);
461
462
463 global.x += location.x;
464 global.y += location.y;
465 return global;
466 }
467
468 /***
469 * converts a coordinate in global coordinates to local coordinates note:
470 * this works only for 2D
471 *
472 * @param point point in local coordinates
473 * @param location location vector
474 * @return point in global coordinates
475 */
476 public static CartesianPoint convertToLocalCoordinates(
477 final CartesianPoint point, final DirectedPoint location)
478 {
479 CartesianPoint local = new CartesianPoint();
480
481
482 local.x = point.x - location.x;
483 local.y = point.y - location.y;
484
485
486 double angle = Math.atan2(local.y, local.x);
487 double length = Math.sqrt(local.x * local.x + local.y * local.y);
488 double rotation = angle - location.getRotZ();
489 local.x = length * Math.cos(rotation);
490 local.y = length * Math.sin(rotation);
491 return local;
492 }
493 }