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