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-2019 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          this.trajectories.add(trajectory);
84      }
85  
86      /**
87       * @return startTime.
88       */
89      public final Time getStartTime()
90      {
91          return this.startTime;
92      }
93  
94      /**
95       * @return length.
96       */
97      public final Length getLength()
98      {
99          return this.endPosition.minus(this.startPosition);
100     }
101 
102     /**
103      * Whether this {@code TrajectoryGroup} holds the given trajectory. Note that this is false if the given trajectory is
104      * derived from a trajectory in this {@code TrajectoryGroup}.
105      * @param trajectory Trajectory&lt;?&gt;; trajectory
106      * @return whether this {@code TrajectoryGroup} holds the given trajectory.
107      */
108     public final boolean contains(final Trajectory<?> trajectory)
109     {
110         return this.trajectories.contains(trajectory);
111     }
112 
113     /**
114      * Returns the number of trajectories in this group.
115      * @return number of trajectories in this group
116      */
117     public final int size()
118     {
119         return this.trajectories.size();
120     }
121 
122     /**
123      * Returns a list of trajectories.
124      * @return list of trajectories
125      */
126     public final List<Trajectory<G>> getTrajectories()
127     {
128         return new ArrayList<>(this.trajectories);
129     }
130 
131     /**
132      * Returns trajectory group between two locations.
133      * @param x0 Length; start length
134      * @param x1 Length; end length
135      * @return list of trajectories
136      */
137     public final synchronized TrajectoryGroup<G> getTrajectoryGroup(final Length x0, final Length x1)
138     {
139         Length minLenght = Length.max(x0, this.startPosition);
140         Length maxLenght = Length.min(x1, this.endPosition);
141         TrajectoryGroup<G> out = new TrajectoryGroup<>(this.startTime, minLenght, maxLenght, this.laneDirection);
142         for (Trajectory<G> trajectory : this.trajectories)
143         {
144             out.addTrajectory(trajectory.subSet(x0, x1));
145         }
146         return out;
147     }
148 
149     /**
150      * Returns trajectory group between two times.
151      * @param t0 Time; start time
152      * @param t1 Time; end time
153      * @return list of trajectories
154      */
155     public final synchronized TrajectoryGroup<G> getTrajectoryGroup(final Time t0, final Time t1)
156     {
157         TrajectoryGroup<G> out = new TrajectoryGroup<>(this.startTime.lt(t0) ? t0 : this.startTime, this.laneDirection);
158         for (Trajectory<G> trajectory : this.trajectories)
159         {
160             out.addTrajectory(trajectory.subSet(t0, t1));
161         }
162         return out;
163     }
164 
165     /**
166      * Returns trajectory group between two locations and between two times.
167      * @param x0 Length; start length
168      * @param x1 Length; end length
169      * @param t0 Time; start time
170      * @param t1 Time; end time
171      * @return list of trajectories
172      */
173     public final synchronized TrajectoryGroup<G> getTrajectoryGroup(final Length x0, final Length x1, final Time t0,
174             final Time t1)
175     {
176         TrajectoryGroup<G> out = new TrajectoryGroup<>(this.startTime.lt(t0) ? t0 : this.startTime, this.laneDirection);
177         for (Trajectory<G> trajectory : this.trajectories)
178         {
179             out.addTrajectory(trajectory.subSet(x0, x1, t0, t1));
180         }
181         return out;
182     }
183 
184     /**
185      * Returns the lane direction.
186      * @return lane direction
187      */
188     public final KpiLaneDirection getLaneDirection()
189     {
190         return this.laneDirection;
191     }
192 
193     /** {@inheritDoc} */
194     @Override
195     public final int hashCode()
196     {
197         final int prime = 31;
198         int result = 1;
199         result = prime * result + ((this.laneDirection == null) ? 0 : this.laneDirection.hashCode());
200         result = prime * result + ((this.endPosition == null) ? 0 : this.endPosition.hashCode());
201         result = prime * result + ((this.startPosition == null) ? 0 : this.startPosition.hashCode());
202         result = prime * result + ((this.startTime == null) ? 0 : this.startTime.hashCode());
203         result = prime * result + ((this.trajectories == null) ? 0 : this.trajectories.hashCode());
204         return result;
205     }
206 
207     /** {@inheritDoc} */
208     @Override
209     public final boolean equals(final Object obj)
210     {
211         if (this == obj)
212         {
213             return true;
214         }
215         if (obj == null)
216         {
217             return false;
218         }
219         if (getClass() != obj.getClass())
220         {
221             return false;
222         }
223         TrajectoryGroup<?> other = (TrajectoryGroup<?>) obj;
224         if (this.laneDirection == null)
225         {
226             if (other.laneDirection != null)
227             {
228                 return false;
229             }
230         }
231         else if (!this.laneDirection.equals(other.laneDirection))
232         {
233             return false;
234         }
235         if (this.endPosition == null)
236         {
237             if (other.endPosition != null)
238             {
239                 return false;
240             }
241         }
242         else if (!this.endPosition.equals(other.endPosition))
243         {
244             return false;
245         }
246         if (this.startPosition == null)
247         {
248             if (other.startPosition != null)
249             {
250                 return false;
251             }
252         }
253         else if (!this.startPosition.equals(other.startPosition))
254         {
255             return false;
256         }
257         if (this.startTime == null)
258         {
259             if (other.startTime != null)
260             {
261                 return false;
262             }
263         }
264         else if (!this.startTime.equals(other.startTime))
265         {
266             return false;
267         }
268         if (this.trajectories == null)
269         {
270             if (other.trajectories != null)
271             {
272                 return false;
273             }
274         }
275         else if (!this.trajectories.equals(other.trajectories))
276         {
277             return false;
278         }
279         return true;
280     }
281 
282     /** {@inheritDoc} */
283     @Override
284     public final String toString()
285     {
286         return "TrajectoryGroup [startTime=" + this.startTime + ", minLength=" + this.startPosition + ", maxLength="
287                 + this.endPosition + ", laneDirection=" + this.laneDirection + "]";
288     }
289 
290     /** {@inheritDoc} */
291     @Override
292     public Iterator<Trajectory<G>> iterator()
293     {
294         return this.trajectories.iterator();
295     }
296 
297 }