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.geometry.DirectedPoint;
19 import org.opentrafficsim.core.gtu.GTUType;
20 import org.opentrafficsim.draw.core.ClonableRenderable2DInterface;
21 import org.opentrafficsim.draw.core.TextAlignment;
22 import org.opentrafficsim.draw.core.TextAnimation;
23 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
24 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
25
26 import nl.tudelft.simulation.dsol.animation.Locatable;
27 import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
28 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
29 import nl.tudelft.simulation.language.d2.Angle;
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 (this.rectangle == null)
142 {
143
144
145 final double length = gtu.getLength().si;
146 final double lFront = gtu.getFront().getDx().si;
147 final double lRear = gtu.getRear().getDx().si;
148 final double width = gtu.getWidth().si;
149 final double w2 = width / 2;
150 final double w4 = width / 4;
151 this.rectangle = new Rectangle2D.Double(lRear, -w2, length, width);
152 this.frontIndicator = new Ellipse2D.Double(lFront - w2 - w4, -w4, w2, w2);
153 this.leftIndicator = new Rectangle2D.Double(lFront - w4, -w2, w4, w4);
154 this.rightIndicator = new Rectangle2D.Double(lFront - w4, w2 - w4, w4, w4);
155 this.leftBrake = new Rectangle2D.Double(lRear, w2 - w4, w4, w4);
156 this.rightBrake = new Rectangle2D.Double(lRear, -w2, w4, w4);
157 this.dot = gtu.getGTUType().isOfType(gtu.getPerceivableContext().getGtuType(GTUType.DEFAULTS.TRUCK))
158 ? new Rectangle2D.Double(0, 0, 0, 0) : new Ellipse2D.Double(0, 0, 0, 0);
159 }
160
161 double scale = graphics.getTransform().getDeterminant();
162
163
164 if (scale > 1)
165 {
166 Color color = this.gtuColorer.getColor(gtu);
167 graphics.setColor(color);
168 BasicStroke saveStroke = (BasicStroke) graphics.getStroke();
169 graphics.setStroke(new BasicStroke(0.05f));
170 graphics.fill(this.rectangle);
171
172 graphics.setColor(Color.WHITE);
173 graphics.fill(this.frontIndicator);
174
175 if (color.equals(Color.WHITE))
176 {
177
178 graphics.setColor(Color.BLACK);
179 graphics.draw(this.frontIndicator);
180 }
181
182
183 graphics.setColor(Color.YELLOW);
184 if (gtu.getTurnIndicatorStatus() != null && gtu.getTurnIndicatorStatus().isLeftOrBoth())
185 {
186 graphics.fill(this.leftIndicator);
187 if (color.equals(Color.YELLOW))
188 {
189 graphics.setColor(Color.BLACK);
190 graphics.draw(this.leftIndicator);
191 }
192 }
193 if (gtu.getTurnIndicatorStatus() != null && gtu.getTurnIndicatorStatus().isRightOrBoth())
194 {
195 graphics.fill(this.rightIndicator);
196 if (color.equals(Color.YELLOW))
197 {
198 graphics.setColor(Color.BLACK);
199 graphics.draw(this.rightIndicator);
200 }
201 }
202
203
204 if (gtu.isBrakingLightsOn())
205 {
206 graphics.setColor(Color.RED);
207 graphics.fill(this.leftBrake);
208 graphics.fill(this.rightBrake);
209 if (color.equals(Color.RED))
210 {
211 graphics.setColor(Color.BLACK);
212 graphics.draw(this.leftBrake);
213 graphics.draw(this.rightBrake);
214 }
215 }
216 graphics.setStroke(saveStroke);
217 }
218 else
219 {
220
221 graphics.setColor(this.gtuColorer.getColor(gtu));
222 double w = 7.0 / Math.sqrt(scale);
223 double x = -w / 2.0;
224 this.dot.setFrame(x, x, w, w);
225 graphics.fill(this.dot);
226 }
227 }
228
229
230 @Override
231 public final void destroy(final SimulatorInterface<?, ?, ?> simulator)
232 {
233 super.destroy(simulator);
234 this.text.destroy(simulator);
235 this.isDestroyed = true;
236 }
237
238
239 @Override
240 @SuppressWarnings("checkstyle:designforextension")
241 public ClonableRenderable2DInterface<LaneBasedGTU> clone(final LaneBasedGTU newSource,
242 final SimulatorInterface.TimeDoubleUnit newSimulator) throws NamingException, RemoteException
243 {
244
245 return new DefaultCarAnimation(newSource, newSimulator, this.gtuColorer);
246 }
247
248
249 @Override
250 public final String toString()
251 {
252 return super.toString();
253 }
254
255
256 @Override
257 public int hashCode()
258 {
259 return this.hashCode;
260 }
261
262
263 @Override
264 public boolean equals(final Object object)
265 {
266
267 return super.equals(object);
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 public class Text extends TextAnimation
284 {
285
286 private static final long serialVersionUID = 20161211L;
287
288
289 private boolean isTextDestroyed = false;
290
291
292
293
294
295
296
297
298
299
300
301
302 public Text(final Locatable source, final String text, final float dx, final float dy,
303 final TextAlignment textAlignment, final Color color, final SimulatorInterface.TimeDoubleUnit simulator)
304 throws RemoteException, NamingException
305 {
306 super(source, text, dx, dy, textAlignment, color, 1.0f, 12.0f, 50f, simulator, TextAnimation.RENDERWHEN1);
307 }
308
309
310
311
312
313
314
315
316
317
318
319
320
321 @SuppressWarnings("parameternumber")
322 public Text(final Locatable source, final String text, final float dx, final float dy,
323 final TextAlignment textAlignment, final Color color, final SimulatorInterface.TimeDoubleUnit simulator,
324 final TextAnimation.ContrastToBackground background) throws RemoteException, NamingException
325 {
326 super(source, text, dx, dy, textAlignment, color, 1.0f, 12.0f, 50f, simulator, background, RENDERWHEN1);
327 }
328
329
330 @Override
331 public final void paint(final Graphics2D graphics, final ImageObserver observer)
332 {
333 final LaneBasedIndividualGTU car = (LaneBasedIndividualGTU) getSource();
334
335 if (car.isDestroyed())
336 {
337 if (!this.isTextDestroyed)
338 {
339 try
340 {
341 destroy(car.getSimulator());
342 }
343 catch (Exception e)
344 {
345 System.err.println("Error while destroying text animation of GTU " + car.getId());
346 }
347 this.isTextDestroyed = true;
348 }
349 return;
350 }
351
352 super.paint(graphics, observer);
353 }
354
355
356 @Override
357 @SuppressWarnings("checkstyle:designforextension")
358 public DirectedPoint getLocation()
359 {
360
361 DirectedPoint p = ((LaneBasedIndividualGTU) getSource()).getLocation();
362 double a = Angle.normalizePi(p.getRotZ());
363 if (a > Math.PI / 2.0 || a < -0.99 * Math.PI / 2.0)
364 {
365 a += Math.PI;
366 }
367 return new DirectedPoint(p.x, p.y, Double.MAX_VALUE, 0.0, 0.0, a);
368 }
369
370
371 @Override
372 @SuppressWarnings("checkstyle:designforextension")
373 public TextAnimation clone(final Locatable newSource, final SimulatorInterface.TimeDoubleUnit newSimulator)
374 throws RemoteException, NamingException
375 {
376 return new Text(newSource, getText(), getDx(), getDy(), getTextAlignment(), getColor(), newSimulator);
377 }
378
379
380 @Override
381 public final String toString()
382 {
383 return "Text [isTextDestroyed=" + this.isTextDestroyed + "]";
384 }
385
386 }
387
388 }