View Javadoc
1   package org.opentrafficsim.core.network;
2   
3   import java.io.Serializable;
4   import java.util.HashMap;
5   import java.util.HashSet;
6   import java.util.Map;
7   import java.util.Set;
8   
9   import javax.media.j3d.Bounds;
10  
11  import org.djunits.value.vdouble.scalar.Length;
12  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
13  import org.opentrafficsim.core.geometry.OTSLine3D;
14  import org.opentrafficsim.core.gtu.GTU;
15  import org.opentrafficsim.core.gtu.GTUType;
16  
17  import nl.tudelft.simulation.dsol.animation.Locatable;
18  import nl.tudelft.simulation.event.EventProducer;
19  import nl.tudelft.simulation.language.Throw;
20  import nl.tudelft.simulation.language.d3.DirectedPoint;
21  
22  /**
23   * A standard implementation of a link between two OTSNodes.
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/license.html">OpenTrafficSim License</a>.
27   * <p>
28   * $LastChangedDate: 2017-04-28 03:35:59 +0200 (Fri, 28 Apr 2017) $, @version $Revision: 3569 $, by $Author: averbraeck $,
29   * initial version Aug 19, 2014 <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   */
33  public class OTSLink extends EventProducer implements Link, Serializable, Locatable
34  {
35      /** */
36      private static final long serialVersionUID = 20150101L;
37  
38      /** the Network. */
39      private final Network network;
40  
41      /** Link id. */
42      private final String id;
43  
44      /** Start node (directional). */
45      private final Node startNode;
46  
47      /** End node (directional). */
48      private final Node endNode;
49  
50      /** Link type to indicate compatibility with GTU types. */
51      private final LinkType linkType;
52  
53      /** Design line of the link. */
54      private final OTSLine3D designLine;
55  
56      /** The simulator on which events can be scheduled. */
57      private final OTSSimulatorInterface simulator;
58  
59      /** The GTUs on this Link. */
60      private final Set<GTU> gtus = new HashSet<>();
61  
62      /**
63       * The direction in which vehicles can drive, i.e., in direction of geometry, reverse, or both. It might be that the link is
64       * FORWARD (from start node to end node) for the GTU type CAR, but BOTH for the GTU type BICYCLE (i.e., bicycles can also go
65       * from end node to start node). If the directionality for a GTUType is set to NONE, this means that the given GTUTYpe
66       * cannot use the Link. If a Directionality is set for GTUType.ALL, the getDirectionality will default to these settings
67       * when there is no specific entry for a given directionality. This means that the settings can be used additive, or
68       * restrictive. <br>
69       * In <b>additive use</b>, set the directionality for GTUType.ALL to NONE, or do not set the directionality for GTUType.ALL.
70       * Now, one by one, the allowed directionalities can be added. An example is a highway, which we only open for CAR, TRUCK
71       * and BUS. <br>
72       * In <b>restrictive use</b>, set the directionality for GTUType.ALL to BOTH, FORWARD, or BACKWARD. Override the
73       * directionality for certain GTUTypes to a more restrictive access, e.g. to NONE. An example is a road that is open for all
74       * road users, except PEDESTRIAN.
75       */
76      private final Map<GTUType, LongitudinalDirectionality> directionalityMap;
77  
78      /**
79       * Construct a new link.
80       * @param id the link id
81       * @param network the network to which the link belongs
82       * @param startNode start node (directional)
83       * @param endNode end node (directional)
84       * @param linkType Link type to indicate compatibility with GTU types
85       * @param designLine the OTSLine3D design line of the Link
86       * @param simulator the simulator on which events can be scheduled
87       * @param directionalityMap the directions (FORWARD, BACKWARD, BOTH, NONE) that GTUtypes can traverse this link
88       * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
89       *             or the end node of the link are not registered in the network.
90       */
91      @SuppressWarnings("checkstyle:parameternumber")
92      public OTSLink(final Network network, final String id, final Node startNode, final Node endNode, final LinkType linkType,
93              final OTSLine3D designLine, final OTSSimulatorInterface simulator,
94              final Map<GTUType, LongitudinalDirectionality> directionalityMap) throws NetworkException
95      {
96          Throw.whenNull(network, "network cannot be null");
97          Throw.whenNull(id, "id cannot be null");
98          Throw.whenNull(startNode, "startNode cannot be null");
99          Throw.whenNull(endNode, "endNode cannot be null");
100         Throw.whenNull(linkType, "linkType cannot be null");
101         Throw.whenNull(designLine, "designLine cannot be null");
102         Throw.whenNull(simulator, "simulator cannot be null");
103         Throw.whenNull(directionalityMap, "directionalityMap cannot be null");
104 
105         this.network = network;
106         this.id = id;
107         this.startNode = startNode;
108         this.endNode = endNode;
109         this.linkType = linkType;
110         this.startNode.addLink(this);
111         this.endNode.addLink(this);
112         this.designLine = designLine;
113         this.simulator = simulator;
114         this.directionalityMap = directionalityMap;
115 
116         this.network.addLink(this);
117     }
118 
119     /**
120      * Construct a new link, with a directionality for all GTUs as provided.
121      * @param id the link id
122      * @param network the network to which the link belongs
123      * @param startNode start node (directional)
124      * @param endNode end node (directional)
125      * @param linkType Link type to indicate compatibility with GTU types
126      * @param designLine the OTSLine3D design line of the Link
127      * @param simulator the simulator on which events can be scheduled
128      * @param directionality the directionality for all GTUs
129      * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
130      *             or the end node of the link are not registered in the network.
131      */
132     @SuppressWarnings("checkstyle:parameternumber")
133     public OTSLink(final Network network, final String id, final Node startNode, final Node endNode, final LinkType linkType,
134             final OTSLine3D designLine, final OTSSimulatorInterface simulator, final LongitudinalDirectionality directionality)
135             throws NetworkException
136     {
137         this(network, id, startNode, endNode, linkType, designLine, simulator,
138                 new HashMap<GTUType, LongitudinalDirectionality>());
139         addDirectionality(GTUType.ALL, directionality);
140     }
141 
142     /**
143      * Clone a link for a new network.
144      * @param newNetwork the new network to which the clone belongs
145      * @param newSimulator the new simulator for this network
146      * @param animation whether to (re)create animation or not. Could be used in subclasses.
147      * @param link the link to clone from
148      * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
149      *             or the end node of the link are not registered in the network.
150      */
151     protected OTSLink(final Network newNetwork, final OTSSimulatorInterface newSimulator, final boolean animation,
152             final OTSLink link) throws NetworkException
153     {
154         this(newNetwork, link.id, newNetwork.getNode(link.startNode.getId()), newNetwork.getNode(link.endNode.getId()),
155                 link.linkType, link.designLine, newSimulator, new HashMap<>(link.directionalityMap));
156     }
157 
158     /** {@inheritDoc} */
159     @Override
160     public final LongitudinalDirectionality getDirectionality(final GTUType gtuType)
161     {
162         if (this.directionalityMap.containsKey(gtuType))
163         {
164             return this.directionalityMap.get(gtuType);
165         }
166         if (this.directionalityMap.containsKey(GTUType.ALL))
167         {
168             return this.directionalityMap.get(GTUType.ALL);
169         }
170         return LongitudinalDirectionality.DIR_NONE;
171     }
172 
173     /** {@inheritDoc} */
174     @Override
175     public final void addDirectionality(final GTUType gtuType, final LongitudinalDirectionality directionality)
176     {
177         this.directionalityMap.put(gtuType, directionality);
178     }
179 
180     /** {@inheritDoc} */
181     @Override
182     public final void removeDirectionality(final GTUType gtuType)
183     {
184         this.directionalityMap.remove(gtuType);
185     }
186 
187     /** {@inheritDoc} */
188     @Override
189     public final void addGTU(final GTU gtu)
190     {
191         if (!this.gtus.contains(gtu))
192         {
193             this.gtus.add(gtu);
194             fireTimedEvent(Link.GTU_ADD_EVENT, new Object[] { gtu.getId(), gtu, this.gtus.size() },
195                     gtu.getSimulator().getSimulatorTime());
196         }
197     }
198 
199     /** {@inheritDoc} */
200     @Override
201     public final void removeGTU(final GTU gtu)
202     {
203         if (this.gtus.contains(gtu))
204         {
205             this.gtus.remove(gtu);
206             fireTimedEvent(Link.GTU_REMOVE_EVENT, new Object[] { gtu.getId(), gtu, this.gtus.size() },
207                     gtu.getSimulator().getSimulatorTime());
208         }
209     }
210 
211     /** {@inheritDoc} */
212     @Override
213     public final Set<GTU> getGTUs()
214     {
215         return new HashSet<GTU>(this.gtus);
216     }
217 
218     /** {@inheritDoc} */
219     @Override
220     public final int getGTUCount()
221     {
222         return this.gtus.size();
223     }
224 
225     /** {@inheritDoc} */
226     @Override
227     public final Network getNetwork()
228     {
229         return this.network;
230     }
231 
232     /** {@inheritDoc} */
233     @Override
234     public final String getId()
235     {
236         return this.id;
237     }
238 
239     /** {@inheritDoc} */
240     @Override
241     public final Node getStartNode()
242     {
243         return this.startNode;
244     }
245 
246     /** {@inheritDoc} */
247     @Override
248     public final Node getEndNode()
249     {
250         return this.endNode;
251     }
252 
253     /** {@inheritDoc} */
254     @Override
255     public final LinkType getLinkType()
256     {
257         return this.linkType;
258     }
259 
260     /** {@inheritDoc} */
261     @Override
262     public final OTSLine3D getDesignLine()
263     {
264         return this.designLine;
265     }
266 
267     /** {@inheritDoc} */
268     @Override
269     public final OTSSimulatorInterface getSimulator()
270     {
271         return this.simulator;
272     }
273 
274     /**
275      * @return directionalityMap the directionality map. Only for internal use in (sub)classes.
276      */
277     protected final Map<GTUType, LongitudinalDirectionality> getDirectionalityMap()
278     {
279         return this.directionalityMap;
280     }
281 
282     /** {@inheritDoc} */
283     @Override
284     public final Length getLength()
285     {
286         return this.designLine.getLength();
287     }
288 
289     /** the location with 0.01 m extra height. */
290     private DirectedPoint zLocation = null;
291 
292     /** {@inheritDoc} */
293     @Override
294     @SuppressWarnings("checkstyle:designforextension")
295     public DirectedPoint getLocation()
296     {
297         if (this.zLocation == null)
298         {
299             DirectedPoint p = this.designLine.getLocation();
300             this.zLocation = new DirectedPoint(p.x, p.y, p.z + 0.01, p.getRotX(), p.getRotY(), p.getRotZ());
301         }
302         return this.zLocation;
303     }
304 
305     /** {@inheritDoc} */
306     @Override
307     @SuppressWarnings("checkstyle:designforextension")
308     public Bounds getBounds()
309     {
310         return this.designLine.getBounds();
311     }
312 
313     /** {@inheritDoc} */
314     @Override
315     @SuppressWarnings("checkstyle:designforextension")
316     public String toString()
317     {
318         return this.id.toString();
319     }
320 
321     /** {@inheritDoc} */
322     @Override
323     @SuppressWarnings("checkstyle:designforextension")
324     public int hashCode()
325     {
326         final int prime = 31;
327         int result = 1;
328         result = prime * result + ((this.endNode == null) ? 0 : this.endNode.hashCode());
329         result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
330         result = prime * result + ((this.linkType == null) ? 0 : this.linkType.hashCode());
331         result = prime * result + ((this.startNode == null) ? 0 : this.startNode.hashCode());
332         return result;
333     }
334 
335     /** {@inheritDoc} */
336     @Override
337     @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
338     public boolean equals(final Object obj)
339     {
340         if (this == obj)
341             return true;
342         if (obj == null)
343             return false;
344         if (getClass() != obj.getClass())
345             return false;
346         OTSLink other = (OTSLink) obj;
347         if (this.endNode == null)
348         {
349             if (other.endNode != null)
350                 return false;
351         }
352         else if (!this.endNode.equals(other.endNode))
353             return false;
354         if (this.id == null)
355         {
356             if (other.id != null)
357                 return false;
358         }
359         else if (!this.id.equals(other.id))
360             return false;
361         if (this.linkType == null)
362         {
363             if (other.linkType != null)
364                 return false;
365         }
366         else if (!this.linkType.equals(other.linkType))
367             return false;
368         if (this.startNode == null)
369         {
370             if (other.startNode != null)
371                 return false;
372         }
373         else if (!this.startNode.equals(other.startNode))
374             return false;
375         return true;
376     }
377 
378     /**
379      * Clone the OTSLink for e.g., copying a network.
380      * @param newNetwork the new network to which the clone belongs
381      * @param newSimulator the new simulator for this network
382      * @param animation whether to (re)create animation or not
383      * @return a clone of this object
384      * @throws NetworkException in case the cloning fails
385      */
386     @SuppressWarnings("checkstyle:designforextension")
387     public OTSLink clone(final Network newNetwork, final OTSSimulatorInterface newSimulator, final boolean animation)
388             throws NetworkException
389     {
390         return new OTSLink(newNetwork, newSimulator, animation, this);
391     }
392 }