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