View Javadoc
1   package org.opentrafficsim.draw.network;
2   
3   import java.awt.Color;
4   import java.awt.Graphics2D;
5   import java.awt.image.ImageObserver;
6   import java.io.Serializable;
7   import java.rmi.RemoteException;
8   
9   import javax.naming.NamingException;
10  
11  import org.djutils.draw.line.PolyLine3d;
12  import org.djutils.draw.point.Point3d;
13  import org.djutils.logger.CategoryLogger;
14  import org.opentrafficsim.core.geometry.DirectedPoint;
15  import org.opentrafficsim.core.geometry.OTSGeometryException;
16  import org.opentrafficsim.core.geometry.OTSLine3D;
17  import org.opentrafficsim.core.geometry.OTSPoint3D;
18  import org.opentrafficsim.core.network.Link;
19  import org.opentrafficsim.core.network.LinkType;
20  import org.opentrafficsim.draw.core.ClonableRenderable2DInterface;
21  import org.opentrafficsim.draw.core.PaintLine;
22  import org.opentrafficsim.draw.core.TextAlignment;
23  import org.opentrafficsim.draw.core.TextAnimation;
24  
25  import nl.tudelft.simulation.dsol.animation.Locatable;
26  import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
27  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
28  import nl.tudelft.simulation.language.d2.Angle;
29  
30  /**
31   * Draws a Link.
32   * <p>
33   * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
34   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
35   * <p>
36   * $LastChangedDate: 2018-10-11 22:54:04 +0200 (Thu, 11 Oct 2018) $, @version $Revision: 4696 $, by $Author: averbraeck $,
37   * initial version Sep 13, 2014 <br>
38   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
39   */
40  public class LinkAnimation extends Renderable2D<Link> implements ClonableRenderable2DInterface<Link>, Serializable
41  {
42      /** */
43      private static final long serialVersionUID = 20140000L;
44  
45      /** */
46      private float width;
47  
48      /** the Text object to destroy when the animation is destroyed. */
49      private Text text;
50  
51      /**
52       * @param link Link; Link
53       * @param simulator SimulatorInterface.TimeDoubleUnit; simulator
54       * @param width float; width
55       * @throws NamingException for problems with registering in context
56       * @throws RemoteException on communication failure
57       */
58      public LinkAnimation(final Link link, final SimulatorInterface.TimeDoubleUnit simulator, final float width)
59              throws NamingException, RemoteException
60      {
61          super(link, simulator);
62          this.width = width;
63          this.text = new Text(link, link.getId(), 0.0f, 1.5f, TextAlignment.CENTER, Color.BLACK, simulator,
64                  link.getLinkType().getId().equals(LinkType.DEFAULTS.FREEWAY.getId()) ? TextAnimation.RENDERWHEN10
65                          : TextAnimation.RENDERWHEN1);
66      }
67  
68      /** {@inheritDoc} */
69      @Override
70      public final void paint(final Graphics2D graphics, final ImageObserver observer)
71      {
72          try
73          {
74              Color color = getSource().getLinkType().isConnector() ? Color.PINK.darker() : Color.BLUE;
75              OTSLine3D designLine = getSource().getDesignLine();
76              PaintLine.paintLine(graphics, color, this.width, getSource().getLocation(), designLine);
77              // Accentuate the end points
78              try
79              {
80                  drawEndPoint(designLine.getFirst(), designLine.get(1), graphics);
81                  drawEndPoint(designLine.getLast(), designLine.get(designLine.size() - 2), graphics);
82              }
83              catch (OTSGeometryException exception)
84              {
85                  // Cannot happen
86                  CategoryLogger.always().error(exception);
87              }
88          }
89          catch (RemoteException e)
90          {
91              CategoryLogger.always().warn(e);
92          }
93      }
94  
95      /**
96       * Draw end point on design line.
97       * @param endPoint OTSPoint3D; the end of the design line where a end point must be highlighted
98       * @param nextPoint OTSPoint3D; the point nearest <code>endPoint</code> (needed to figure out the direction of the design
99       *            line)
100      * @param graphics Graphics2D; graphics content
101      */
102     private void drawEndPoint(final OTSPoint3D endPoint, final OTSPoint3D nextPoint, final Graphics2D graphics)
103     {
104         // End point marker is 2 times the width of the design line
105         double dx = nextPoint.x - endPoint.x;
106         double dy = nextPoint.y - endPoint.y;
107         double length = endPoint.distanceSI(nextPoint);
108         // scale dx, dy so that size is this.width
109         dx *= this.width / length;
110         dy *= this.width / length;
111         try
112         {
113             PolyLine3d line = new PolyLine3d(new Point3d(endPoint.x - dy, endPoint.y + dx, endPoint.z),
114                     new Point3d(endPoint.x + dy, endPoint.y - dx, endPoint.z));
115             PaintLine.paintLine(graphics, getSource().getLinkType().isConnector() ? Color.PINK.darker() : Color.BLUE,
116                     this.width / 30, getSource().getLocation(), line);
117         }
118         catch (RemoteException exception)
119         {
120             CategoryLogger.always().error(exception);
121         }
122     }
123 
124     /** {@inheritDoc} */
125     @Override
126     public final void destroy(final SimulatorInterface<?, ?, ?> simulator)
127     {
128         super.destroy(simulator);
129         this.text.destroy(simulator);
130     }
131 
132     /** {@inheritDoc} */
133     @Override
134     @SuppressWarnings("checkstyle:designforextension")
135     public ClonableRenderable2DInterface<Link> clone(final Link newSource, final SimulatorInterface.TimeDoubleUnit newSimulator)
136             throws NamingException, RemoteException
137     {
138         // the constructor also constructs the corresponding Text object
139         return new LinkAnimation(newSource, newSimulator, this.width);
140     }
141 
142     /** {@inheritDoc} */
143     @Override
144     public final String toString()
145     {
146         return "LinkAnimation [width=" + this.width + ", link=" + super.getSource() + "]";
147     }
148 
149     /**
150      * Text animation for the Link. Separate class to be able to turn it on and off...
151      * <p>
152      * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
153      * <br>
154      * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
155      * </p>
156      * $LastChangedDate: 2018-10-11 22:54:04 +0200 (Thu, 11 Oct 2018) $, @version $Revision: 4696 $, by $Author: averbraeck $,
157      * initial version Dec 11, 2016 <br>
158      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
159      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
160      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
161      */
162     public class Text extends TextAnimation
163     {
164         /** */
165         private static final long serialVersionUID = 20161211L;
166 
167         /**
168          * @param source Locatable; the object for which the text is displayed
169          * @param text String; the text to display
170          * @param dx float; the horizontal movement of the text, in meters
171          * @param dy float; the vertical movement of the text, in meters
172          * @param textPlacement TextAlignment; where to place the text
173          * @param color Color; the color of the text
174          * @param simulator SimulatorInterface.TimeDoubleUnit; the simulator
175          * @param scaleDependentRendering ScaleDependentRendering; enables rendering in a scale dependent fashion
176          * @throws NamingException when animation context cannot be created or retrieved
177          * @throws RemoteException - when remote context cannot be found
178          */
179         public Text(final Locatable source, final String text, final float dx, final float dy,
180                 final TextAlignment textPlacement, final Color color, final SimulatorInterface.TimeDoubleUnit simulator,
181                 final ScaleDependentRendering scaleDependentRendering) throws RemoteException, NamingException
182         {
183             super(source, text, dx, dy, textPlacement, color, 2.0f, 12.0f, 50f, simulator, null, scaleDependentRendering);
184         }
185 
186         /** {@inheritDoc} */
187         @Override
188         @SuppressWarnings("checkstyle:designforextension")
189         public DirectedPoint getLocation()
190         {
191             // draw always on top, and not upside down.
192             DirectedPoint p = ((Link) getSource()).getDesignLine().getLocationFractionExtended(0.5);
193             double a = Angle.normalizePi(p.getRotZ());
194             if (a > Math.PI / 2.0 || a < -0.99 * Math.PI / 2.0)
195             {
196                 a += Math.PI;
197             }
198             return new DirectedPoint(p.x, p.y, Double.MAX_VALUE, 0.0, 0.0, a);
199         }
200 
201         /** {@inheritDoc} */
202         @Override
203         @SuppressWarnings("checkstyle:designforextension")
204         public TextAnimation clone(final Locatable newSource, final SimulatorInterface.TimeDoubleUnit newSimulator)
205                 throws RemoteException, NamingException
206         {
207             return new Text(newSource, getText(), getDx(), getDy(), getTextAlignment(), getColor(), newSimulator,
208                     super.getScaleDependentRendering());
209         }
210 
211         /** {@inheritDoc} */
212         @Override
213         public final String toString()
214         {
215             return "LinkAnimation.Text []";
216         }
217     }
218 
219 }