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