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  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  public class TrajectoryGroup<G extends GtuDataInterface> implements Iterable<Trajectory<G>>
26  {
27  
28      
29      private final Time startTime;
30  
31      
32      private final Length startPosition;
33  
34      
35      private final Length endPosition;
36  
37      
38      private final KpiLaneDirection laneDirection;
39  
40      
41      private final List<Trajectory<G>> trajectories = new ArrayList<>();
42  
43      
44  
45  
46  
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  
55  
56  
57  
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          
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  
79  
80  
81      public final synchronized void addTrajectory(final Trajectory<G> trajectory)
82      {
83          this.trajectories.add(trajectory);
84      }
85  
86      
87  
88  
89      public final Time getStartTime()
90      {
91          return this.startTime;
92      }
93  
94      
95  
96  
97      public final Length getLength()
98      {
99          return this.endPosition.minus(this.startPosition);
100     }
101 
102     
103 
104 
105 
106 
107 
108     public final boolean contains(final Trajectory<?> trajectory)
109     {
110         return this.trajectories.contains(trajectory);
111     }
112 
113     
114 
115 
116 
117     public final int size()
118     {
119         return this.trajectories.size();
120     }
121 
122     
123 
124 
125 
126     public final List<Trajectory<G>> getTrajectories()
127     {
128         return new ArrayList<>(this.trajectories);
129     }
130 
131     
132 
133 
134 
135 
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 
151 
152 
153 
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 
167 
168 
169 
170 
171 
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 
186 
187 
188     public final KpiLaneDirection getLaneDirection()
189     {
190         return this.laneDirection;
191     }
192 
193     
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     
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     
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     
291     @Override
292     public Iterator<Trajectory<G>> iterator()
293     {
294         return this.trajectories.iterator();
295     }
296 
297 }