1 package nl.tudelft.simulation.dsol.web.animation.D2;
2
3 import java.awt.Color;
4 import java.awt.Dimension;
5 import java.awt.geom.Rectangle2D;
6 import java.rmi.RemoteException;
7 import java.util.ArrayList;
8 import java.util.LinkedHashMap;
9 import java.util.LinkedHashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13 import java.util.SortedSet;
14 import java.util.TreeSet;
15
16 import javax.media.j3d.BoundingBox;
17 import javax.vecmath.Point3d;
18 import javax.vecmath.Point4i;
19
20 import org.djutils.event.EventInterface;
21 import org.djutils.event.EventListenerInterface;
22 import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
23
24 import nl.javel.gisbeans.map.MapInterface;
25 import nl.tudelft.simulation.dsol.animation.Locatable;
26 import nl.tudelft.simulation.dsol.animation.D2.GisRenderable2D;
27 import nl.tudelft.simulation.dsol.animation.D2.Renderable2DComparator;
28 import nl.tudelft.simulation.dsol.animation.D2.Renderable2DInterface;
29 import nl.tudelft.simulation.dsol.experiment.Replication;
30 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
31 import nl.tudelft.simulation.dsol.web.animation.HTMLGraphics2D;
32 import nl.tudelft.simulation.language.d3.DirectedPoint;
33 import nl.tudelft.simulation.naming.context.ContextInterface;
34 import nl.tudelft.simulation.naming.context.util.ContextUtil;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public class HTMLAnimationPanel extends HTMLGridPanel implements EventListenerInterface
51 {
52
53 private SortedSet<Renderable2DInterface<? extends Locatable>> elements =
54 new TreeSet<Renderable2DInterface<? extends Locatable>>(new Renderable2DComparator());
55
56
57 private Map<Class<? extends Locatable>, Boolean> visibilityMap = new LinkedHashMap<>();
58
59
60 private Set<Class<? extends Locatable>> hiddenClasses = new LinkedHashSet<>();
61
62
63 private Set<Class<? extends Locatable>> shownClasses = new LinkedHashSet<>();
64
65
66 private SimulatorInterface<?, ?, ?> simulator;
67
68
69 private ContextInterface context = null;
70
71
72 private Point4i dragLine = new Point4i();
73
74
75 private boolean dragLineEnabled = false;
76
77
78 private List<Renderable2DInterface<? extends Locatable>> elementList = new ArrayList<>();
79
80
81 private boolean dirtyElements = false;
82
83
84 private Map<String, Class<? extends Locatable>> toggleLocatableMap = new LinkedHashMap<>();
85
86
87 private Map<Class<? extends Locatable>, ToggleButtonInfo> toggleButtonMap = new LinkedHashMap<>();
88
89
90 private Map<String, MapInterface> toggleGISMap = new LinkedHashMap<>();
91
92
93 private Map<String, ToggleButtonInfo> toggleGISButtonMap = new LinkedHashMap<>();
94
95
96 private List<ToggleButtonInfo> toggleButtons = new ArrayList<>();
97
98
99 private GTUColorer gtuColorer = null;
100
101
102
103
104
105
106
107
108 public HTMLAnimationPanel(final Rectangle2D extent, final Dimension size, final SimulatorInterface<?, ?, ?> simulator)
109 throws RemoteException
110 {
111 super(extent, size);
112 super.showGrid = true;
113 this.simulator = simulator;
114 simulator.addListener(this, Replication.START_REPLICATION_EVENT);
115 }
116
117
118 @Override
119 public void paintComponent(final HTMLGraphics2D g2)
120 {
121
122 super.paintComponent(g2);
123
124
125 if (this.dirtyElements)
126 {
127 synchronized (this.elementList)
128 {
129 this.elementList.clear();
130 this.elementList.addAll(this.elements);
131 this.dirtyElements = false;
132 }
133 }
134
135
136 for (Renderable2DInterface<? extends Locatable> element : this.elementList)
137 {
138 if (isShowElement(element))
139 {
140 element.paint(g2, this.getExtent(), this.getSize(), this);
141 }
142 }
143
144
145 if (this.dragLineEnabled)
146 {
147 g2.setColor(Color.BLACK);
148 g2.drawLine(this.dragLine.w, this.dragLine.x, this.dragLine.y, this.dragLine.z);
149 this.dragLineEnabled = false;
150 }
151 }
152
153
154
155
156
157
158 public boolean isShowElement(final Renderable2DInterface<? extends Locatable> element)
159 {
160 return isShowClass(element.getSource().getClass());
161 }
162
163
164
165
166
167
168
169 public boolean isShowClass(final Class<? extends Locatable> locatableClass)
170 {
171 if (this.hiddenClasses.contains(locatableClass))
172 {
173 return false;
174 }
175 else
176 {
177 boolean show = true;
178 if (!this.shownClasses.contains(locatableClass))
179 {
180 for (Class<? extends Locatable> lc : this.visibilityMap.keySet())
181 {
182 if (lc.isAssignableFrom(locatableClass))
183 {
184 if (!this.visibilityMap.get(lc))
185 {
186 show = false;
187 }
188 }
189 }
190
191 if (show)
192 {
193 this.shownClasses.add(locatableClass);
194 }
195 else
196 {
197 this.hiddenClasses.add(locatableClass);
198 }
199 }
200 return show;
201 }
202 }
203
204
205 @SuppressWarnings("unchecked")
206 @Override
207 public void notify(final EventInterface event) throws RemoteException
208 {
209 if (event.getType().equals(ContextInterface.OBJECT_ADDED_EVENT))
210 {
211 objectAdded((Renderable2DInterface<? extends Locatable>) ((Object[]) event.getContent())[2]);
212 }
213
214 else if (event.getType().equals(ContextInterface.OBJECT_REMOVED_EVENT))
215 {
216 objectRemoved((Renderable2DInterface<? extends Locatable>) ((Object[]) event.getContent())[2]);
217 }
218
219 else if
220 (event.getType().equals(Replication.START_REPLICATION_EVENT))
221 {
222 synchronized (this.elementList)
223 {
224 this.elements.clear();
225 try
226 {
227 if (this.context != null)
228 {
229 this.context.removeListener(this, ContextInterface.OBJECT_ADDED_EVENT);
230 this.context.removeListener(this, ContextInterface.OBJECT_REMOVED_EVENT);
231 }
232
233 this.context =
234 ContextUtil.lookupOrCreateSubContext(this.simulator.getReplication().getContext(), "animation/2D");
235 this.context.addListener(this, ContextInterface.OBJECT_ADDED_EVENT);
236 this.context.addListener(this, ContextInterface.OBJECT_REMOVED_EVENT);
237 for (Object element : this.context.values())
238 {
239 objectAdded((Renderable2DInterface<? extends Locatable>) element);
240 }
241 this.repaint();
242 }
243 catch (Exception exception)
244 {
245 this.simulator.getLogger().always().warn(exception, "notify");
246 }
247 }
248 }
249 }
250
251
252
253
254
255 public void objectAdded(final Renderable2DInterface<? extends Locatable> element)
256 {
257 synchronized (this.elementList)
258 {
259 this.elements.add(element);
260 this.dirtyElements = true;
261 }
262 }
263
264
265
266
267
268 public void objectRemoved(final Renderable2DInterface<? extends Locatable> element)
269 {
270 synchronized (this.elementList)
271 {
272 this.elements.remove(element);
273 this.dirtyElements = true;
274 }
275 }
276
277
278
279
280
281 public synchronized Rectangle2D fullExtent()
282 {
283 double minX = Double.MAX_VALUE;
284 double maxX = -Double.MAX_VALUE;
285 double minY = Double.MAX_VALUE;
286 double maxY = -Double.MAX_VALUE;
287 Point3d p3dL = new Point3d();
288 Point3d p3dU = new Point3d();
289 try
290 {
291 for (Renderable2DInterface<? extends Locatable> renderable : this.elementList)
292 {
293 DirectedPoint l = renderable.getSource().getLocation();
294 BoundingBox b = new BoundingBox(renderable.getSource().getBounds());
295 b.getLower(p3dL);
296 b.getUpper(p3dU);
297 minX = Math.min(minX, l.x + Math.min(p3dL.x, p3dU.x));
298 minY = Math.min(minY, l.y + Math.min(p3dL.y, p3dU.y));
299 maxX = Math.max(maxX, l.x + Math.max(p3dL.x, p3dU.x));
300 maxY = Math.max(maxY, l.y + Math.max(p3dL.y, p3dU.y));
301 }
302 }
303 catch (Exception e)
304 {
305
306 }
307
308 minX = minX - 0.05 * Math.abs(minX);
309 minY = minY - 0.05 * Math.abs(minY);
310 maxX = maxX + 0.05 * Math.abs(maxX);
311 maxY = maxY + 0.05 * Math.abs(maxY);
312
313 return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
314 }
315
316
317
318
319 public synchronized void zoomAll()
320 {
321 this.extent = Renderable2DInterface.Util.computeVisibleExtent(fullExtent(), this.getSize());
322 this.repaint();
323 }
324
325
326
327
328
329 public void showClass(final Class<? extends Locatable> locatableClass)
330 {
331 this.visibilityMap.put(locatableClass, true);
332 this.shownClasses.clear();
333 this.hiddenClasses.clear();
334 this.repaint();
335 }
336
337
338
339
340
341 public void hideClass(final Class<? extends Locatable> locatableClass)
342 {
343 this.visibilityMap.put(locatableClass, false);
344 this.shownClasses.clear();
345 this.hiddenClasses.clear();
346 this.repaint();
347 }
348
349
350
351
352
353
354 public void toggleClass(final Class<? extends Locatable> locatableClass)
355 {
356 if (!this.visibilityMap.containsKey(locatableClass))
357 {
358 showClass(locatableClass);
359 }
360 this.visibilityMap.put(locatableClass, !this.visibilityMap.get(locatableClass));
361 this.shownClasses.clear();
362 this.hiddenClasses.clear();
363 this.repaint();
364 }
365
366
367
368
369 public final SortedSet<Renderable2DInterface<? extends Locatable>> getElements()
370 {
371 return this.elements;
372 }
373
374
375
376
377 public final Point4i getDragLine()
378 {
379 return this.dragLine;
380 }
381
382
383
384
385 public final boolean isDragLineEnabled()
386 {
387 return this.dragLineEnabled;
388 }
389
390
391
392
393 public final void setDragLineEnabled(final boolean dragLineEnabled)
394 {
395 this.dragLineEnabled = dragLineEnabled;
396 }
397
398
399
400
401
402
403
404
405
406
407
408
409 public final void addToggleAnimationButtonText(final String name, final Class<? extends Locatable> locatableClass,
410 final String toolTipText, final boolean initiallyVisible)
411 {
412 ToggleButtonInfo.LocatableClass buttonInfo =
413 new ToggleButtonInfo.LocatableClass(name, locatableClass, toolTipText, initiallyVisible);
414 if (initiallyVisible)
415 {
416 showClass(locatableClass);
417 }
418 else
419 {
420 hideClass(locatableClass);
421 }
422 this.toggleButtons.add(buttonInfo);
423 this.toggleLocatableMap.put(name, locatableClass);
424 this.toggleButtonMap.put(locatableClass, buttonInfo);
425 }
426
427
428
429
430
431 public final void showClass(final String name)
432 {
433 showClass(this.toggleLocatableMap.get(name));
434 }
435
436
437
438
439
440 public final void hideClass(final String name)
441 {
442 hideClass(this.toggleLocatableMap.get(name));
443 }
444
445
446
447
448
449 public final void addToggleText(final String text)
450 {
451 this.toggleButtons.add(new ToggleButtonInfo.Text(text, true));
452 }
453
454
455
456
457
458
459
460 public final void addAllToggleGISButtonText(final String header, final GisRenderable2D gisMap, final String toolTipText)
461 {
462 addToggleText(" ");
463 addToggleText(header);
464 try
465 {
466 for (String layerName : gisMap.getMap().getLayerMap().keySet())
467 {
468 addToggleGISButtonText(layerName, layerName, gisMap, toolTipText);
469 }
470 }
471 catch (RemoteException exception)
472 {
473 exception.printStackTrace();
474 }
475 }
476
477
478
479
480
481
482
483
484 public final void addToggleGISButtonText(final String layerName, final String displayName, final GisRenderable2D gisMap,
485 final String toolTipText)
486 {
487 ToggleButtonInfo.Gis buttonInfo = new ToggleButtonInfo.Gis(displayName, layerName, toolTipText, true);
488 this.toggleButtons.add(buttonInfo);
489 this.toggleGISMap.put(layerName, gisMap.getMap());
490 this.toggleGISButtonMap.put(layerName, buttonInfo);
491 }
492
493
494
495
496
497 public final void showGISLayer(final String layerName)
498 {
499 MapInterface gisMap = this.toggleGISMap.get(layerName);
500 if (gisMap != null)
501 {
502 try
503 {
504 gisMap.showLayer(layerName);
505 this.toggleGISButtonMap.get(layerName).setVisible(true);
506 }
507 catch (RemoteException exception)
508 {
509 exception.printStackTrace();
510 }
511 }
512 }
513
514
515
516
517
518 public final void hideGISLayer(final String layerName)
519 {
520 MapInterface gisMap = this.toggleGISMap.get(layerName);
521 if (gisMap != null)
522 {
523 try
524 {
525 gisMap.hideLayer(layerName);
526 this.toggleGISButtonMap.get(layerName).setVisible(false);
527 }
528 catch (RemoteException exception)
529 {
530 exception.printStackTrace();
531 }
532 }
533 }
534
535
536
537
538
539 public final void toggleGISLayer(final String layerName)
540 {
541 MapInterface gisMap = this.toggleGISMap.get(layerName);
542 if (gisMap != null)
543 {
544 try
545 {
546 if (gisMap.getVisibleLayers().contains(gisMap.getLayerMap().get(layerName)))
547 {
548 gisMap.hideLayer(layerName);
549 this.toggleGISButtonMap.get(layerName).setVisible(false);
550 }
551 else
552 {
553 gisMap.showLayer(layerName);
554 this.toggleGISButtonMap.get(layerName).setVisible(true);
555 }
556 }
557 catch (RemoteException exception)
558 {
559 exception.printStackTrace();
560 }
561 }
562 }
563
564
565
566
567 public final List<ToggleButtonInfo> getToggleButtons()
568 {
569 return this.toggleButtons;
570 }
571
572 }