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.Duration;
8 import org.djunits.value.vdouble.scalar.Length;
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 Duration 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 Duration 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
59 public TrajectoryGroup(final Duration startTime, final Length startPosition, final Length endPosition,
60 final LaneData<?> lane)
61 {
62 Throw.whenNull(startTime, "Start time may not be null.");
63
64 Throw.whenNull(lane, "Lane 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 Throw.when(startPosition.gt(endPosition), IllegalArgumentException.class,
68 "Start position should be smaller than end position in the direction of travel");
69 this.startTime = startTime;
70 this.startPosition = startPosition;
71 this.endPosition = endPosition;
72 this.lane = lane;
73 }
74
75
76
77
78
79 public final synchronized void addTrajectory(final Trajectory<G> trajectory)
80 {
81 this.trajectories.add(trajectory);
82 }
83
84
85
86
87
88 public final Duration getStartTime()
89 {
90 return this.startTime;
91 }
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.lane);
142 for (Trajectory<G> trajectory : this.trajectories)
143 {
144 Trajectory<G> sub = trajectory.subSet(x0, x1);
145 if (sub.size() > 0)
146 {
147 out.addTrajectory(sub);
148 }
149 }
150 return out;
151 }
152
153
154
155
156
157
158
159 public final synchronized TrajectoryGroup<G> getTrajectoryGroup(final Duration t0, final Duration t1)
160 {
161 TrajectoryGroup<G> out = new TrajectoryGroup<>(this.startTime.lt(t0) ? t0 : this.startTime, this.lane);
162 for (Trajectory<G> trajectory : this.trajectories)
163 {
164 Trajectory<G> sub = trajectory.subSet(t0, t1);
165 if (sub.size() > 0)
166 {
167 out.addTrajectory(sub);
168 }
169 }
170 return out;
171 }
172
173
174
175
176
177
178
179
180
181 public final synchronized TrajectoryGroup<G> getTrajectoryGroup(final Length x0, final Length x1, final Duration t0,
182 final Duration t1)
183 {
184 TrajectoryGroup<G> out = new TrajectoryGroup<>(this.startTime.lt(t0) ? t0 : this.startTime, this.lane);
185 for (Trajectory<G> trajectory : this.trajectories)
186 {
187 out.addTrajectory(trajectory.subSet(x0, x1, t0, t1));
188 }
189 return out;
190 }
191
192
193
194
195
196 public final LaneData<?> getLane()
197 {
198 return this.lane;
199 }
200
201 @Override
202 public final int hashCode()
203 {
204 final int prime = 31;
205 int result = 1;
206 result = prime * result + this.lane.hashCode();
207 result = prime * result + this.endPosition.hashCode();
208 result = prime * result + this.startPosition.hashCode();
209 result = prime * result + this.startTime.hashCode();
210 result = prime * result + this.trajectories.hashCode();
211 return result;
212 }
213
214 @Override
215 public final boolean equals(final Object obj)
216 {
217 if (this == obj)
218 {
219 return true;
220 }
221 if (obj == null)
222 {
223 return false;
224 }
225 if (getClass() != obj.getClass())
226 {
227 return false;
228 }
229 TrajectoryGroup<?> other = (TrajectoryGroup<?>) obj;
230 if (!this.lane.equals(other.lane))
231 {
232 return false;
233 }
234 if (!this.endPosition.equals(other.endPosition))
235 {
236 return false;
237 }
238 if (!this.startPosition.equals(other.startPosition))
239 {
240 return false;
241 }
242 if (!this.startTime.equals(other.startTime))
243 {
244 return false;
245 }
246 if (!this.trajectories.equals(other.trajectories))
247 {
248 return false;
249 }
250 return true;
251 }
252
253 @Override
254 public final String toString()
255 {
256 return "TrajectoryGroup [startTime=" + this.startTime + ", minLength=" + this.startPosition + ", maxLength="
257 + this.endPosition + ", lane=" + this.lane + ", collected "
258 + (this.trajectories == null ? "null" : this.trajectories.size()) + " trajectories]";
259 }
260
261 @Override
262 public Iterator<Trajectory<G>> iterator()
263 {
264 return this.trajectories.iterator();
265 }
266
267 }