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