1 package org.opentrafficsim.animation;
2
3 import java.awt.Color;
4 import java.rmi.RemoteException;
5 import java.util.Collections;
6 import java.util.LinkedHashMap;
7 import java.util.Map;
8 import java.util.Optional;
9
10 import javax.naming.NamingException;
11
12 import org.djutils.event.Event;
13 import org.djutils.event.EventListener;
14 import org.djutils.exceptions.Throw;
15 import org.opentrafficsim.animation.PerceptionAnimation.ChannelAttention;
16 import org.opentrafficsim.animation.data.AnimationBusStopData;
17 import org.opentrafficsim.animation.data.AnimationConflictData;
18 import org.opentrafficsim.animation.data.AnimationCrossSectionElementData;
19 import org.opentrafficsim.animation.data.AnimationGtuData;
20 import org.opentrafficsim.animation.data.AnimationGtuGeneratorPositionData;
21 import org.opentrafficsim.animation.data.AnimationLaneData;
22 import org.opentrafficsim.animation.data.AnimationLaneDetectorData;
23 import org.opentrafficsim.animation.data.AnimationLinkData;
24 import org.opentrafficsim.animation.data.AnimationNodeData;
25 import org.opentrafficsim.animation.data.AnimationPriorityData;
26 import org.opentrafficsim.animation.data.AnimationShoulderData;
27 import org.opentrafficsim.animation.data.AnimationSpeedSignData;
28 import org.opentrafficsim.animation.data.AnimationStripeData;
29 import org.opentrafficsim.animation.data.AnimationTrafficLightData;
30 import org.opentrafficsim.animation.data.AnimationTrafficLightDetectorData;
31 import org.opentrafficsim.animation.gtu.colorer.GtuColorerManager;
32 import org.opentrafficsim.base.logger.Logger;
33 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
34 import org.opentrafficsim.core.gtu.Gtu;
35 import org.opentrafficsim.core.gtu.GtuGenerator.GtuGeneratorPosition;
36 import org.opentrafficsim.core.gtu.GtuType;
37 import org.opentrafficsim.core.network.Link;
38 import org.opentrafficsim.core.network.Network;
39 import org.opentrafficsim.core.network.Node;
40 import org.opentrafficsim.core.object.LocatedObject;
41 import org.opentrafficsim.core.object.NonLocatedObject;
42 import org.opentrafficsim.draw.gtu.DefaultCarAnimation;
43 import org.opentrafficsim.draw.gtu.DefaultCarAnimation.GtuData;
44 import org.opentrafficsim.draw.gtu.DefaultCarAnimation.GtuData.GtuMarker;
45 import org.opentrafficsim.draw.network.LinkAnimation;
46 import org.opentrafficsim.draw.network.NodeAnimation;
47 import org.opentrafficsim.draw.road.BusStopAnimation;
48 import org.opentrafficsim.draw.road.BusStopAnimation.BusStopData;
49 import org.opentrafficsim.draw.road.ConflictAnimation;
50 import org.opentrafficsim.draw.road.ConflictAnimation.ConflictData;
51 import org.opentrafficsim.draw.road.CrossSectionElementAnimation;
52 import org.opentrafficsim.draw.road.GtuGeneratorPositionAnimation;
53 import org.opentrafficsim.draw.road.GtuGeneratorPositionAnimation.GtuGeneratorPositionData;
54 import org.opentrafficsim.draw.road.LaneAnimation;
55 import org.opentrafficsim.draw.road.LaneDetectorAnimation;
56 import org.opentrafficsim.draw.road.LaneDetectorAnimation.LaneDetectorData;
57 import org.opentrafficsim.draw.road.PriorityAnimation;
58 import org.opentrafficsim.draw.road.SpeedSignAnimation;
59 import org.opentrafficsim.draw.road.SpeedSignAnimation.SpeedSignData;
60 import org.opentrafficsim.draw.road.StripeAnimation;
61 import org.opentrafficsim.draw.road.TrafficLightAnimation;
62 import org.opentrafficsim.draw.road.TrafficLightAnimation.TrafficLightData;
63 import org.opentrafficsim.draw.road.TrafficLightDetectorAnimation;
64 import org.opentrafficsim.draw.road.TrafficLightDetectorAnimation.TrafficLightDetectorData;
65 import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator;
66 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
67 import org.opentrafficsim.road.network.lane.CrossSectionElement;
68 import org.opentrafficsim.road.network.lane.CrossSectionLink;
69 import org.opentrafficsim.road.network.lane.Lane;
70 import org.opentrafficsim.road.network.lane.Shoulder;
71 import org.opentrafficsim.road.network.lane.Stripe;
72 import org.opentrafficsim.road.network.lane.conflict.Conflict;
73 import org.opentrafficsim.road.network.lane.object.BusStop;
74 import org.opentrafficsim.road.network.lane.object.SpeedSign;
75 import org.opentrafficsim.road.network.lane.object.detector.LaneDetector;
76 import org.opentrafficsim.road.network.lane.object.detector.SinkDetector;
77 import org.opentrafficsim.road.network.lane.object.detector.TrafficLightDetector;
78 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
79
80 import nl.tudelft.simulation.dsol.SimRuntimeException;
81 import nl.tudelft.simulation.dsol.animation.Locatable;
82 import nl.tudelft.simulation.dsol.animation.d2.Renderable2d;
83 import nl.tudelft.simulation.naming.context.Contextualized;
84
85
86
87
88
89
90
91
92
93
94 public class DefaultAnimationFactory implements EventListener
95 {
96
97 private final Network network;
98
99
100 private final OtsSimulatorInterface simulator;
101
102
103 private final GtuColorerManager gtuColorerManager;
104
105
106 private Map<LaneBasedGtu, Renderable2d<GtuData>> animatedGTUs = Collections.synchronizedMap(new LinkedHashMap<>());
107
108
109 private Map<LaneBasedGtu, Renderable2d<ChannelAttention>> animatedAttention =
110 Collections.synchronizedMap(new LinkedHashMap<>());
111
112
113 private Map<Locatable, Renderable2d<?>> animatedLocatedObjects = Collections.synchronizedMap(new LinkedHashMap<>());
114
115
116 private Map<NonLocatedObject, Renderable2d<?>> animatedNonLocatedObjects =
117 Collections.synchronizedMap(new LinkedHashMap<>());
118
119
120 private Map<GtuType, GtuMarker> gtuMarkers = new LinkedHashMap<>();
121
122
123
124
125
126
127
128
129 protected DefaultAnimationFactory(final Network network, final GtuColorerManager gtuColorerManager,
130 final boolean animateNetwork)
131 {
132 this.network = network;
133 this.simulator = network.getSimulator();
134 this.gtuColorerManager = gtuColorerManager;
135
136
137 network.addListener(this, Network.GTU_ADD_EVENT);
138 network.addListener(this, Network.GTU_REMOVE_EVENT);
139 network.addListener(this, Network.OBJECT_ADD_EVENT);
140 network.addListener(this, Network.OBJECT_REMOVE_EVENT);
141 network.addListener(this, Network.NONLOCATED_OBJECT_ADD_EVENT);
142 network.addListener(this, Network.NONLOCATED_OBJECT_REMOVE_EVENT);
143
144
145 if (animateNetwork)
146 {
147 for (Node node : network.getNodeMap().values())
148 {
149 new NodeAnimation(new AnimationNodeData(node), this.simulator);
150 }
151 for (Link link : network.getLinkMap().values())
152 {
153 new LinkAnimation(new AnimationLinkData(link), this.simulator, 0.5f);
154 if (link instanceof CrossSectionLink cLink)
155 {
156 for (CrossSectionElement element : cLink.getCrossSectionElementList())
157 {
158 if (element instanceof Shoulder shoulder)
159 {
160 new CrossSectionElementAnimation<>(new AnimationShoulderData(shoulder), this.simulator,
161 Color.DARK_GRAY);
162 }
163 else if (element instanceof Lane lane)
164 {
165 new LaneAnimation(new AnimationLaneData(lane), this.simulator, Color.GRAY.brighter());
166 }
167 else if (element instanceof Stripe stripe)
168 {
169 new StripeAnimation(new AnimationStripeData(stripe), this.simulator);
170 }
171 else
172 {
173 new CrossSectionElementAnimation<>(new AnimationCrossSectionElementData<>(element), this.simulator,
174 Color.DARK_GRAY);
175 }
176 }
177 if (!cLink.getPriority().isNone())
178 {
179 new PriorityAnimation(new AnimationPriorityData(cLink), this.simulator);
180 }
181 }
182 }
183 }
184
185 for (Gtu gtu : network.getGTUs())
186 {
187 GtuData gtuData = new AnimationGtuData(this.gtuColorerManager, (LaneBasedGtu) gtu,
188 this.gtuMarkers.getOrDefault(gtu.getType(), GtuMarker.CIRCLE));
189 Renderable2d<GtuData> gtuAnimation = new DefaultCarAnimation(gtuData, this.simulator);
190 this.animatedGTUs.put((LaneBasedGtu) gtu, gtuAnimation);
191
192 Renderable2d<ChannelAttention> attentionAnimation = new PerceptionAnimation((LaneBasedGtu) gtu);
193 this.animatedAttention.put((LaneBasedGtu) gtu, attentionAnimation);
194 }
195
196 for (LocatedObject object : network.getObjectMap().values())
197 {
198 animateLocatedObject(object);
199 }
200
201 for (NonLocatedObject object : network.getNonLocatedObjectMap().values())
202 {
203 animateNonLocatedObject(object);
204 }
205
206 }
207
208
209
210
211
212
213
214 public void setGtuMarker(final GtuType gtuType, final GtuMarker marker)
215 {
216 Throw.whenNull(marker, "marker");
217 this.gtuMarkers.put(gtuType, marker);
218 }
219
220
221
222
223
224
225
226
227
228
229 public static DefaultAnimationFactory animateNetwork(final Network network, final Contextualized contextualized,
230 final GtuColorerManager gtuColorerManager, final Map<GtuType, GtuMarker> markers)
231 {
232 DefaultAnimationFactory factory = new DefaultAnimationFactory(network, gtuColorerManager, true);
233 markers.forEach((type, marker) -> factory.setGtuMarker(type, marker));
234 return factory;
235 }
236
237
238
239
240
241
242
243
244
245 public static DefaultAnimationFactory animateXmlNetwork(final Network network, final GtuColorerManager gtuColorerManager,
246 final Map<GtuType, GtuMarker> markers)
247 {
248 DefaultAnimationFactory factory = new DefaultAnimationFactory(network, gtuColorerManager, false);
249 markers.forEach((type, marker) -> factory.setGtuMarker(type, marker));
250 return factory;
251 }
252
253 @Override
254 public void notify(final Event event)
255 {
256 try
257 {
258 if (event.getType().equals(Network.GTU_ADD_EVENT))
259 {
260
261 Optional<Gtu> gtu = this.network.getGTU((String) event.getContent());
262 if (gtu.isPresent() && gtu.get() instanceof LaneBasedGtu laneBasedGtu)
263 {
264 this.simulator.scheduleEventNow(() -> animateGTU(laneBasedGtu));
265 }
266 }
267 else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
268 {
269 LaneBasedGtu gtu = (LaneBasedGtu) this.network.getGTU((String) event.getContent()).get();
270 if (this.animatedGTUs.containsKey(gtu))
271 {
272 this.animatedGTUs.get(gtu).destroy(gtu.getSimulator());
273 this.animatedGTUs.remove(gtu);
274 }
275 if (this.animatedAttention.containsKey(gtu))
276 {
277 this.animatedAttention.get(gtu).destroy(gtu.getSimulator());
278 this.animatedAttention.remove(gtu);
279 }
280 }
281 else if (event.getType().equals(Network.OBJECT_ADD_EVENT))
282 {
283 LocatedObject object = this.network.getObjectMap().get((String) event.getContent());
284 animateLocatedObject(object);
285 }
286 else if (event.getType().equals(Network.OBJECT_REMOVE_EVENT))
287 {
288 LocatedObject object = this.network.getObjectMap().get((String) event.getContent());
289
290
291 this.animatedLocatedObjects.remove(object);
292 }
293 else if (event.getType().equals(Network.NONLOCATED_OBJECT_ADD_EVENT))
294 {
295 NonLocatedObject object = this.network.getNonLocatedObjectMap().get((String) event.getContent());
296 animateNonLocatedObject(object);
297 }
298 else if (event.getType().equals(Network.NONLOCATED_OBJECT_REMOVE_EVENT))
299 {
300 NonLocatedObject object = this.network.getNonLocatedObjectMap().get((String) event.getContent());
301
302
303 this.animatedNonLocatedObjects.remove(object);
304 }
305 }
306 catch (SimRuntimeException exception)
307 {
308 Logger.ots().error(exception, "Exception while updating network animation.");
309 }
310 }
311
312
313
314
315
316 protected void animateGTU(final LaneBasedGtu gtu)
317 {
318 GtuData gtuData = new AnimationGtuData(this.gtuColorerManager, gtu,
319 this.gtuMarkers.getOrDefault(gtu.getType(), GtuMarker.CIRCLE));
320 Renderable2d<GtuData> gtuAnimation = new DefaultCarAnimation(gtuData, this.simulator);
321 this.animatedGTUs.put(gtu, gtuAnimation);
322
323 Renderable2d<ChannelAttention> attentionAnimation = new PerceptionAnimation((LaneBasedGtu) gtu);
324 this.animatedAttention.put((LaneBasedGtu) gtu, attentionAnimation);
325 }
326
327
328
329
330
331 protected void animateLocatedObject(final LocatedObject object)
332 {
333 try
334 {
335 if (object instanceof SinkDetector)
336 {
337 SinkDetector detector = (SinkDetector) object;
338
339 Renderable2d<LaneDetectorData> objectAnimation = LaneDetectorAnimation
340 .ofGenericType(new AnimationLaneDetectorData(detector), this.simulator, Color.ORANGE);
341 this.animatedLocatedObjects.put(object, objectAnimation);
342 }
343 else if (object instanceof TrafficLightDetector)
344 {
345 TrafficLightDetector trafficLigthDetector = (TrafficLightDetector) object;
346 Renderable2d<TrafficLightDetectorData> objectAnimation = new TrafficLightDetectorAnimation(
347 new AnimationTrafficLightDetectorData(trafficLigthDetector), this.simulator);
348 this.animatedLocatedObjects.put(object, objectAnimation);
349 }
350 else if (object instanceof TrafficLightDetector.StartEndDetector)
351 {
352
353 return;
354 }
355 else if (object instanceof LaneDetector)
356 {
357 LaneDetector detector = (LaneDetector) object;
358 Renderable2d<LaneDetectorData> objectAnimation = LaneDetectorAnimation
359 .ofGenericType(new AnimationLaneDetectorData(detector), this.simulator, Color.BLACK);
360 this.animatedLocatedObjects.put(object, objectAnimation);
361 }
362 else if (object instanceof Conflict)
363 {
364 Conflict conflict = (Conflict) object;
365 Renderable2d<ConflictData> objectAnimation =
366 new ConflictAnimation(new AnimationConflictData(conflict), this.simulator);
367 this.animatedLocatedObjects.put(object, objectAnimation);
368 }
369 else if (object instanceof TrafficLight)
370 {
371 TrafficLight trafficLight = (TrafficLight) object;
372 Renderable2d<TrafficLightData> objectAnimation =
373 new TrafficLightAnimation(new AnimationTrafficLightData(trafficLight), this.simulator);
374 this.animatedLocatedObjects.put(object, objectAnimation);
375 }
376 else if (object instanceof SpeedSign)
377 {
378 SpeedSign speedSign = (SpeedSign) object;
379 Renderable2d<SpeedSignData> objectAnimation =
380 new SpeedSignAnimation(new AnimationSpeedSignData(speedSign), this.simulator);
381 this.animatedLocatedObjects.put(object, objectAnimation);
382 }
383 else if (object instanceof BusStop)
384 {
385 BusStop busStop = (BusStop) object;
386 Renderable2d<BusStopData> objectAnimation =
387 new BusStopAnimation(new AnimationBusStopData(busStop), this.simulator);
388 this.animatedLocatedObjects.put(object, objectAnimation);
389 }
390 }
391 catch (RemoteException | NamingException exception)
392 {
393 Logger.ots().error(exception, "Exception while drawing Object of class LocatedObject.");
394 }
395 }
396
397
398
399
400
401 protected void animateNonLocatedObject(final NonLocatedObject object)
402 {
403 if (object instanceof LaneBasedGtuGenerator)
404 {
405 LaneBasedGtuGenerator generator = (LaneBasedGtuGenerator) object;
406 for (GtuGeneratorPosition position : generator.getPositions())
407 {
408 Renderable2d<GtuGeneratorPositionData> objectAnimation =
409 new GtuGeneratorPositionAnimation(new AnimationGtuGeneratorPositionData(position), this.simulator);
410 this.animatedLocatedObjects.put(position, objectAnimation);
411 }
412 }
413 }
414
415 }