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