View Javadoc
1   package org.opentrafficsim.road.network.lane.object;
2   
3   import java.rmi.RemoteException;
4   import java.util.HashSet;
5   import java.util.List;
6   import java.util.Map;
7   import java.util.Set;
8   
9   import javax.naming.NamingException;
10  
11  import org.djunits.value.vdouble.scalar.Length;
12  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
13  import org.opentrafficsim.core.gtu.GTUDirectionality;
14  import org.opentrafficsim.core.network.LongitudinalDirectionality;
15  import org.opentrafficsim.core.network.NetworkException;
16  import org.opentrafficsim.road.gtu.lane.RoadGTUTypes;
17  import org.opentrafficsim.road.network.animation.BusStopAnimation;
18  import org.opentrafficsim.road.network.lane.CrossSectionElement;
19  import org.opentrafficsim.road.network.lane.Lane;
20  import org.opentrafficsim.road.network.lane.conflict.BusStopConflictRule;
21  import org.opentrafficsim.road.network.lane.conflict.Conflict;
22  
23  import nl.tudelft.simulation.immutablecollections.Immutable;
24  import nl.tudelft.simulation.immutablecollections.ImmutableHashSet;
25  import nl.tudelft.simulation.immutablecollections.ImmutableSet;
26  
27  /**
28   * A bus stop is a location on a lane. The stop has a name, and a set of lines. At a single stop in reality, there may be
29   * different locations where busses stop for different lines. A {@code BusStop} pertains to only one such location. The bus stop
30   * in reality is represented by a shared name over a few {@code BusStop}'s, with different lines. As lines may also be set
31   * dynamically, the name and lines are insufficient to identify a specific {@code BusStop}. Hence there is a fixed unique id per
32   * {@code BusStop}.
33   * <p>
34   * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
35   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
36   * <p>
37   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 24 jan. 2017 <br>
38   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
39   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
40   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
41   */
42  public class BusStop extends AbstractLaneBasedObject
43  {
44  
45      /** */
46      private static final long serialVersionUID = 20170124L;
47  
48      /** Line numbers. */
49      private final Set<String> lines = new HashSet<>();
50  
51      /** Stop name. */
52      private final String name;
53  
54      /** Stored conflicts downstream. */
55      private Set<Conflict> conflicts = null;
56  
57      /**
58       * @param id id
59       * @param lane lane
60       * @param longitudinalPosition position
61       * @param name name of stop
62       * @param simulator the simulator to schedule on
63       * @throws NetworkException when the position on the lane is out of bounds
64       */
65      public BusStop(final String id, final Lane lane, final Length longitudinalPosition, final String name,
66              final OTSSimulatorInterface simulator) throws NetworkException
67      {
68          super(id, lane, LongitudinalDirectionality.DIR_PLUS, longitudinalPosition,
69                  LaneBasedObject.makeGeometry(lane, longitudinalPosition), Length.ZERO);
70          this.name = name;
71  
72          try
73          {
74              new BusStopAnimation(this, simulator);
75          }
76          catch (RemoteException | NamingException exception)
77          {
78              throw new NetworkException(exception);
79          }
80      }
81  
82      /**
83       * Sets the lines.
84       * @param lines lines that stop at this location
85       */
86      public final void setLines(final Set<String> lines)
87      {
88          this.lines.clear();
89          this.lines.addAll(lines);
90      }
91  
92      /**
93       * Returns the lines set.
94       * @return whether the lines belongs to this stop
95       */
96      public final ImmutableSet<String> getLines()
97      {
98          return new ImmutableHashSet<>(this.lines, Immutable.COPY);
99      }
100 
101     /**
102      * Returns the downstream conflicts of the bus stop. Search is only performed over links with BUS_STOP priority.
103      * @return downstream conflicts of the given conflict
104      */
105     public final Set<Conflict> getConflicts()
106     {
107         if (this.conflicts == null)
108         {
109             this.conflicts = new HashSet<>();
110             Lane lane = getLane();
111             // conflict forces only plus or minus as direction
112             GTUDirectionality dir = getDirection().isForward() ? GTUDirectionality.DIR_PLUS : GTUDirectionality.DIR_MINUS;
113             Length position = getLongitudinalPosition();
114             while (lane != null)
115             {
116                 List<LaneBasedObject> objects = lane.getObjectAhead(position, dir);
117                 while (objects != null)
118                 {
119                     for (LaneBasedObject object : objects)
120                     {
121                         if (object instanceof Conflict)
122                         {
123                             Conflict conflict = (Conflict) object;
124                             if (conflict.getConflictRule() instanceof BusStopConflictRule)
125                             {
126                                 this.conflicts.add(conflict);
127                             }
128                         }
129                     }
130                     objects = lane.getObjectAhead(objects.get(0).getLongitudinalPosition(), dir);
131                 }
132                 Map<Lane, GTUDirectionality> downstreamLanes = lane.downstreamLanes(dir, RoadGTUTypes.BUS);
133                 int numLanes = 0;
134                 for (Lane nextLane : downstreamLanes.keySet())
135                 {
136                     if (nextLane.getParentLink().getPriority().isBusStop())
137                     {
138                         numLanes++;
139                         lane = nextLane;
140                         dir = downstreamLanes.get(lane);
141                         position = dir.isPlus() ? Length.ZERO : lane.getLength();
142                     }
143                 }
144                 if (numLanes != 1)
145                 {
146                     lane = null;
147                 }
148             }
149         }
150         return this.conflicts;
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public final int hashCode()
156     {
157         final int prime = 31;
158         int result = 1;
159         result = prime * result + this.getId().hashCode();
160         return result;
161     }
162 
163     /** {@inheritDoc} */
164     @Override
165     public final boolean equals(final Object obj)
166     {
167         if (this == obj)
168         {
169             return true;
170         }
171         if (obj == null)
172         {
173             return false;
174         }
175         if (getClass() != obj.getClass())
176         {
177             return false;
178         }
179         BusStop other = (BusStop) obj;
180         if (!this.getId().equals(other.getId()))
181         {
182             return false;
183         }
184         return true;
185     }
186 
187     /** {@inheritDoc} */
188     @Override
189     public final String toString()
190     {
191         String out = "BusStop [id=" + getId() + ", lines=";
192         String delim = "";
193         for (String line : this.lines)
194         {
195             out = out + delim + line;
196             delim = "/";
197         }
198         return out + "]";
199     }
200 
201     /** {@inheritDoc} */
202     @Override
203     public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE, final OTSSimulatorInterface newSimulator,
204             final boolean animation) throws NetworkException
205     {
206         BusStop busStop = new BusStop(getId(), (Lane) newCSE, getLongitudinalPosition(), this.name, newSimulator);
207         busStop.setLines(this.lines);
208         return busStop;
209     }
210 
211 }