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