View Javadoc
1   package org.opentrafficsim.road.network.lane;
2   
3   import java.io.Serializable;
4   import java.util.ArrayList;
5   import java.util.List;
6   
7   import org.opentrafficsim.core.geometry.OTSLine3D;
8   import org.opentrafficsim.core.network.LinkType;
9   import org.opentrafficsim.core.network.Network;
10  import org.opentrafficsim.core.network.NetworkException;
11  import org.opentrafficsim.core.network.Node;
12  import org.opentrafficsim.core.network.OTSLink;
13  import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
14  
15  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
16  import nl.tudelft.simulation.event.EventType;
17  import nl.tudelft.simulation.language.Throw;
18  
19  /**
20   * A CrossSectionLink is a link with lanes where GTUs can possibly switch between lanes.
21   * <p>
22   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
23   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
24   * <p>
25   * $LastChangedDate: 2015-09-16 19:20:07 +0200 (Wed, 16 Sep 2015) $, @version $Revision: 1405 $, by $Author: averbraeck $,
26   * initial version Aug 19, 2014 <br>
27   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
28   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
29   * @author <a href="http://www.citg.tudelft.nl">Guus Tamminga</a>
30   */
31  public class CrossSectionLink extends OTSLink implements Serializable
32  {
33      /** */
34      private static final long serialVersionUID = 20141015L;
35  
36      /** List of cross-section elements. */
37      private final List<CrossSectionElement> crossSectionElementList = new ArrayList<>();
38  
39      /** List of lanes. */
40      private final List<Lane> lanes = new ArrayList<>();
41  
42      /** The policy to generally keep left, keep right, or keep lane. */
43      private final LaneKeepingPolicy laneKeepingPolicy;
44  
45      /** Priority. */
46      // TODO per GTUDirectionality / LongitudinalDirectionality?
47      private Priority priority = Priority.NONE;
48  
49      /** Fraction in range 0...1 to divide origin or destination flow over connectors. */
50      private Double demandWeight = null;
51  
52      /**
53       * The (regular, not timed) event type for pub/sub indicating the addition of a Lane to a CrossSectionLink. <br>
54       * Payload: Object[] { String networkId, String linkId, String LaneId, Lane lane, int laneNumber } <br>
55       * TODO work in a different way with lane numbers to align to standard lane numbering.
56       */
57      public static final EventType LANE_ADD_EVENT = new EventType("LINK.LANE.ADD");
58  
59      /**
60       * The (regular, not timed) event type for pub/sub indicating the removal of a Lane from a CrossSectionLink. <br>
61       * Payload: Object[] { String networkId, String linkId, String LaneId } <br>
62       * TODO allow for the removal of a Lane; currently this is not possible.
63       */
64      public static final EventType LANE_REMOVE_EVENT = new EventType("LINK.LANE.REMOVE");
65  
66      /**
67       * Construction of a cross section link.
68       * @param network Network; the network
69       * @param id String; the link id.
70       * @param startNode OTSNode; the start node (directional).
71       * @param endNode OTSNode; the end node (directional).
72       * @param linkType LinkType; the link type
73       * @param designLine OTSLine3D; the design line of the Link
74       * @param simulator the simulator on which events can be scheduled
75       * @param laneKeepingPolicy LaneKeepingPolicy; the policy to generally keep left, keep right, or keep lane
76       * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
77       *             or the end node of the link are not registered in the network.
78       */
79      @SuppressWarnings("checkstyle:parameternumber")
80      public CrossSectionLink(final Network network, final String id, final Node startNode, final Node endNode,
81              final LinkType linkType, final OTSLine3D designLine, final SimulatorInterface.TimeDoubleUnit simulator,
82              final LaneKeepingPolicy laneKeepingPolicy) throws NetworkException
83      {
84          super(network, id, startNode, endNode, linkType, designLine, simulator);
85          this.laneKeepingPolicy = laneKeepingPolicy;
86      }
87  
88      /**
89       * Clone a CrossSectionLink for a new network.
90       * @param newNetwork the new network to which the clone belongs
91       * @param newSimulator the new simulator for this network
92       * @param animation whether to (re)create animation or not
93       * @param link the link to clone from
94       * @throws NetworkException if link already exists in the network, if name of the link is not unique, or if the start node
95       *             or the end node of the link are not registered in the network.
96       */
97      protected CrossSectionLink(final Network newNetwork, final SimulatorInterface.TimeDoubleUnit newSimulator, final boolean animation,
98              final CrossSectionLink link) throws NetworkException
99      {
100         super(newNetwork, newSimulator, animation, link);
101         this.laneKeepingPolicy = link.laneKeepingPolicy;
102         for (CrossSectionElement cse : link.crossSectionElementList)
103         {
104             cse.clone(this, newSimulator, animation);
105             // the CrossSectionElement will add itself to the Link (OTS-237)
106         }
107     }
108 
109     /**
110      * Add a cross section element at the end of the list. <br>
111      * <b>Note:</b> LEFT is seen as a positive lateral direction, RIGHT as a negative lateral direction.
112      * @param cse CrossSectionElement; the cross section element to add.
113      */
114     protected final void addCrossSectionElement(final CrossSectionElement cse)
115     {
116         this.crossSectionElementList.add(cse);
117         if (cse instanceof Lane)
118         {
119             this.lanes.add((Lane) cse);
120             fireEvent(LANE_ADD_EVENT,
121                     new Object[] { getNetwork().getId(), getId(), cse.getId(), (Lane) cse, this.lanes.indexOf(cse) });
122         }
123     }
124 
125     /**
126      * Retrieve a safe copy of the cross section element list.
127      * @return List&lt;CrossSectionElement&gt;; the cross section element list.
128      */
129     public final List<CrossSectionElement> getCrossSectionElementList()
130     {
131         return this.crossSectionElementList == null ? new ArrayList<>() : new ArrayList<>(this.crossSectionElementList);
132     }
133 
134     /**
135      * Retrieve the lane keeping policy.
136      * @return LaneKeepingPolicy; the lane keeping policy on this CrossSectionLink
137      */
138     public final LaneKeepingPolicy getLaneKeepingPolicy()
139     {
140         return this.laneKeepingPolicy;
141     }
142 
143     /**
144      * Find a cross section element with a specified id.
145      * @param id String; the id to search for
146      * @return CrossSectionElement; the cross section element with the given id, or null if not found
147      */
148     public final CrossSectionElement getCrossSectionElement(final String id)
149     {
150         for (CrossSectionElement cse : this.crossSectionElementList)
151         {
152             if (cse.getId().equals(id))
153             {
154                 return cse;
155             }
156         }
157         return null;
158     }
159 
160     /**
161      * Return a safe copy of the list of lanes of this CrossSectionLink.
162      * @return List&lt;Lane&gt;; the list of lanes.
163      */
164     public final List<Lane> getLanes()
165     {
166         return this.lanes == null ? new ArrayList<>() : new ArrayList<>(this.lanes);
167     }
168 
169     /**
170      * @return priority.
171      */
172     public final Priority getPriority()
173     {
174         return this.priority;
175     }
176 
177     /**
178      * @param priority set priority.
179      */
180     public final void setPriority(final Priority priority)
181     {
182         this.priority = priority;
183     }
184 
185     /**
186      * Sets the demand weight. This is only applicable to links of type CONNECTOR.
187      * @param demandWeight double; demand weight, which is any positive value
188      */
189     public final void setDemandWeight(final double demandWeight)
190     {
191         Throw.when(demandWeight < 0.0, IllegalArgumentException.class, "Demand weight should be positive.");
192         Throw.when(!getLinkType().isConnector(), IllegalArgumentException.class,
193                 "Demand weight can only be set on connectors.");
194         this.demandWeight = demandWeight;
195     }
196 
197     /**
198      * Clears the demand weight. This is only applicable to links of type CONNECTOR.
199      */
200     public final void clearDemandWeight()
201     {
202         this.demandWeight = null;
203     }
204 
205     /**
206      * Returns the demand weight. This is only applicable to links of type CONNECTOR.
207      * @return Double; demand weight, any positive value, or {@code null}
208      */
209     public final Double getDemandWeight()
210     {
211         return this.demandWeight;
212     }
213 
214     /** {@inheritDoc} */
215     @Override
216     public final String toString()
217     {
218         return "CrossSectionLink [crossSectionElementList=" + this.crossSectionElementList + ", lanes=" + this.lanes
219                 + ", laneKeepingPolicy=" + this.laneKeepingPolicy + "]";
220     }
221 
222     /** {@inheritDoc} */
223     @Override
224     @SuppressWarnings("checkstyle:designforextension")
225     public CrossSectionLink clone(final Network newNetwork, final SimulatorInterface.TimeDoubleUnit newSimulator, final boolean animation)
226             throws NetworkException
227     {
228         return new CrossSectionLink(newNetwork, newSimulator, animation, this);
229     }
230 
231     /**
232      * Priority of a link.
233      * <p>
234      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
235      * <br>
236      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
237      * <p>
238      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 12 dec. 2016 <br>
239      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
240      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
241      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
242      */
243     public enum Priority
244     {
245         /** Traffic has priority. */
246         PRIORITY,
247 
248         /** No priority. */
249         NONE,
250 
251         /** Turn on red. */
252         TURN_ON_RED,
253 
254         /** Yield. */
255         YIELD,
256 
257         /** Need to stop. */
258         STOP,
259 
260         /** Priority according to all-stop rules. */
261         ALL_STOP,
262 
263         /** Priority at bus stop, i.e. bus has right of way if it wants to leave the bus stop. */
264         BUS_STOP;
265 
266         /**
267          * Returns whether this is priority.
268          * @return whether this is priority
269          */
270         public boolean isPriority()
271         {
272             return this.equals(PRIORITY);
273         }
274 
275         /**
276          * Returns whether this is none.
277          * @return whether this is none
278          */
279         public boolean isNone()
280         {
281             return this.equals(NONE);
282         }
283 
284         /**
285          * Returns whether this is turn on red.
286          * @return whether this is turn on red
287          */
288         public boolean isTurnOnRed()
289         {
290             return this.equals(TURN_ON_RED);
291         }
292 
293         /**
294          * Returns whether this is yield.
295          * @return whether this is yield
296          */
297         public boolean isYield()
298         {
299             return this.equals(YIELD);
300         }
301 
302         /**
303          * Returns whether this is stop.
304          * @return whether this is stop
305          */
306         public boolean isStop()
307         {
308             return this.equals(STOP);
309         }
310 
311         /**
312          * Returns whether this is all-stop.
313          * @return whether this is all-stop
314          */
315         public boolean isAllStop()
316         {
317             return this.equals(ALL_STOP);
318         }
319 
320         /**
321          * Returns whether this is bus stop.
322          * @return whether this is bus stop
323          */
324         public boolean isBusStop()
325         {
326             return this.equals(BUS_STOP);
327         }
328 
329     }
330 
331 }