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