1 package org.opentrafficsim.animation.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.util.function.Supplier;
11
12 import org.djunits.value.vdouble.scalar.Length;
13 import org.djutils.base.Identifiable;
14 import org.djutils.draw.point.DirectedPoint2d;
15 import org.opentrafficsim.animation.DrawLevel;
16 import org.opentrafficsim.animation.OtsRenderable;
17 import org.opentrafficsim.animation.RenderableTextSource;
18 import org.opentrafficsim.animation.TextAlignment;
19 import org.opentrafficsim.animation.gtu.DefaultCarAnimation.GtuData;
20 import org.opentrafficsim.base.geometry.OtsLine2d;
21 import org.opentrafficsim.base.geometry.OtsShape;
22
23 import nl.tudelft.simulation.naming.context.Contextualized;
24
25
26
27
28
29
30
31
32
33
34
35 public class DefaultCarAnimation extends OtsRenderable<GtuData>
36 {
37
38 private Text text;
39
40
41 private final int hashCode;
42
43
44 private Rectangle2D.Double rectangle;
45
46
47 private Ellipse2D.Double frontIndicator;
48
49
50 private Rectangle2D.Double leftIndicator;
51
52
53 private Rectangle2D.Double rightIndicator;
54
55
56 private Rectangle2D.Double leftBrake;
57
58
59 private Rectangle2D.Double rightBrake;
60
61
62 private RectangularShape marker;
63
64
65
66
67
68
69 public DefaultCarAnimation(final GtuData gtu, final Contextualized contextualized)
70 {
71 super(gtu, contextualized);
72 this.hashCode = gtu.hashCode();
73 this.text = new Text(gtu, gtu::getId, 0.0f, 0.0f, TextAlignment.CENTER, Color.BLACK, contextualized,
74 new RenderableTextSource.ContrastToBackground()
75 {
76 @Override
77 public Color getBackgroundColor()
78 {
79 return gtu.getColor();
80 }
81 }).setDynamic(true);
82 }
83
84 @Override
85 public final void paint(final Graphics2D graphics, final ImageObserver observer)
86 {
87 setRendering(graphics);
88 final GtuData gtu = getSource();
89 if (this.rectangle == null)
90 {
91
92
93 final double length = gtu.getLength().si;
94 final double lFront = gtu.getFront().si;
95 final double lRear = gtu.getRear().si;
96 final double width = gtu.getWidth().si;
97 final double w2 = width / 2;
98 final double w4 = width / 4;
99 this.rectangle = new Rectangle2D.Double(lRear, -w2, length, width);
100 this.frontIndicator = new Ellipse2D.Double(lFront - w2 - w4, -w4, w2, w2);
101 this.leftIndicator = new Rectangle2D.Double(lFront - w4, -w2, w4, w4);
102 this.rightIndicator = new Rectangle2D.Double(lFront - w4, w2 - w4, w4, w4);
103 this.leftBrake = new Rectangle2D.Double(lRear, w2 - w4, w4, w4);
104 this.rightBrake = new Rectangle2D.Double(lRear, -w2, w4, w4);
105 this.marker = gtu.getMarker();
106 }
107
108 double scaleX = graphics.getTransform().getScaleX();
109 double scaleY = graphics.getTransform().getScaleY();
110 if (scaleX > 1 && scaleY > 1)
111 {
112
113 graphics.rotate(-gtu.getDirZ());
114
115 Color color = gtu.getColor();
116 graphics.setColor(color);
117 BasicStroke saveStroke = (BasicStroke) graphics.getStroke();
118 graphics.setStroke(new BasicStroke(0.05f));
119 graphics.fill(this.rectangle);
120
121 graphics.setColor(Color.WHITE);
122 graphics.fill(this.frontIndicator);
123
124 if (color.equals(Color.WHITE))
125 {
126
127 graphics.setColor(Color.BLACK);
128 graphics.draw(this.frontIndicator);
129 }
130
131
132 graphics.setColor(Color.YELLOW);
133 if (gtu.leftIndicatorOn())
134 {
135 graphics.fill(this.leftIndicator);
136 if (color.equals(Color.YELLOW))
137 {
138 graphics.setColor(Color.BLACK);
139 graphics.draw(this.leftIndicator);
140 }
141 }
142 if (gtu.rightIndicatorOn())
143 {
144 graphics.fill(this.rightIndicator);
145 if (color.equals(Color.YELLOW))
146 {
147 graphics.setColor(Color.BLACK);
148 graphics.draw(this.rightIndicator);
149 }
150 }
151
152
153 if (gtu.isBrakingLightsOn())
154 {
155 graphics.setColor(Color.RED);
156 graphics.fill(this.leftBrake);
157 graphics.fill(this.rightBrake);
158 if (color.equals(Color.RED))
159 {
160 graphics.setColor(Color.BLACK);
161 graphics.draw(this.leftBrake);
162 graphics.draw(this.rightBrake);
163 }
164 }
165
166 graphics.setStroke(saveStroke);
167 }
168 else
169 {
170
171 graphics.setColor(gtu.getColor());
172 double w = 7.0 / scaleX;
173 double h = 7.0 / scaleY;
174 double x = -w / 2.0;
175 double y = -h / 2.0;
176 this.marker.setFrame(x, y, w, h);
177 graphics.fill(this.marker);
178 }
179
180 resetRendering(graphics);
181 }
182
183 @Override
184 public boolean isRotate()
185 {
186 return false;
187 }
188
189 @Override
190 public void destroy(final Contextualized contextProvider)
191 {
192 super.destroy(contextProvider);
193 this.text.destroy(contextProvider);
194 }
195
196 @Override
197 public int hashCode()
198 {
199 return this.hashCode;
200 }
201
202 @Override
203 public boolean equals(final Object object)
204 {
205
206 return super.equals(object);
207 }
208
209
210
211
212
213
214
215
216
217
218
219
220 public static class Text extends RenderableTextSource<GtuData, Text>
221 {
222
223 private boolean isTextDestroyed = false;
224
225
226
227
228
229
230
231
232
233
234
235 public Text(final GtuData source, final Supplier<String> text, final float dx, final float dy,
236 final TextAlignment textAlignment, final Color color, final Contextualized contextualized)
237 {
238 super(source, text, dx, dy, textAlignment, color, 1.0f, 12.0f, 50f, contextualized,
239 RenderableTextSource.RENDERWHEN1);
240 }
241
242
243
244
245
246
247
248
249
250
251
252
253 @SuppressWarnings("parameternumber")
254 public Text(final GtuData source, final Supplier<String> text, final float dx, final float dy,
255 final TextAlignment textAlignment, final Color color, final Contextualized contextualized,
256 final RenderableTextSource.ContrastToBackground background)
257 {
258 super(source, text, dx, dy, textAlignment, color, 1.0f, 12.0f, 50f, contextualized, background, RENDERWHEN1);
259 setRotate(false);
260 }
261
262 @Override
263 public final String toString()
264 {
265 return "Text [isTextDestroyed=" + this.isTextDestroyed + "]";
266 }
267
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281 public interface GtuData extends OtsShape, Identifiable
282 {
283
284
285
286
287 Color getColor();
288
289
290
291
292
293 Length getLength();
294
295
296
297
298
299 Length getWidth();
300
301
302
303
304
305 Length getFront();
306
307
308
309
310
311 Length getRear();
312
313
314
315
316
317 boolean leftIndicatorOn();
318
319
320
321
322
323 boolean rightIndicatorOn();
324
325
326
327
328
329 default RectangularShape getMarker()
330 {
331 return new Ellipse2D.Double(0, 0, 0, 0);
332 }
333
334
335
336
337
338 boolean isBrakingLightsOn();
339
340 @Override
341 DirectedPoint2d getLocation();
342
343 @Override
344 default double getZ()
345 {
346 return DrawLevel.GTU.getZ();
347 }
348
349 @Override
350 default double getDirZ()
351 {
352 DirectedPoint2d p = getLocation();
353 return p == null ? 0.0 : p.getDirZ();
354 }
355
356
357
358
359
360 default OtsLine2d getPath()
361 {
362 return null;
363 }
364
365
366
367
368 enum GtuMarker
369 {
370
371 CIRCLE(new Ellipse2D.Double(0, 0, 0, 0)),
372
373
374 SQUARE(new Rectangle2D.Double(0, 0, 0, 0));
375
376
377 private RectangularShape shape;
378
379
380
381
382
383 GtuMarker(final RectangularShape shape)
384 {
385 this.shape = shape;
386 }
387
388
389
390
391
392 public RectangularShape getShape()
393 {
394 return this.shape;
395 }
396 }
397 }
398
399 }