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