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(GTUType.TRUCK) ? new Rectangle2D.Double(0, 0, 0, 0)
169 : new Ellipse2D.Double(0, 0, 0, 0);
170 }
171
172 double scale = graphics.getTransform().getDeterminant();
173
174
175 if (scale > 1)
176 {
177 graphics.setColor(this.gtuColorer.getColor(gtu));
178 BasicStroke saveStroke = (BasicStroke) graphics.getStroke();
179 graphics.setStroke(new BasicStroke(0));
180 graphics.fill(this.rectangle);
181
182
183 graphics.setColor(Color.WHITE);
184 graphics.fill(this.frontIndicator);
185
186
187 graphics.setColor(Color.YELLOW);
188 if (gtu.getTurnIndicatorStatus() != null && gtu.getTurnIndicatorStatus().isLeftOrBoth())
189 {
190 graphics.fill(this.leftIndicator);
191 }
192 if (gtu.getTurnIndicatorStatus() != null && gtu.getTurnIndicatorStatus().isRightOrBoth())
193 {
194 graphics.fill(this.rightIndicator);
195 }
196
197
198 if (gtu.isBrakingLightsOn())
199 {
200 graphics.setColor(Color.RED);
201 graphics.fill(this.leftBrake);
202 graphics.fill(this.rightBrake);
203 }
204 graphics.setStroke(saveStroke);
205 }
206 else
207 {
208
209 graphics.setColor(this.gtuColorer.getColor(gtu));
210 double w = 7.0 / Math.sqrt(scale);
211 double x = -w / 2.0;
212 this.dot.setFrame(x, x, w, w);
213 graphics.fill(this.dot);
214 }
215
216 }
217
218
219 @Override
220 public final void destroy() throws NamingException
221 {
222 this.isDestroyed = true;
223 super.destroy();
224 this.text.destroy();
225 }
226
227
228 @Override
229 @SuppressWarnings("checkstyle:designforextension")
230 public ClonableRenderable2DInterface<LaneBasedGTU> clone(final LaneBasedGTU newSource,
231 final SimulatorInterface.TimeDoubleUnit newSimulator) throws NamingException, RemoteException
232 {
233
234 return new DefaultCarAnimation(newSource, newSimulator, this.gtuColorer);
235 }
236
237
238 @Override
239 public final String toString()
240 {
241 return super.toString();
242 }
243
244
245 @Override
246 public int hashCode()
247 {
248 return this.hashCode;
249 }
250
251
252 @Override
253 public boolean equals(final Object object)
254 {
255
256 return super.equals(object);
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 public class Text extends TextAnimation
273 {
274
275 private static final long serialVersionUID = 20161211L;
276
277
278 private boolean isTextDestroyed = false;
279
280
281
282
283
284
285
286
287
288
289
290
291 public Text(final Locatable source, final String text, final float dx, final float dy,
292 final TextAlignment textAlignment, final Color color, final SimulatorInterface.TimeDoubleUnit simulator)
293 throws RemoteException, NamingException
294 {
295 super(source, text, dx, dy, textAlignment, color, 1.0f, 12.0f, simulator);
296 }
297
298
299 @Override
300 public final void paint(final Graphics2D graphics, final ImageObserver observer) throws RemoteException
301 {
302 final LaneBasedIndividualGTU car = (LaneBasedIndividualGTU) getSource();
303
304 if (car.isDestroyed())
305 {
306 if (!this.isTextDestroyed)
307 {
308 try
309 {
310 destroy();
311 }
312 catch (Exception e)
313 {
314 System.err.println("Error while destroying text animation of GTU " + car.getId());
315 }
316 this.isTextDestroyed = true;
317 }
318 return;
319 }
320
321 super.paint(graphics, observer);
322 }
323
324
325 @Override
326 @SuppressWarnings("checkstyle:designforextension")
327 public DirectedPoint getLocation() throws RemoteException
328 {
329
330 DirectedPoint p = ((LaneBasedIndividualGTU) getSource()).getLocation();
331 double a = Angle.normalizePi(p.getRotZ());
332 if (a > Math.PI / 2.0 || a < -0.99 * Math.PI / 2.0)
333 {
334 a += Math.PI;
335 }
336 return new DirectedPoint(p.x, p.y, Double.MAX_VALUE, 0.0, 0.0, a);
337 }
338
339
340 @Override
341 @SuppressWarnings("checkstyle:designforextension")
342 public TextAnimation clone(final Locatable newSource, final SimulatorInterface.TimeDoubleUnit newSimulator)
343 throws RemoteException, NamingException
344 {
345 return new Text(newSource, getText(), getDx(), getDy(), getTextAlignment(), getColor(), newSimulator);
346 }
347
348
349 @Override
350 public final String toString()
351 {
352 return "Text [isTextDestroyed=" + this.isTextDestroyed + "]";
353 }
354
355 }
356
357 }