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