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