1 package org.opentrafficsim.draw.core;
2
3 import java.awt.Color;
4 import java.awt.Dimension;
5 import java.awt.Font;
6 import java.awt.FontMetrics;
7 import java.awt.Graphics2D;
8 import java.awt.geom.Point2D;
9 import java.awt.geom.Rectangle2D;
10 import java.awt.image.ImageObserver;
11 import java.io.Serializable;
12 import java.rmi.RemoteException;
13
14 import javax.media.j3d.Bounds;
15 import javax.naming.NamingException;
16
17 import nl.tudelft.simulation.dsol.animation.Locatable;
18 import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
19 import nl.tudelft.simulation.dsol.logger.SimLogger;
20 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
21 import nl.tudelft.simulation.language.d3.BoundingBox;
22 import nl.tudelft.simulation.language.d3.DirectedPoint;
23
24
25
26
27
28
29
30
31
32
33
34
35
36 public abstract class TextAnimation implements Locatable, Serializable
37 {
38
39 private static final long serialVersionUID = 20161211L;
40
41
42 private final Locatable source;
43
44
45 private String text;
46
47
48 private float dx;
49
50
51 private float dy;
52
53
54 private final TextAlignment textAlignment;
55
56
57 private Color color;
58
59
60 private final float fontSize;
61
62
63 private final float minFontSize;
64
65
66 private final AnimationImpl animationImpl;
67
68
69 private Font font;
70
71
72 private Rectangle2D fontRectangle = null;
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 @SuppressWarnings("checkstyle:parameternumber")
88 public TextAnimation(final Locatable source, final String text, final float dx, final float dy,
89 final TextAlignment textAlignment, final Color color, final float fontSize, final float minFontSize,
90 final SimulatorInterface.TimeDoubleUnit simulator) throws RemoteException, NamingException
91 {
92 this.source = source;
93 this.text = text;
94 this.dx = dx;
95 this.dy = dy;
96 this.textAlignment = textAlignment;
97 this.color = color;
98 this.fontSize = fontSize;
99 this.minFontSize = minFontSize;
100
101 this.font = new Font("SansSerif", Font.PLAIN, 2);
102 if (this.fontSize != 2.0f)
103 {
104 this.font = this.font.deriveFont(this.fontSize);
105 }
106
107 this.animationImpl = new AnimationImpl(this, simulator);
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121 public TextAnimation(final Locatable source, final String text, final float dx, final float dy,
122 final TextAlignment textAlignment, final Color color, final SimulatorInterface.TimeDoubleUnit simulator)
123 throws RemoteException, NamingException
124 {
125 this(source, text, dx, dy, textAlignment, color, 2.0f, 12.0f, simulator);
126 }
127
128
129 @Override
130 @SuppressWarnings("checkstyle:designforextension")
131 public DirectedPoint getLocation() throws RemoteException
132 {
133
134 DirectedPoint p = this.source.getLocation();
135 return new DirectedPoint(p.x, p.y, Double.MAX_VALUE, 0.0, 0.0, p.getRotZ());
136 }
137
138
139 @Override
140 public final Bounds getBounds() throws RemoteException
141 {
142 return new BoundingBox(0.0, 0.0, 0.0);
143 }
144
145
146
147
148
149
150
151 @SuppressWarnings("checkstyle:designforextension")
152 public void paint(final Graphics2D graphics, final ImageObserver observer) throws RemoteException
153 {
154 double scale = Math.sqrt(graphics.getTransform().getDeterminant());
155 Rectangle2D scaledFontRectangle;
156 synchronized (this.font)
157 {
158 if (scale < this.minFontSize)
159 {
160 graphics.setFont(this.font.deriveFont((float) (this.minFontSize / scale)));
161 FontMetrics fm = graphics.getFontMetrics();
162 scaledFontRectangle = fm.getStringBounds(this.text, graphics);
163 }
164 else
165 {
166 graphics.setFont(this.font);
167 if (this.fontRectangle == null)
168 {
169 FontMetrics fm = graphics.getFontMetrics();
170 this.fontRectangle = fm.getStringBounds(this.text, graphics);
171 }
172 scaledFontRectangle = this.fontRectangle;
173 }
174 graphics.setColor(this.color);
175 float dxText =
176 this.textAlignment.equals(TextAlignment.LEFT) ? 0.0f : this.textAlignment.equals(TextAlignment.CENTER)
177 ? (float) -scaledFontRectangle.getWidth() / 2.0f : (float) -scaledFontRectangle.getWidth();
178 graphics.drawString(this.text, dxText + this.dx, this.fontSize / 2.0f - this.dy);
179 }
180 }
181
182
183
184
185 public final void destroy()
186 {
187 try
188 {
189 this.animationImpl.destroy();
190 }
191 catch (NamingException exception)
192 {
193 SimLogger.always().warn(exception, "Tried to destroy Text for GTU animation of GTU {}", this.source.toString());
194 }
195 }
196
197
198
199
200
201
202
203
204
205 public abstract TextAnimation clone(Locatable newSource, SimulatorInterface.TimeDoubleUnit newSimulator)
206 throws RemoteException, NamingException;
207
208
209
210
211
212 protected final Locatable getSource()
213 {
214 return this.source;
215 }
216
217
218
219
220
221 protected final float getDx()
222 {
223 return this.dx;
224 }
225
226
227
228
229
230 protected final float getDy()
231 {
232 return this.dy;
233 }
234
235
236
237
238
239
240 protected final void setXY(final float x, final float y)
241 {
242 this.dx = x;
243 this.dy = y;
244 }
245
246
247
248
249
250 protected final TextAlignment getTextAlignment()
251 {
252 return this.textAlignment;
253 }
254
255
256
257
258
259 protected final float getFontSize()
260 {
261 return this.fontSize;
262 }
263
264
265
266
267
268 protected final Font getFont()
269 {
270 return this.font;
271 }
272
273
274
275
276
277 protected final String getText()
278 {
279 return this.text;
280 }
281
282
283
284
285
286 protected final void setText(final String text)
287 {
288 this.text = text;
289 synchronized (this.font)
290 {
291 this.fontRectangle = null;
292 }
293 }
294
295
296
297
298
299 protected final Color getColor()
300 {
301 return this.color;
302 }
303
304
305
306
307
308 protected final void setColor(final Color color)
309 {
310 this.color = color;
311 }
312
313
314
315
316
317 public final boolean isFlip()
318 {
319 return this.animationImpl.isFlip();
320 }
321
322
323
324
325
326 public final void setFlip(final boolean flip)
327 {
328 this.animationImpl.setFlip(flip);
329 }
330
331
332
333
334
335 public final boolean isRotate()
336 {
337 return this.animationImpl.isRotate();
338 }
339
340
341
342
343
344 public final void setRotate(final boolean rotate)
345 {
346 this.animationImpl.setRotate(rotate);
347
348 }
349
350
351
352
353
354 public final boolean isScale()
355 {
356 return this.animationImpl.isScale();
357 }
358
359
360
361
362
363 public final void setScale(final boolean scale)
364 {
365 this.animationImpl.setScale(scale);
366 }
367
368
369
370
371
372 public final boolean isTranslate()
373 {
374 return this.animationImpl.isTranslate();
375 }
376
377
378
379
380
381 public final void setTranslate(final boolean translate)
382 {
383 this.animationImpl.setTranslate(translate);
384 }
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399 private static class AnimationImpl extends Renderable2D<Locatable> implements Serializable
400 {
401
402 private static final long serialVersionUID = 20170400L;
403
404
405
406
407
408
409
410
411 AnimationImpl(final Locatable source, final SimulatorInterface.TimeDoubleUnit simulator)
412 throws NamingException, RemoteException
413 {
414 super(source, simulator);
415 }
416
417
418 @Override
419 public final void paint(final Graphics2D graphics, final ImageObserver observer) throws RemoteException
420 {
421 TextAnimation ta = ((TextAnimation) getSource());
422 ta.paint(graphics, observer);
423 }
424
425
426 @Override
427 public boolean contains(final Point2D pointWorldCoordinates, final Rectangle2D extent, final Dimension screen)
428 {
429 return false;
430 }
431
432
433 @Override
434 public final String toString()
435 {
436 return "TextAnimation.AnimationImpl []";
437 }
438
439 }
440 }