View Javadoc
1   package org.opentrafficsim.core.network;
2   
3   import java.io.Serializable;
4   import java.util.LinkedHashSet;
5   import java.util.Set;
6   
7   import javax.media.j3d.Bounds;
8   
9   import org.djunits.value.vdouble.scalar.Length;
10  import org.opentrafficsim.core.geometry.OTSLine3D;
11  import org.opentrafficsim.core.gtu.GTU;
12  import org.opentrafficsim.core.gtu.GTUType;
13  
14  import nl.tudelft.simulation.dsol.animation.Locatable;
15  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
16  import nl.tudelft.simulation.event.EventProducer;
17  import nl.tudelft.simulation.language.Throw;
18  import nl.tudelft.simulation.language.d3.DirectedPoint;
19  
20  /**
21   * A standard implementation of a link between two OTSNodes.
22   * <p>
23   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
24   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
25   * <p>
26   * $LastChangedDate: 2018-09-19 13:55:45 +0200 (Wed, 19 Sep 2018) $, @version $Revision: 4006 $, by $Author: averbraeck $,
27   * initial version Aug 19, 2014 <br>
28   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
29   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
30   */
31  public class OTSLink extends EventProducer implements Link, Serializable, Locatable
32  {
33      /** */
34      private static final long serialVersionUID = 20150101L;
35  
36      /** the Network. */
37      private final Network network;
38  
39      /** Link id. */
40      private final String id;
41  
42      /** Start node (directional). */
43      private final Node startNode;
44  
45      /** End node (directional). */
46      private final Node endNode;
47  
48      /** Link type to indicate compatibility with GTU types. */
49      private final LinkType linkType;
50  
51      /** Design line of the link. */
52      private final OTSLine3D designLine;
53  
54      /** The simulator on which events can be scheduled. */
55      private final SimulatorInterface.TimeDoubleUnit simulator;
56  
57      /** The GTUs on this Link. */
58      private final Set<GTU> gtus = new LinkedHashSet<>();
59  
60      /**
61       * Construct a new link.
62       * @param id the link id
63       * @param network the network to which the link belongs
64       * @param startNode start node (directional)
65       * @param endNode end node (directional)
66       * @param linkType Link type to indicate compatibility with GTU types
67       * @param designLine the OTSLine3D design line of the Link
68       * @param simulator the simulator on which events can be scheduled
69       * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
70       *             or the end node of the link are not registered in the network.
71       */
72      @SuppressWarnings("checkstyle:parameternumber")
73      public OTSLink(final Network network, final String id, final Node startNode, final Node endNode, final LinkType linkType,
74              final OTSLine3D designLine, final SimulatorInterface.TimeDoubleUnit simulator) throws NetworkException
75      {
76          Throw.whenNull(network, "network cannot be null");
77          Throw.whenNull(id, "id cannot be null");
78          Throw.whenNull(startNode, "startNode cannot be null");
79          Throw.whenNull(endNode, "endNode cannot be null");
80          Throw.whenNull(linkType, "linkType cannot be null");
81          Throw.whenNull(designLine, "designLine cannot be null");
82          Throw.whenNull(simulator, "simulator cannot be null");
83  
84          this.network = network;
85          this.id = id;
86          this.startNode = startNode;
87          this.endNode = endNode;
88          this.linkType = linkType;
89          this.startNode.addLink(this);
90          this.endNode.addLink(this);
91          this.designLine = designLine;
92          this.simulator = simulator;
93          this.network.addLink(this);
94      }
95  
96      /**
97       * Clone a link for a new network.
98       * @param newNetwork the new network to which the clone belongs
99       * @param newSimulator the new simulator for this network
100      * @param animation whether to (re)create animation or not. Could be used in subclasses.
101      * @param link the link to clone from
102      * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
103      *             or the end node of the link are not registered in the network.
104      */
105     protected OTSLink(final Network newNetwork, final SimulatorInterface.TimeDoubleUnit newSimulator, final boolean animation,
106             final OTSLink link) throws NetworkException
107     {
108         this(newNetwork, link.id, newNetwork.getNode(link.startNode.getId()), newNetwork.getNode(link.endNode.getId()),
109                 link.linkType, link.designLine, newSimulator);
110     }
111 
112     /** {@inheritDoc} */
113     @Override
114     public final LongitudinalDirectionality getDirectionality(final GTUType gtuType)
115     {
116         return this.getLinkType().getDirectionality(gtuType, true);
117     }
118 
119     /** {@inheritDoc} */
120     @Override
121     public final void addGTU(final GTU gtu)
122     {
123         if (!this.gtus.contains(gtu))
124         {
125             this.gtus.add(gtu);
126             fireTimedEvent(Link.GTU_ADD_EVENT, new Object[] { gtu.getId(), gtu, this.gtus.size() },
127                     gtu.getSimulator().getSimulatorTime());
128         }
129     }
130 
131     /** {@inheritDoc} */
132     @Override
133     public final void removeGTU(final GTU gtu)
134     {
135         if (this.gtus.contains(gtu))
136         {
137             this.gtus.remove(gtu);
138             fireTimedEvent(Link.GTU_REMOVE_EVENT, new Object[] { gtu.getId(), gtu, this.gtus.size() },
139                     gtu.getSimulator().getSimulatorTime());
140         }
141     }
142 
143     /** {@inheritDoc} */
144     @Override
145     public final Set<GTU> getGTUs()
146     {
147         return new LinkedHashSet<>(this.gtus);
148     }
149 
150     /** {@inheritDoc} */
151     @Override
152     public final int getGTUCount()
153     {
154         return this.gtus.size();
155     }
156 
157     /** {@inheritDoc} */
158     @Override
159     public final Network getNetwork()
160     {
161         return this.network;
162     }
163 
164     /** {@inheritDoc} */
165     @Override
166     public final String getId()
167     {
168         return this.id;
169     }
170 
171     /** {@inheritDoc} */
172     @Override
173     public final Node getStartNode()
174     {
175         return this.startNode;
176     }
177 
178     /** {@inheritDoc} */
179     @Override
180     public final Node getEndNode()
181     {
182         return this.endNode;
183     }
184 
185     /** {@inheritDoc} */
186     @Override
187     public final LinkType getLinkType()
188     {
189         return this.linkType;
190     }
191 
192     /** {@inheritDoc} */
193     @Override
194     public final OTSLine3D getDesignLine()
195     {
196         return this.designLine;
197     }
198 
199     /** {@inheritDoc} */
200     @Override
201     public final SimulatorInterface.TimeDoubleUnit getSimulator()
202     {
203         return this.simulator;
204     }
205 
206     /** {@inheritDoc} */
207     @Override
208     public final Length getLength()
209     {
210         return this.designLine.getLength();
211     }
212 
213     /** the location with 0.01 m extra height. */
214     private DirectedPoint zLocation = null;
215 
216     /** {@inheritDoc} */
217     @Override
218     @SuppressWarnings("checkstyle:designforextension")
219     public DirectedPoint getLocation()
220     {
221         if (this.zLocation == null)
222         {
223             DirectedPoint p = this.designLine.getLocation();
224             this.zLocation = new DirectedPoint(p.x, p.y, p.z + 0.01, p.getRotX(), p.getRotY(), p.getRotZ());
225         }
226         return this.zLocation;
227     }
228 
229     /** {@inheritDoc} */
230     @Override
231     @SuppressWarnings("checkstyle:designforextension")
232     public Bounds getBounds()
233     {
234         return this.designLine.getBounds();
235     }
236 
237     /** {@inheritDoc} */
238     @Override
239     @SuppressWarnings("checkstyle:designforextension")
240     public String toString()
241     {
242         return this.id.toString();
243     }
244 
245     /** {@inheritDoc} */
246     @Override
247     @SuppressWarnings("checkstyle:designforextension")
248     public int hashCode()
249     {
250         final int prime = 31;
251         int result = 1;
252         result = prime * result + ((this.endNode == null) ? 0 : this.endNode.hashCode());
253         result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
254         result = prime * result + ((this.linkType == null) ? 0 : this.linkType.hashCode());
255         result = prime * result + ((this.startNode == null) ? 0 : this.startNode.hashCode());
256         return result;
257     }
258 
259     /** {@inheritDoc} */
260     @Override
261     @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
262     public boolean equals(final Object obj)
263     {
264         if (this == obj)
265             return true;
266         if (obj == null)
267             return false;
268         if (getClass() != obj.getClass())
269             return false;
270         OTSLink other = (OTSLink) obj;
271         if (this.endNode == null)
272         {
273             if (other.endNode != null)
274                 return false;
275         }
276         else if (!this.endNode.equals(other.endNode))
277             return false;
278         if (this.id == null)
279         {
280             if (other.id != null)
281                 return false;
282         }
283         else if (!this.id.equals(other.id))
284             return false;
285         if (this.linkType == null)
286         {
287             if (other.linkType != null)
288                 return false;
289         }
290         else if (!this.linkType.equals(other.linkType))
291             return false;
292         if (this.startNode == null)
293         {
294             if (other.startNode != null)
295                 return false;
296         }
297         else if (!this.startNode.equals(other.startNode))
298             return false;
299         return true;
300     }
301 
302     /**
303      * Clone the OTSLink for e.g., copying a network.
304      * @param newNetwork the new network to which the clone belongs
305      * @param newSimulator the new simulator for this network
306      * @param animation whether to (re)create animation or not
307      * @return a clone of this object
308      * @throws NetworkException in case the cloning fails
309      */
310     @SuppressWarnings("checkstyle:designforextension")
311     public OTSLink clone(final Network newNetwork, final SimulatorInterface.TimeDoubleUnit newSimulator,
312             final boolean animation) throws NetworkException
313     {
314         return new OTSLink(newNetwork, newSimulator, animation, this);
315     }
316 }