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