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