View Javadoc
1   package org.opentrafficsim.core.animation;
2   
3   import java.awt.Color;
4   import java.awt.Font;
5   import java.awt.FontMetrics;
6   import java.awt.Graphics2D;
7   import java.awt.geom.Rectangle2D;
8   import java.awt.image.ImageObserver;
9   import java.io.Serializable;
10  import java.rmi.RemoteException;
11  
12  import javax.media.j3d.Bounds;
13  import javax.naming.NamingException;
14  
15  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
16  
17  import nl.tudelft.simulation.dsol.animation.Locatable;
18  import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
19  import nl.tudelft.simulation.language.d3.BoundingBox;
20  import nl.tudelft.simulation.language.d3.DirectedPoint;
21  
22  /**
23   * Display a text for another Locatable object.
24   * <p>
25   * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
26   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
27   * </p>
28   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
29   * initial version Dec 11, 2016 <br>
30   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
31   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
32   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
33   */
34  public abstract class TextAnimation implements Locatable, Serializable
35  {
36      /** */
37      private static final long serialVersionUID = 20161211L;
38  
39      /** the object for which the text is displayed. */
40      private final Locatable source;
41  
42      /** the text to display. */
43      private String text;
44  
45      /** the horizontal movement of the text, in meters. */
46      private final float dx;
47  
48      /** the vertical movement of the text, in meters. */
49      private final float dy;
50  
51      /** whether to center or not. */
52      private final TextAlignment textAlignment;
53  
54      /** the color of the text. */
55      private Color color;
56  
57      /** fontSize the size of the font; default = 2.0 (meters). */
58      private final float fontSize;
59  
60      /** the animation implementation. */
61      private final AnimationImpl animationImpl;
62  
63      /** the font. */
64      private Font font;
65  
66      /** the font rectangle. */
67      private Rectangle2D fontRectangle = null;
68  
69      /**
70       * @param source the object for which the text is displayed
71       * @param text the text to display
72       * @param dx the horizontal movement of the text, in meters
73       * @param dy the vertical movement of the text, in meters
74       * @param textAlignment where to place the text
75       * @param color the color of the text
76       * @param fontSize the size of the font; default = 2.0 (meters)
77       * @param simulator the simulator
78       * @throws NamingException when animation context cannot be created or retrieved
79       * @throws RemoteException - when remote context cannot be found
80       */
81      @SuppressWarnings("checkstyle:parameternumber")
82      public TextAnimation(final Locatable source, final String text, final float dx, final float dy,
83              final TextAlignment textAlignment, final Color color, final float fontSize, final OTSSimulatorInterface simulator)
84              throws RemoteException, NamingException
85      {
86          this.source = source;
87          this.text = text;
88          this.dx = dx;
89          this.dy = dy;
90          this.textAlignment = textAlignment;
91          this.color = color;
92          this.fontSize = fontSize;
93  
94          this.font = new Font("SansSerif", Font.PLAIN, 2);
95          if (this.fontSize != 2.0f)
96          {
97              this.font = this.font.deriveFont(this.fontSize);
98          }
99  
100         this.animationImpl = new AnimationImpl(this, simulator);
101     }
102 
103     /**
104      * @param source the object for which the text is displayed
105      * @param text the text to display
106      * @param dx the horizontal movement of the text, in meters
107      * @param dy the vertical movement of the text, in meters
108      * @param textAlignment where to place the text
109      * @param color the color of the text
110      * @param simulator the simulator
111      * @throws NamingException when animation context cannot be created or retrieved
112      * @throws RemoteException - when remote context cannot be found
113      */
114     public TextAnimation(final Locatable source, final String text, final float dx, final float dy,
115             final TextAlignment textAlignment, final Color color, final OTSSimulatorInterface simulator)
116             throws RemoteException, NamingException
117     {
118         this(source, text, dx, dy, textAlignment, color, 2.0f, simulator);
119     }
120 
121     /** {@inheritDoc} */
122     @Override
123     @SuppressWarnings("checkstyle:designforextension")
124     public DirectedPoint getLocation() throws RemoteException
125     {
126         // draw always on top.
127         DirectedPoint p = this.source.getLocation();
128         return new DirectedPoint(p.x, p.y, Double.MAX_VALUE, 0.0, 0.0, p.getRotZ());
129     }
130 
131     /** {@inheritDoc} */
132     @Override
133     public final Bounds getBounds() throws RemoteException
134     {
135         return new BoundingBox(0.0, 0.0, 0.0);
136     }
137 
138     /**
139      * paint() method so it can be overridden or extended.
140      * @param graphics the graphics object
141      * @param observer the observer
142      * @throws RemoteException on network exception
143      */
144     @SuppressWarnings("checkstyle:designforextension")
145     public void paint(final Graphics2D graphics, final ImageObserver observer) throws RemoteException
146     {
147         graphics.setFont(this.font);
148         synchronized (this.font)
149         {
150             if (this.fontRectangle == null)
151             {
152                 FontMetrics fm = graphics.getFontMetrics();
153                 this.fontRectangle = fm.getStringBounds(this.text, graphics);
154             }
155             graphics.setColor(this.color);
156             float dxText =
157                     this.textAlignment.equals(TextAlignment.LEFT) ? 0.0f : this.textAlignment.equals(TextAlignment.CENTER)
158                             ? (float) -this.fontRectangle.getWidth() / 2.0f : (float) -this.fontRectangle.getWidth();
159             graphics.drawString(this.text, dxText + this.dx, this.fontSize / 2.0f - this.dy);
160         }
161     }
162 
163     /**
164      * Destroy the text animation.
165      */
166     public final void destroy()
167     {
168         try
169         {
170             this.animationImpl.destroy();
171         }
172         catch (NamingException exception)
173         {
174             System.err.println("Tried to destroy Text for GTU animation of GTU " + this.source.toString());
175         }
176     }
177 
178     /**
179      * Clone the TextAnimation and return a copy for the new source on the new simulator.
180      * @param newSource the new source to link to the text animation
181      * @param newSimulator the new simulator to register the animation on
182      * @return a copy of the TextAnimation
183      * @throws RemoteException when remote animation cannot be reached
184      * @throws NamingException when animation name cannot be found or bound in the Context
185      */
186     public abstract TextAnimation clone(final Locatable newSource, final OTSSimulatorInterface newSimulator)
187             throws RemoteException, NamingException;
188 
189     /**
190      * @return source
191      */
192     protected final Locatable getSource()
193     {
194         return this.source;
195     }
196 
197     /**
198      * @return dx
199      */
200     protected final float getDx()
201     {
202         return this.dx;
203     }
204 
205     /**
206      * @return dy
207      */
208     protected final float getDy()
209     {
210         return this.dy;
211     }
212 
213     /**
214      * @return textAlignment
215      */
216     protected final TextAlignment getTextAlignment()
217     {
218         return this.textAlignment;
219     }
220 
221     /**
222      * @return fontSize
223      */
224     protected final float getFontSize()
225     {
226         return this.fontSize;
227     }
228 
229     /**
230      * @return font
231      */
232     protected final Font getFont()
233     {
234         return this.font;
235     }
236 
237     /**
238      * @return current text
239      */
240     protected final String getText()
241     {
242         return this.text;
243     }
244 
245     /**
246      * @param text set new text
247      */
248     protected final void setText(final String text)
249     {
250         this.text = text;
251         synchronized (this.font)
252         {
253             this.fontRectangle = null;
254         }
255     }
256 
257     /**
258      * @return current color
259      */
260     protected final Color getColor()
261     {
262         return this.color;
263     }
264 
265     /**
266      * @param color set new color
267      */
268     protected final void setColor(final Color color)
269     {
270         this.color = color;
271     }
272 
273     /**
274      * @return Returns the flip.
275      */
276     public final boolean isFlip()
277     {
278         return this.animationImpl.isFlip();
279     }
280 
281     /**
282      * @param flip The flip to set.
283      */
284     public final void setFlip(final boolean flip)
285     {
286         this.animationImpl.setFlip(flip);
287     }
288 
289     /**
290      * @return Returns the rotate.
291      */
292     public final boolean isRotate()
293     {
294         return this.animationImpl.isRotate();
295     }
296 
297     /**
298      * @param rotate The rotate to set.
299      */
300     public final void setRotate(final boolean rotate)
301     {
302         this.animationImpl.setRotate(rotate);
303 
304     }
305 
306     /**
307      * @return Returns the scale.
308      */
309     public final boolean isScale()
310     {
311         return this.animationImpl.isScale();
312     }
313 
314     /**
315      * @param scale The scale to set.
316      */
317     public final void setScale(final boolean scale)
318     {
319         this.animationImpl.setScale(scale);
320     }
321 
322     /**
323      * @return Returns the translate.
324      */
325     public final boolean isTranslate()
326     {
327         return this.animationImpl.isTranslate();
328     }
329 
330     /**
331      * @param translate The translate to set.
332      */
333     public final void setTranslate(final boolean translate)
334     {
335         this.animationImpl.setTranslate(translate);
336     }
337 
338     /**
339      * The implementation of the text animation. Cloning will be taken care of by the overarching TextAnimation-derived class.
340      * <p>
341      * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
342      * <br>
343      * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
344      * </p>
345      * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
346      * initial version Dec 11, 2016 <br>
347      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
348      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
349      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
350      */
351     private static class AnimationImpl extends Renderable2D implements Serializable
352     {
353         /** */
354         private static final long serialVersionUID = 20170400L;
355 
356         /**
357          * @param source the source
358          * @param simulator the simulator
359          * @throws NamingException when animation context cannot be created or retrieved
360          * @throws RemoteException - when remote context cannot be found
361          */
362         AnimationImpl(final Locatable source, final OTSSimulatorInterface simulator) throws NamingException, RemoteException
363         {
364             super(source, simulator);
365         }
366 
367         /** {@inheritDoc} */
368         @Override
369         public final void paint(final Graphics2D graphics, final ImageObserver observer) throws RemoteException
370         {
371             TextAnimation ta = ((TextAnimation) getSource());
372             ta.paint(graphics, observer);
373         }
374 
375         /** {@inheritDoc} */
376         @Override
377         public final String toString()
378         {
379             return "TextAnimation.AnimationImpl []";
380         }
381 
382     }
383 }