1 package org.opentrafficsim.kpi.sampling;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Map.Entry;
10 import java.util.Set;
11 import java.util.UUID;
12
13 import org.djunits.unit.LengthUnit;
14 import org.djunits.value.vdouble.scalar.Duration;
15 import org.djunits.value.vdouble.scalar.Frequency;
16 import org.djunits.value.vdouble.scalar.Length;
17 import org.djunits.value.vdouble.scalar.Time;
18 import org.opentrafficsim.kpi.interfaces.LaneDataInterface;
19 import org.opentrafficsim.kpi.interfaces.LinkDataInterface;
20 import org.opentrafficsim.kpi.sampling.meta.MetaDataSet;
21 import org.opentrafficsim.kpi.sampling.meta.MetaDataType;
22
23 import nl.tudelft.simulation.immutablecollections.ImmutableIterator;
24 import nl.tudelft.simulation.language.Throw;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public final class Query
40 {
41
42 private final String id;
43
44
45 private final Sampler sampler;
46
47
48 private final String description;
49
50
51 private final MetaDataSet metaDataSet;
52
53
54 private final Frequency updateFrequency;
55
56
57 private final Duration interval;
58
59
60 private final List<SpaceTimeRegion> spaceTimeRegions = new ArrayList<>();
61
62
63
64
65
66
67
68
69 public Query(final Sampler sampler, final String id, final String description, final MetaDataSet metaDataSet)
70 {
71 this(sampler, description, metaDataSet, null, null);
72 }
73
74
75
76
77
78
79
80
81
82 public Query(final Sampler sampler, final String id, final String description, final MetaDataSet metaDataSet, final Duration interval)
83 {
84 this(sampler, id, description, metaDataSet, null, interval);
85 }
86
87
88
89
90
91
92
93
94
95 public Query(final Sampler sampler, final String id, final String description, final MetaDataSet metaDataSet,
96 final Frequency updateFrequency)
97 {
98 this(sampler, id, description, metaDataSet, updateFrequency, null);
99 }
100
101
102
103
104
105
106
107
108
109
110 public Query(final Sampler sampler, final String id, final String description, final MetaDataSet metaDataSet,
111 final Frequency updateFrequency, final Duration interval)
112 {
113 Throw.whenNull(sampler, "Sampling may not be null.");
114 Throw.whenNull(description, "Description may not be null.");
115 Throw.whenNull(metaDataSet, "Meta data may not be null.");
116 this.sampler = sampler;
117 this.metaDataSet = new MetaDataSet(metaDataSet);
118 this.id = id == null ? UUID.randomUUID().toString() : id;
119 this.description = description;
120 this.updateFrequency = updateFrequency;
121 this.interval = interval;
122 sampler.registerMetaDataTypes(metaDataSet.getMetaDataTypes());
123 }
124
125
126
127
128
129
130
131 public Query(final Sampler sampler, final String description, final MetaDataSet metaDataSet)
132 {
133 this(sampler, null, description, metaDataSet, null, null);
134 }
135
136
137
138
139
140
141
142
143 public Query(final Sampler sampler, final String description, final MetaDataSet metaDataSet, final Duration interval)
144 {
145 this(sampler, null, description, metaDataSet, null, interval);
146 }
147
148
149
150
151
152
153
154
155 public Query(final Sampler sampler, final String description, final MetaDataSet metaDataSet,
156 final Frequency updateFrequency)
157 {
158 this(sampler, null, description, metaDataSet, updateFrequency, null);
159 }
160
161
162
163
164
165
166
167
168
169 public Query(final Sampler sampler, final String description, final MetaDataSet metaDataSet,
170 final Frequency updateFrequency, final Duration interval)
171 {
172 this(sampler, null, description, metaDataSet, updateFrequency, interval);
173 }
174
175
176
177
178
179 public String getId()
180 {
181 return this.id.toString();
182 }
183
184
185
186
187 public String getDescription()
188 {
189 return this.description;
190 }
191
192
193
194
195 public Frequency getUpdateFrequency()
196 {
197 return this.updateFrequency;
198 }
199
200
201
202
203 public Duration getInterval()
204 {
205 return this.interval;
206 }
207
208
209
210
211 public int metaDataSize()
212 {
213 return this.metaDataSet.size();
214 }
215
216
217
218
219 public Iterator<Entry<MetaDataType<?>, Set<?>>> getMetaDataSetIterator()
220 {
221 return this.metaDataSet.getMetaDataSetIterator();
222 }
223
224
225
226
227
228
229
230
231
232
233 public void addSpaceTimeRegionLink(final LinkDataInterface link, final KpiGtuDirectionality direction,
234 final Length startPosition, final Length endPosition, final Time startTime, final Time endTime)
235 {
236 Throw.whenNull(link, "Link may not be null.");
237 Throw.whenNull(direction, "Direction may not be null.");
238 Throw.whenNull(startPosition, "Start position may not be null.");
239 Throw.whenNull(endPosition, "End position may not be null.");
240 Throw.whenNull(startTime, "Start time may not be null.");
241 Throw.whenNull(endTime, "End time may not be null.");
242 Throw.when(endPosition.lt(startPosition), IllegalArgumentException.class,
243 "End position should be greater than start position.");
244 Throw.when(endTime.lt(startTime), IllegalArgumentException.class, "End time should be greater than start time.");
245 for (LaneDataInterface lane : link.getLaneDatas())
246 {
247 Length x0 = new Length(lane.getLength().si * startPosition.si / link.getLength().si, LengthUnit.SI);
248 Length x1 = new Length(lane.getLength().si * endPosition.si / link.getLength().si, LengthUnit.SI);
249 addSpaceTimeRegion(new KpiLaneDirection(lane, direction), x0, x1, startTime, endTime);
250 }
251 }
252
253
254
255
256
257
258
259
260
261 public void addSpaceTimeRegion(final KpiLaneDirection laneDirection, final Length startPosition, final Length endPosition,
262 final Time startTime, final Time endTime)
263 {
264 Throw.whenNull(laneDirection, "Lane direction may not be null.");
265 Throw.whenNull(startPosition, "Start position may not be null.");
266 Throw.whenNull(endPosition, "End position may not be null.");
267 Throw.whenNull(startTime, "Start time may not be null.");
268 Throw.whenNull(endTime, "End time may not be null.");
269 Throw.when(endPosition.lt(startPosition), IllegalArgumentException.class,
270 "End position should be greater than start position.");
271 Throw.when(endTime.lt(startTime), IllegalArgumentException.class, "End time should be greater than start time.");
272 SpaceTimeRegion spaceTimeRegion = new SpaceTimeRegion(laneDirection, startPosition, endPosition, startTime, endTime);
273 this.sampler.registerSpaceTimeRegion(spaceTimeRegion);
274 this.spaceTimeRegions.add(spaceTimeRegion);
275 }
276
277
278
279
280 public int spaceTimeRegionSize()
281 {
282 return this.spaceTimeRegions.size();
283 }
284
285
286
287
288 public Iterator<SpaceTimeRegion> getSpaceTimeIterator()
289 {
290 return new ImmutableIterator<>(this.spaceTimeRegions.iterator());
291 }
292
293
294
295
296
297
298
299
300
301 public <T> List<TrajectoryGroup> getTrajectoryGroups(final Time endTime)
302 {
303 return getTrajectoryGroups(Time.ZERO, endTime);
304 }
305
306
307
308
309
310
311
312
313
314
315 @SuppressWarnings("unchecked")
316 public <T> List<TrajectoryGroup> getTrajectoryGroups(final Time startTime, final Time endTime)
317 {
318 Throw.whenNull(startTime, "Start t may not be null.");
319 Throw.whenNull(endTime, "End t may not be null.");
320
321 Map<String, TrajectoryAcceptList> trajectoryAcceptLists = new HashMap<>();
322 List<TrajectoryGroup> trajectoryGroupList = new ArrayList<>();
323 for (SpaceTimeRegion spaceTimeRegion : this.spaceTimeRegions)
324 {
325 Time start = startTime.gt(spaceTimeRegion.getStartTime()) ? startTime : spaceTimeRegion.getStartTime();
326 Time end = endTime.lt(spaceTimeRegion.getEndTime()) ? endTime : spaceTimeRegion.getEndTime();
327 TrajectoryGroup trajectoryGroup;
328 if (this.sampler.getTrajectoryGroup(spaceTimeRegion.getLaneDirection()) == null)
329 {
330 trajectoryGroup = new TrajectoryGroup(start, spaceTimeRegion.getLaneDirection());
331 }
332 else
333 {
334 trajectoryGroup = this.sampler.getTrajectoryGroup(spaceTimeRegion.getLaneDirection())
335 .getTrajectoryGroup(spaceTimeRegion.getStartPosition(), spaceTimeRegion.getEndPosition(), start, end);
336 }
337 for (Trajectory trajectory : trajectoryGroup.getTrajectories())
338 {
339 if (!trajectoryAcceptLists.containsKey(trajectory.getGtuId()))
340 {
341 trajectoryAcceptLists.put(trajectory.getGtuId(), new TrajectoryAcceptList());
342 }
343 trajectoryAcceptLists.get(trajectory.getGtuId()).addTrajectory(trajectory, trajectoryGroup);
344 }
345 trajectoryGroupList.add(trajectoryGroup);
346 }
347
348 Iterator<String> iterator = trajectoryAcceptLists.keySet().iterator();
349 while (iterator.hasNext())
350 {
351 String gtuId = iterator.next();
352 TrajectoryAcceptList trajectoryAcceptListCombined = trajectoryAcceptLists.get(gtuId);
353 trajectoryAcceptListCombined.acceptAll();
354 for (MetaDataType<?> metaDataType : this.metaDataSet.getMetaDataTypes())
355 {
356
357 TrajectoryAcceptList trajectoryAcceptList = trajectoryAcceptLists.get(gtuId);
358 TrajectoryAcceptList trajectoryAcceptListCopy = new TrajectoryAcceptList();
359 for (int i = 0; i < trajectoryAcceptList.size(); i++)
360 {
361 trajectoryAcceptListCopy.addTrajectory(trajectoryAcceptList.getTrajectory(i),
362 trajectoryAcceptList.getTrajectoryGroup(i));
363 }
364
365 ((MetaDataType<T>) metaDataType).accept(trajectoryAcceptListCopy,
366 (Set<T>) new HashSet<>(this.metaDataSet.get(metaDataType)));
367
368 for (int i = 0; i < trajectoryAcceptListCopy.size(); i++)
369 {
370 Trajectory trajectory = trajectoryAcceptListCopy.getTrajectory(i);
371 trajectoryAcceptListCombined.acceptTrajectory(trajectory,
372 trajectoryAcceptListCombined.isAccepted(trajectory)
373 && trajectoryAcceptListCopy.isAccepted(trajectory));
374 }
375 }
376 }
377
378 List<TrajectoryGroup> out = new ArrayList<>();
379 for (TrajectoryGroup full : trajectoryGroupList)
380 {
381 TrajectoryGroup filtered = new TrajectoryGroup(full.getStartTime(), full.getLaneDirection());
382 for (Trajectory trajectory : full.getTrajectories())
383 {
384 String gtuId = trajectory.getGtuId();
385 if (trajectoryAcceptLists.get(gtuId).isAccepted(trajectory))
386 {
387 filtered.addTrajectory(trajectory);
388 }
389 }
390 out.add(filtered);
391 }
392 return out;
393 }
394
395
396
397
398 public Sampler getSampler()
399 {
400 return this.sampler;
401 }
402
403
404 @Override
405 public int hashCode()
406 {
407 final int prime = 31;
408 int result = 1;
409 result = prime * result + ((this.description == null) ? 0 : this.description.hashCode());
410 result = prime * result + ((this.interval == null) ? 0 : this.interval.hashCode());
411 result = prime * result + ((this.metaDataSet == null) ? 0 : this.metaDataSet.hashCode());
412 result = prime * result + ((this.sampler == null) ? 0 : this.sampler.hashCode());
413 result = prime * result + ((this.spaceTimeRegions == null) ? 0 : this.spaceTimeRegions.hashCode());
414 result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
415 result = prime * result + ((this.updateFrequency == null) ? 0 : this.updateFrequency.hashCode());
416 return result;
417 }
418
419
420 @Override
421 public boolean equals(final Object obj)
422 {
423 if (this == obj)
424 {
425 return true;
426 }
427 if (obj == null)
428 {
429 return false;
430 }
431 if (getClass() != obj.getClass())
432 {
433 return false;
434 }
435 Query other = (Query) obj;
436 if (this.description == null)
437 {
438 if (other.description != null)
439 {
440 return false;
441 }
442 }
443 else if (!this.description.equals(other.description))
444 {
445 return false;
446 }
447 if (this.interval == null)
448 {
449 if (other.interval != null)
450 {
451 return false;
452 }
453 }
454 else if (!this.interval.equals(other.interval))
455 {
456 return false;
457 }
458 if (this.metaDataSet == null)
459 {
460 if (other.metaDataSet != null)
461 {
462 return false;
463 }
464 }
465 else if (!this.metaDataSet.equals(other.metaDataSet))
466 {
467 return false;
468 }
469 if (this.sampler == null)
470 {
471 if (other.sampler != null)
472 {
473 return false;
474 }
475 }
476 else if (!this.sampler.equals(other.sampler))
477 {
478 return false;
479 }
480 if (this.spaceTimeRegions == null)
481 {
482 if (other.spaceTimeRegions != null)
483 {
484 return false;
485 }
486 }
487 else if (!this.spaceTimeRegions.equals(other.spaceTimeRegions))
488 {
489 return false;
490 }
491 if (this.id == null)
492 {
493 if (other.id != null)
494 {
495 return false;
496 }
497 }
498 else if (!this.id.equals(other.id))
499 {
500 return false;
501 }
502 if (this.updateFrequency == null)
503 {
504 if (other.updateFrequency != null)
505 {
506 return false;
507 }
508 }
509 else if (!this.updateFrequency.equals(other.updateFrequency))
510 {
511 return false;
512 }
513 return true;
514 }
515
516
517 @Override
518 public String toString()
519 {
520 return "Query (" + this.description + ")";
521 }
522
523 }