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