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      /** Line numbers. */
35      private final Set<String> lines = new LinkedHashSet<>();
36  
37      /** Stop name. */
38      private final String name;
39  
40      /** Stored conflicts downstream. */
41      private Set<Conflict> conflicts = null;
42  
43      /** Bus type. */
44      private final GtuType busType;
45  
46      /**
47       * Constructor.
48       * @param id id
49       * @param lane lane
50       * @param longitudinalPosition position
51       * @param name name of stop
52       * @param busType bus type.
53       * @throws NetworkException when the position on the lane is out of bounds
54       */
55      public BusStop(final String id, final Lane lane, final Length longitudinalPosition, final String name,
56              final GtuType busType) throws NetworkException
57      {
58          super(id, lane, longitudinalPosition, LaneBasedObject.makeLine(lane, longitudinalPosition), Length.ZERO);
59          this.name = name;
60          this.busType = busType;
61          init();
62      }
63  
64      /**
65       * Sets the lines.
66       * @param lines lines that stop at this location
67       */
68      public final void setLines(final Set<String> lines)
69      {
70          this.lines.clear();
71          this.lines.addAll(lines);
72      }
73  
74      /**
75       * Returns the lines set.
76       * @return whether the lines belongs to this stop
77       */
78      public final ImmutableSet<String> getLines()
79      {
80          return new ImmutableHashSet<>(this.lines, Immutable.COPY);
81      }
82  
83      /**
84       * Returns the downstream conflicts of the bus stop. Search is only performed over links with BUS_STOP priority.
85       * @return downstream conflicts of the given conflict
86       */
87      public final Set<Conflict> getConflicts()
88      {
89          if (this.conflicts == null)
90          {
91              this.conflicts = new LinkedHashSet<>();
92              Lane lane = getLane();
93              // conflict forces only plus or minus as direction
94              Length position = getLongitudinalPosition();
95              while (lane != null)
96              {
97                  List<LaneBasedObject> objects = lane.getObjectAhead(position);
98                  while (!objects.isEmpty())
99                  {
100                     for (LaneBasedObject object : objects)
101                     {
102                         if (object instanceof Conflict)
103                         {
104                             Conflict conflict = (Conflict) object;
105                             if (conflict.getConflictRule() instanceof BusStopConflictRule)
106                             {
107                                 this.conflicts.add(conflict);
108                             }
109                         }
110                     }
111                     objects = lane.getObjectAhead(objects.get(0).getLongitudinalPosition());
112                 }
113                 //
114                 Set<Lane> downstreamLanes = lane.nextLanes(this.busType);
115                 int numLanes = 0;
116                 for (Lane nextLane : downstreamLanes)
117                 {
118                     if (nextLane.getLink().getPriority().isBusStop())
119                     {
120                         numLanes++;
121                         lane = nextLane;
122                         position = Length.ZERO;
123                     }
124                 }
125                 if (numLanes != 1)
126                 {
127                     lane = null;
128                 }
129             }
130         }
131         return this.conflicts;
132     }
133 
134     @Override
135     public final int hashCode()
136     {
137         final int prime = 31;
138         int result = 1;
139         result = prime * result + this.getId().hashCode();
140         return result;
141     }
142 
143     @Override
144     public final boolean equals(final Object obj)
145     {
146         if (this == obj)
147         {
148             return true;
149         }
150         if (obj == null)
151         {
152             return false;
153         }
154         if (getClass() != obj.getClass())
155         {
156             return false;
157         }
158         BusStop other = (BusStop) obj;
159         if (!this.getId().equals(other.getId()))
160         {
161             return false;
162         }
163         return true;
164     }
165 
166     @Override
167     public final String toString()
168     {
169         String out = "BusStop [id=" + getId() + ", lines=";
170         String delim = "";
171         for (String line : this.lines)
172         {
173             out = out + delim + line;
174             delim = "/";
175         }
176         return out + "]";
177     }
178 
179 }