1 package org.opentrafficsim.draw.gtu;
2
3 import java.awt.BasicStroke;
4 import java.awt.Color;
5 import java.awt.Graphics2D;
6 import java.awt.geom.Ellipse2D;
7 import java.awt.geom.Rectangle2D;
8 import java.awt.geom.RectangularShape;
9 import java.awt.image.ImageObserver;
10 import java.io.Serializable;
11 import java.rmi.RemoteException;
12
13 import javax.naming.NamingException;
14
15 import org.opentrafficsim.core.animation.gtu.colorer.DefaultSwitchableGTUColorer;
16 import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
17 import org.opentrafficsim.core.animation.gtu.colorer.IDGTUColorer;
18 import org.opentrafficsim.core.gtu.GTUType;
19 import org.opentrafficsim.draw.core.ClonableRenderable2DInterface;
20 import org.opentrafficsim.draw.core.TextAlignment;
21 import org.opentrafficsim.draw.core.TextAnimation;
22 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
23 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
24
25 import nl.tudelft.simulation.dsol.animation.Locatable;
26 import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
27 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
28 import nl.tudelft.simulation.language.d2.Angle;
29 import nl.tudelft.simulation.language.d3.DirectedPoint;
30
31
32
33
34
35
36
37
38
39
40
41
42 public class DefaultCarAnimation extends Renderable2D<LaneBasedGTU>
43 implements ClonableRenderable2DInterface<LaneBasedGTU>, Serializable
44 {
45
46 private static final long serialVersionUID = 20150000L;
47
48
49 private GTUColorer gtuColorer = new DefaultSwitchableGTUColorer();
50
51
52 private Text text;
53
54
55 private boolean isDestroyed = false;
56
57
58 private final int hashCode;
59
60
61 private Rectangle2D.Double rectangle;
62
63
64 private Ellipse2D.Double frontIndicator;
65
66
67 private Rectangle2D.Double leftIndicator;
68
69
70 private Rectangle2D.Double rightIndicator;
71
72
73 private Rectangle2D.Double leftBrake;
74
75
76 private Rectangle2D.Double rightBrake;
77
78
79 private RectangularShape dot;
80
81
82
83
84
85
86
87
88 public DefaultCarAnimation(final LaneBasedGTU gtu, final SimulatorInterface.TimeDoubleUnit simulator)
89 throws NamingException, RemoteException
90 {
91 this(gtu, simulator, null);
92 }
93
94
95
96
97
98
99
100
101
102 public DefaultCarAnimation(final LaneBasedGTU gtu, final SimulatorInterface.TimeDoubleUnit simulator,
103 final GTUColorer gtuColorer) throws NamingException, RemoteException
104 {
105 super(gtu, simulator);
106 this.hashCode = gtu.hashCode();
107 if (null == gtuColorer)
108 {
109 this.gtuColorer = new IDGTUColorer();
110 }
111 else
112 {
113 this.gtuColorer = gtuColorer;
114 }
115 this.text = new Text(gtu, gtu.getId(), 0.0f, 0.0f, TextAlignment.CENTER, Color.BLACK, simulator,
116 new TextAnimation.ContrastToBackground()
117 {
118
119 @Override
120 public Color getBackgroundColor()
121 {
122 return gtuColorer.getColor(gtu);
123 }
124 });
125 }
126
127
128
129
130
131 public final void setGTUColorer(final GTUColorer newGTUColorer)
132 {
133 this.gtuColorer = newGTUColorer;
134 }
135
136
137 @Override
138 public final void paint(final Graphics2D graphics, final ImageObserver observer)
139 {
140 final LaneBasedGTU gtu = getSource();
141 if (gtu.isDestroyed())
142 {
143 if (!this.isDestroyed)
144 {
145 try
146 {
147 destroy();
148 }
149 catch (Exception e)
150 {
151 System.err.println("Error while destroying GTU " + gtu.getId());
152 e.printStackTrace();
153 }
154 }
155 return;
156 }
157
158 if (this.rectangle == null)
159 {
160
161
162 final double length = gtu.getLength().si;
163 final double lFront = gtu.getFront().getDx().si;
164 final double lRear = gtu.getRear().getDx().si;
165 final double width = gtu.getWidth().si;
166 final double w2 = width / 2;
167 final double w4 = width / 4;
168 this.rectangle = new Rectangle2D.Double(lRear, -w2, length, width);
169 this.frontIndicator = new Ellipse2D.Double(lFront - w2 - w4, -w4, w2, w2);
170 this.leftIndicator = new Rectangle2D.Double(lFront - w4, -w2, w4, w4);
171 this.rightIndicator = new Rectangle2D.Double(lFront - w4, w2 - w4, w4, w4);
172 this.leftBrake = new Rectangle2D.Double(lRear, w2 - w4, w4, w4);
173 this.rightBrake = new Rectangle2D.Double(lRear, -w2, w4, w4);
174 this.dot = gtu.getGTUType().isOfType(gtu.getPerceivableContext().getGtuType(GTUType.DEFAULTS.TRUCK))
175 ? new Rectangle2D.Double(0, 0, 0, 0) : new Ellipse2D.Double(0, 0, 0, 0);
176 }
177
178 double scale = graphics.getTransform().getDeterminant();
179
180
181 if (scale > 1)
182 {
183 Color color = this.gtuColorer.getColor(gtu);
184 graphics.setColor(color);
185 BasicStroke saveStroke = (BasicStroke) graphics.getStroke();
186 graphics.setStroke(new BasicStroke(0.05f));
187 graphics.fill(this.rectangle);
188
189 graphics.setColor(Color.WHITE);
190 graphics.fill(this.frontIndicator);
191
192 if (color.equals(Color.WHITE))
193 {
194
195 graphics.setColor(Color.BLACK);
196 graphics.draw(this.frontIndicator);
197 }
198
199
200 graphics.setColor(Color.YELLOW);
201 if (gtu.getTurnIndicatorStatus() != null && gtu.getTurnIndicatorStatus().isLeftOrBoth())
202 {
203 graphics.fill(this.leftIndicator);
204 if (color.equals(Color.YELLOW))
205 {
206 graphics.setColor(Color.BLACK);
207 graphics.draw(this.leftIndicator);
208 }
209 }
210 if (gtu.getTurnIndicatorStatus() != null && gtu.getTurnIndicatorStatus().isRightOrBoth())
211 {
212 graphics.fill(this.rightIndicator);
213 if (color.equals(Color.YELLOW))
214 {
215 graphics.setColor(Color.BLACK);
216 graphics.draw(this.rightIndicator);
217 }
218 }
219
220
221 if (gtu.isBrakingLightsOn())
222 {
223 graphics.setColor(Color.RED);
224 graphics.fill(this.leftBrake);
225 graphics.fill(this.rightBrake);
226 if (color.equals(Color.RED))
227 {
228 graphics.setColor(Color.BLACK);
229 graphics.draw(this.leftBrake);
230 graphics.draw(this.rightBrake);
231 }
232 }
233 graphics.setStroke(saveStroke);
234 }
235 else
236 {
237
238 graphics.setColor(this.gtuColorer.getColor(gtu));
239 double w = 7.0 / Math.sqrt(scale);
240 double x = -w / 2.0;
241 this.dot.setFrame(x, x, w, w);
242 graphics.fill(this.dot);
243 }
244 }
245
246
247 @Override
248 public final void destroy() throws NamingException, RemoteException
249 {
250 this.isDestroyed = true;
251 super.destroy();
252 this.text.destroy();
253 }
254
255
256 @Override
257 @SuppressWarnings("checkstyle:designforextension")
258 public ClonableRenderable2DInterface<LaneBasedGTU> clone(final LaneBasedGTU newSource,
259 final SimulatorInterface.TimeDoubleUnit newSimulator) throws NamingException, RemoteException
260 {
261
262 return new DefaultCarAnimation(newSource, newSimulator, this.gtuColorer);
263 }
264
265
266 @Override
267 public final String toString()
268 {
269 return super.toString();
270 }
271
272
273 @Override
274 public int hashCode()
275 {
276 return this.hashCode;
277 }
278
279
280 @Override
281 public boolean equals(final Object object)
282 {
283
284 return super.equals(object);
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300 public class Text extends TextAnimation
301 {
302
303 private static final long serialVersionUID = 20161211L;
304
305
306 private boolean isTextDestroyed = false;
307
308
309
310
311
312
313
314
315
316
317
318
319 public Text(final Locatable source, final String text, final float dx, final float dy,
320 final TextAlignment textAlignment, final Color color, final SimulatorInterface.TimeDoubleUnit simulator)
321 throws RemoteException, NamingException
322 {
323 super(source, text, dx, dy, textAlignment, color, 1.0f, 12.0f, 50f, simulator, TextAnimation.RENDERWHEN1);
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338 @SuppressWarnings("parameternumber")
339 public Text(final Locatable source, final String text, final float dx, final float dy,
340 final TextAlignment textAlignment, final Color color, final SimulatorInterface.TimeDoubleUnit simulator,
341 final TextAnimation.ContrastToBackground background) throws RemoteException, NamingException
342 {
343 super(source, text, dx, dy, textAlignment, color, 1.0f, 12.0f, 50f, simulator, background, RENDERWHEN1);
344 }
345
346
347 @Override
348 public final void paint(final Graphics2D graphics, final ImageObserver observer) throws RemoteException
349 {
350 final LaneBasedIndividualGTU car = (LaneBasedIndividualGTU) getSource();
351
352 if (car.isDestroyed())
353 {
354 if (!this.isTextDestroyed)
355 {
356 try
357 {
358 destroy();
359 }
360 catch (Exception e)
361 {
362 System.err.println("Error while destroying text animation of GTU " + car.getId());
363 }
364 this.isTextDestroyed = true;
365 }
366 return;
367 }
368
369 super.paint(graphics, observer);
370 }
371
372
373 @Override
374 @SuppressWarnings("checkstyle:designforextension")
375 public DirectedPoint getLocation() throws RemoteException
376 {
377
378 DirectedPoint p = ((LaneBasedIndividualGTU) getSource()).getLocation();
379 double a = Angle.normalizePi(p.getRotZ());
380 if (a > Math.PI / 2.0 || a < -0.99 * Math.PI / 2.0)
381 {
382 a += Math.PI;
383 }
384 return new DirectedPoint(p.x, p.y, Double.MAX_VALUE, 0.0, 0.0, a);
385 }
386
387
388 @Override
389 @SuppressWarnings("checkstyle:designforextension")
390 public TextAnimation clone(final Locatable newSource, final SimulatorInterface.TimeDoubleUnit newSimulator)
391 throws RemoteException, NamingException
392 {
393 return new Text(newSource, getText(), getDx(), getDy(), getTextAlignment(), getColor(), newSimulator);
394 }
395
396
397 @Override
398 public final String toString()
399 {
400 return "Text [isTextDestroyed=" + this.isTextDestroyed + "]";
401 }
402
403 }
404
405 }