View Javadoc
1   package org.opentrafficsim.kpi.sampling;
2   
3   import java.util.ArrayList;
4   import java.util.Iterator;
5   import java.util.List;
6   
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.djunits.value.vdouble.scalar.Time;
9   import org.djutils.exceptions.Throw;
10  import org.opentrafficsim.kpi.interfaces.GtuData;
11  import org.opentrafficsim.kpi.interfaces.LaneData;
12  
13  /**
14   * Contains all trajectories pertaining to a certain space-time region.
15   * <p>
16   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
17   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
18   * </p>
19   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
20   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
21   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
22   * @param <G> gtu data type
23   */
24  public class TrajectoryGroup<G extends GtuData> implements Iterable<Trajectory<G>>
25  {
26  
27      /** Start time of trajectories. */
28      private final Time startTime;
29  
30      /** Start position of the section. */
31      private final Length startPosition;
32  
33      /** End position of the section. */
34      private final Length endPosition;
35  
36      /** Direction for which the trajectories have been sampled. */
37      private final LaneData<?> lane;
38  
39      /** Trajectories. */
40      private final List<Trajectory<G>> trajectories = new ArrayList<>();
41  
42      /**
43       * Constructor without length specification. The complete lane will be used.
44       * @param startTime Time; start time of trajectories
45       * @param lane LaneData&lt;?&gt;; lane
46       */
47      public TrajectoryGroup(final Time startTime, final LaneData<?> lane)
48      {
49          this(startTime, Length.ZERO, lane == null ? null : lane.getLength(), lane);
50      }
51  
52      /**
53       * @param startTime Time; start time of trajectory group
54       * @param startPosition Length; start position
55       * @param endPosition Length; end position
56       * @param lane LaneData&lt;?&gt;; the lane
57       */
58      public TrajectoryGroup(final Time startTime, final Length startPosition, final Length endPosition,
59              final LaneData<?> lane)
60      {
61          Throw.whenNull(startTime, "Start time may not be null.");
62          // keep before position check; prevents "End position may not be null" due to missing direction in other constructor
63          Throw.whenNull(lane, "Lane direction time may not be null.");
64          Throw.whenNull(startPosition, "Start position may not be null");
65          Throw.whenNull(endPosition, "End position may not be null");
66          Throw.when(startPosition.gt(endPosition), IllegalArgumentException.class,
67                  "Start position should be smaller than end position in the direction of travel");
68          this.startTime = startTime;
69          this.startPosition = startPosition;
70          this.endPosition = endPosition;
71          this.lane = lane;
72      }
73  
74      /**
75       * Add trajectory.
76       * @param trajectory Trajectory&lt;G&gt;; trajectory to add
77       */
78      public final synchronized void addTrajectory(final Trajectory<G> trajectory)
79      {
80          // System.out.println("Adding trajectory " + trajectory + " to " + this.toString());
81          this.trajectories.add(trajectory);
82      }
83  
84      /**
85       * @return startTime.
86       */
87      public final Time getStartTime()
88      {
89          return this.startTime;
90      }
91  
92      /**
93       * @return length.
94       */
95      public final Length getLength()
96      {
97          return this.endPosition.minus(this.startPosition);
98      }
99  
100     /**
101      * Whether this {@code TrajectoryGroup} holds the given trajectory. Note that this is false if the given trajectory is
102      * derived from a trajectory in this {@code TrajectoryGroup}.
103      * @param trajectory Trajectory&lt;?&gt;; trajectory
104      * @return whether this {@code TrajectoryGroup} holds the given trajectory.
105      */
106     public final boolean contains(final Trajectory<?> trajectory)
107     {
108         return this.trajectories.contains(trajectory);
109     }
110 
111     /**
112      * Returns the number of trajectories in this group.
113      * @return number of trajectories in this group
114      */
115     public final int size()
116     {
117         return this.trajectories.size();
118     }
119 
120     /**
121      * Returns a list of trajectories.
122      * @return list of trajectories
123      */
124     public final List<Trajectory<G>> getTrajectories()
125     {
126         return new ArrayList<>(this.trajectories);
127     }
128 
129     /**
130      * Returns trajectory group between two locations.
131      * @param x0 Length; start length
132      * @param x1 Length; end length
133      * @return list of trajectories
134      */
135     public final synchronized TrajectoryGroup<G> getTrajectoryGroup(final Length x0, final Length x1)
136     {
137         Length minLenght = Length.max(x0, this.startPosition);
138         Length maxLenght = Length.min(x1, this.endPosition);
139         TrajectoryGroup<G> out = new TrajectoryGroup<>(this.startTime, minLenght, maxLenght, this.lane);
140         for (Trajectory<G> trajectory : this.trajectories)
141         {
142             out.addTrajectory(trajectory.subSet(x0, x1));
143         }
144         return out;
145     }
146 
147     /**
148      * Returns trajectory group between two times.
149      * @param t0 Time; start time
150      * @param t1 Time; end time
151      * @return list of trajectories
152      */
153     public final synchronized TrajectoryGroup<G> getTrajectoryGroup(final Time t0, final Time t1)
154     {
155         TrajectoryGroup<G> out = new TrajectoryGroup<>(this.startTime.lt(t0) ? t0 : this.startTime, this.lane);
156         for (Trajectory<G> trajectory : this.trajectories)
157         {
158             out.addTrajectory(trajectory.subSet(t0, t1));
159         }
160         return out;
161     }
162 
163     /**
164      * Returns trajectory group between two locations and between two times.
165      * @param x0 Length; start length
166      * @param x1 Length; end length
167      * @param t0 Time; start time
168      * @param t1 Time; end time
169      * @return list of trajectories
170      */
171     public final synchronized TrajectoryGroup<G> getTrajectoryGroup(final Length x0, final Length x1, final Time t0,
172             final Time t1)
173     {
174         TrajectoryGroup<G> out = new TrajectoryGroup<>(this.startTime.lt(t0) ? t0 : this.startTime, this.lane);
175         for (Trajectory<G> trajectory : this.trajectories)
176         {
177             out.addTrajectory(trajectory.subSet(x0, x1, t0, t1));
178         }
179         return out;
180     }
181 
182     /**
183      * Returns the lane.
184      * @return lane
185      */
186     public final LaneData<?> getLane()
187     {
188         return this.lane;
189     }
190 
191     /** {@inheritDoc} */
192     @Override
193     public final int hashCode()
194     {
195         final int prime = 31;
196         int result = 1;
197         result = prime * result + ((this.lane == null) ? 0 : this.lane.hashCode());
198         result = prime * result + ((this.endPosition == null) ? 0 : this.endPosition.hashCode());
199         result = prime * result + ((this.startPosition == null) ? 0 : this.startPosition.hashCode());
200         result = prime * result + ((this.startTime == null) ? 0 : this.startTime.hashCode());
201         result = prime * result + ((this.trajectories == null) ? 0 : this.trajectories.hashCode());
202         return result;
203     }
204 
205     /** {@inheritDoc} */
206     @Override
207     public final boolean equals(final Object obj)
208     {
209         if (this == obj)
210         {
211             return true;
212         }
213         if (obj == null)
214         {
215             return false;
216         }
217         if (getClass() != obj.getClass())
218         {
219             return false;
220         }
221         TrajectoryGroup<?> other = (TrajectoryGroup<?>) obj;
222         if (this.lane == null)
223         {
224             if (other.lane != null)
225             {
226                 return false;
227             }
228         }
229         else if (!this.lane.equals(other.lane))
230         {
231             return false;
232         }
233         if (this.endPosition == null)
234         {
235             if (other.endPosition != null)
236             {
237                 return false;
238             }
239         }
240         else if (!this.endPosition.equals(other.endPosition))
241         {
242             return false;
243         }
244         if (this.startPosition == null)
245         {
246             if (other.startPosition != null)
247             {
248                 return false;
249             }
250         }
251         else if (!this.startPosition.equals(other.startPosition))
252         {
253             return false;
254         }
255         if (this.startTime == null)
256         {
257             if (other.startTime != null)
258             {
259                 return false;
260             }
261         }
262         else if (!this.startTime.equals(other.startTime))
263         {
264             return false;
265         }
266         if (this.trajectories == null)
267         {
268             if (other.trajectories != null)
269             {
270                 return false;
271             }
272         }
273         else if (!this.trajectories.equals(other.trajectories))
274         {
275             return false;
276         }
277         return true;
278     }
279 
280     /** {@inheritDoc} */
281     @Override
282     public final String toString()
283     {
284         return "TrajectoryGroup [startTime=" + this.startTime + ", minLength=" + this.startPosition + ", maxLength="
285                 + this.endPosition + ", laneDirection=" + this.lane + ", collected "
286                 + (this.trajectories == null ? "null" : this.trajectories.size()) + " trajectories]";
287     }
288 
289     /** {@inheritDoc} */
290     @Override
291     public Iterator<Trajectory<G>> iterator()
292     {
293         return this.trajectories.iterator();
294     }
295 
296 }