View Javadoc
1   package org.opentrafficsim.kpi.sampling;
2   
3   import java.io.BufferedWriter;
4   import java.io.IOException;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   import java.util.Iterator;
8   import java.util.LinkedHashMap;
9   import java.util.LinkedHashSet;
10  import java.util.List;
11  import java.util.Map;
12  import java.util.Set;
13  import java.util.function.BiFunction;
14  import java.util.function.Function;
15  
16  import org.djunits.value.vdouble.scalar.Length;
17  import org.djunits.value.vdouble.scalar.Time;
18  import org.opentrafficsim.base.CompressedFileWriter;
19  import org.opentrafficsim.kpi.interfaces.GtuDataInterface;
20  import org.opentrafficsim.kpi.interfaces.GtuTypeDataInterface;
21  import org.opentrafficsim.kpi.interfaces.LaneDataInterface;
22  import org.opentrafficsim.kpi.interfaces.LinkDataInterface;
23  import org.opentrafficsim.kpi.interfaces.NodeDataInterface;
24  import org.opentrafficsim.kpi.interfaces.RouteDataInterface;
25  import org.opentrafficsim.kpi.sampling.ListTable.ListRecord;
26  import org.opentrafficsim.kpi.sampling.data.ExtendedDataType;
27  import org.opentrafficsim.kpi.sampling.meta.FilterDataType;
28  
29  /**
30   * SamplerData is a storage for trajectory data. Adding trajectory groups can only be done by subclasses. This is however not a
31   * guaranteed read-only class. Any type can obtain the lane directions and with those the coupled trajectory groups.
32   * Trajectories can be added to these trajectory groups. Data can also be added to the trajectories themselves.
33   * <p>
34   * Copyright (c) 2020-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
35   * BSD-style license. See <a href="https://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
36   * </p>
37   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
38   * @author <a href="https://www.tudelft.nl/pknoppers">Peter Knoppers</a>
39   * @author <a href="https://www.transport.citg.tudelft.nl">Wouter Schakel</a>
40   * @param <G> gtu data type
41   */
42  // TODO: extending list table requires us to know the columns beforehand, create a view asTable()?
43  public class SamplerData<G extends GtuDataInterface> extends AbstractTable
44  {
45  
46      /**
47       * Constructor.
48       * @param columns Collection&lt;Column&lt;?&gt;&gt;; columns
49       */
50      public SamplerData(final Collection<Column<?>> columns)
51      {
52          super("sampler", "Trajectory data", columns);
53      }
54  
55      /** Map with all sampling data. */
56      private final Map<KpiLaneDirection, TrajectoryGroup<G>> trajectories = new LinkedHashMap<>();
57  
58      /**
59       * Stores a trajectory group with the lane direction.
60       * @param kpiLaneDirection KpiLaneDirection; lane direction
61       * @param trajectoryGroup trajectory group for given lane direction
62       */
63      protected final void putTrajectoryGroup(final KpiLaneDirection kpiLaneDirection, final TrajectoryGroup<G> trajectoryGroup)
64      {
65          this.trajectories.put(kpiLaneDirection, trajectoryGroup);
66      }
67  
68      /**
69       * Returns the set of lane directions.
70       * @return Set&lt;KpiLaneDirection&gt;; lane directions
71       */
72      public final Set<KpiLaneDirection> getLaneDirections()
73      {
74          return this.trajectories.keySet();
75      }
76  
77      /**
78       * Returns whether there is data for the give lane direction.
79       * @param kpiLaneDirection KpiLaneDirection; lane direction
80       * @return whether there is data for the give lane direction
81       */
82      public final boolean contains(final KpiLaneDirection kpiLaneDirection)
83      {
84          return this.trajectories.containsKey(kpiLaneDirection);
85      }
86  
87      /**
88       * Returns the trajectory group of given lane direction.
89       * @param kpiLaneDirection KpiLaneDirection; lane direction
90       * @return trajectory group of given lane direction, {@code null} if none
91       */
92      public final TrajectoryGroup<G> getTrajectoryGroup(final KpiLaneDirection kpiLaneDirection)
93      {
94          return this.trajectories.get(kpiLaneDirection);
95      }
96  
97      /**
98       * Write the contents of the sampler in to a file. By default this is zipped and numeric data is formated %.3f.
99       * @param file String; file
100      */
101     public final void writeToFile(final String file)
102     {
103         writeToFile(file, "%.3f", CompressionMethod.ZIP);
104     }
105 
106     /**
107      * Write the contents of the sampler in to a file.
108      * @param file String; file
109      * @param format String; number format, as used in {@code String.format()}
110      * @param compression CompressionMethod; how to compress the data
111      */
112     public final void writeToFile(final String file, final String format, final CompressionMethod compression)
113     {
114         int counter = 0;
115         BufferedWriter bw = CompressedFileWriter.create(file, compression.equals(CompressionMethod.ZIP));
116 
117         // TODO: Sampler used this to cut-off space if SpaceTimeRegion's did not cover complete lanes. Trajectories are however
118         // recorded over the complete length.
119 
120         /*
121          * // create Query, as this class is designed to filter for space-time regions Query<G> query = new Query<>(this, "",
122          * new MetaDataSet()); for (SpaceTimeRegion str : this.spaceTimeRegions) {
123          * query.addSpaceTimeRegion(str.getLaneDirection(), str.getStartPosition(), str.getEndPosition(), str.getStartTime(),
124          * str.getEndTime()); } List<TrajectoryGroup<G>> groups =
125          * query.getTrajectoryGroups(Time.instantiateSI(Double.POSITIVE_INFINITY));
126          */
127 
128         Collection<TrajectoryGroup<G>> groups = this.trajectories.values();
129         try
130         {
131             // gather all filter data types for the header line
132             List<FilterDataType<?>> allFilterDataTypes = new ArrayList<>();
133             for (TrajectoryGroup<G> group : groups)
134             {
135                 for (Trajectory<G> trajectory : group.getTrajectories())
136                 {
137                     for (FilterDataType<?> filterDataType : trajectory.getFilterDataTypes())
138                     {
139                         if (!allFilterDataTypes.contains(filterDataType))
140                         {
141                             allFilterDataTypes.add(filterDataType);
142                         }
143                     }
144                 }
145             }
146             // gather all extended data types for the header line
147             List<ExtendedDataType<?, ?, ?, ?>> allExtendedDataTypes = new ArrayList<>();
148             for (TrajectoryGroup<G> group : groups)
149             {
150                 for (Trajectory<?> trajectory : group.getTrajectories())
151                 {
152                     for (ExtendedDataType<?, ?, ?, ?> extendedDataType : trajectory.getExtendedDataTypes())
153                     {
154                         if (!allExtendedDataTypes.contains(extendedDataType))
155                         {
156                             allExtendedDataTypes.add(extendedDataType);
157                         }
158                     }
159                 }
160             }
161             // create header line
162             StringBuilder str = new StringBuilder();
163             str.append("traj#,linkId,laneId&dir,gtuId,t,x,v,a");
164             for (FilterDataType<?> metaDataType : allFilterDataTypes)
165             {
166                 str.append(",");
167                 str.append(metaDataType.getId());
168             }
169             for (ExtendedDataType<?, ?, ?, ?> extendedDataType : allExtendedDataTypes)
170             {
171                 str.append(",");
172                 str.append(extendedDataType.getId());
173             }
174             bw.write(str.toString());
175             bw.newLine();
176             for (TrajectoryGroup<G> group : groups)
177             {
178                 for (Trajectory<G> trajectory : group.getTrajectories())
179                 {
180                     counter++;
181                     float[] t = trajectory.getT();
182                     float[] x = trajectory.getX();
183                     float[] v = trajectory.getV();
184                     float[] a = trajectory.getA();
185                     Map<ExtendedDataType<?, ?, ?, ?>, Object> extendedData = new LinkedHashMap<>();
186                     for (ExtendedDataType<?, ?, ?, ?> extendedDataType : allExtendedDataTypes)
187                     {
188                         if (trajectory.contains(extendedDataType))
189                         {
190                             try
191                             {
192                                 extendedData.put(extendedDataType, trajectory.getExtendedData(extendedDataType));
193                             }
194                             catch (SamplingException exception)
195                             {
196                                 // should not occur, we obtain the extended data types from the trajectory
197                                 throw new RuntimeException("Error while loading extended data type.", exception);
198                             }
199                         }
200                     }
201                     for (int i = 0; i < t.length; i++)
202                     {
203                         // TODO: values can contain ","; use csv writer
204                         str = new StringBuilder();
205                         str.append(counter);
206                         str.append(",");
207                         if (!compression.equals(CompressionMethod.OMIT_DUPLICATE_INFO) || i == 0)
208                         {
209                             str.append(group.getLaneDirection().getLaneData().getLinkData().getId());
210                             str.append(",");
211                             str.append(group.getLaneDirection().getLaneData().getId());
212                             str.append(group.getLaneDirection().getKpiDirection().isPlus() ? "+" : "-");
213                             str.append(",");
214                             str.append(trajectory.getGtuId());
215                             str.append(",");
216                         }
217                         else
218                         {
219                             // one trajectory is on the same lane and pertains to the same GTU, no need to repeat data
220                             str.append(",,,");
221                         }
222                         str.append(String.format(format, t[i]));
223                         str.append(",");
224                         str.append(String.format(format, x[i]));
225                         str.append(",");
226                         str.append(String.format(format, v[i]));
227                         str.append(",");
228                         str.append(String.format(format, a[i]));
229                         for (FilterDataType<?> metaDataType : allFilterDataTypes)
230                         {
231                             str.append(",");
232                             if (i == 0 && trajectory.contains(metaDataType))
233                             {
234                                 // no need to repeat meta data
235                                 str.append(metaDataType.formatValue(format, castValue(trajectory.getMetaData(metaDataType))));
236                             }
237                         }
238                         for (ExtendedDataType<?, ?, ?, ?> extendedDataType : allExtendedDataTypes)
239                         {
240                             str.append(",");
241                             if (trajectory.contains(extendedDataType))
242                             {
243                                 try
244                                 {
245                                     str.append(extendedDataType.formatValue(format, castValue(extendedData, extendedDataType,
246                                         i)));
247                                 }
248                                 catch (SamplingException exception)
249                                 {
250                                     // should not occur, we obtain the extended data types from the trajectory
251                                     throw new RuntimeException("Error while loading extended data type.", exception);
252                                 }
253                             }
254                         }
255                         bw.write(str.toString());
256                         bw.newLine();
257                     }
258                 }
259             }
260         }
261         catch (IOException exception)
262         {
263             throw new RuntimeException("Could not write to file.", exception);
264         }
265         // close file on fail
266         finally
267         {
268             try
269             {
270                 if (bw != null)
271                 {
272                     bw.close();
273                 }
274             }
275             catch (IOException ex)
276             {
277                 ex.printStackTrace();
278             }
279         }
280     }
281 
282     /**
283      * Cast value to type for meta data.
284      * @param value Object; value object to cast
285      * @return cast value
286      * @param <T> type of value
287      */
288     @SuppressWarnings("unchecked")
289     private <T> T castValue(final Object value)
290     {
291         return (T) value;
292     }
293 
294     /**
295      * Cast value to type for extended data.
296      * @param extendedData Map&lt;ExtendedDataType&lt;?,?,?,?&gt;,Object&gt;; extended data of trajectory in output form
297      * @param extendedDataType ExtendedDataType&lt;?,?,?,?&gt;; extended data type
298      * @param i int; index of value to return
299      * @return cast value
300      * @throws SamplingException when the found index is out of bounds
301      * @param <T> type of value
302      * @param <O> output type
303      * @param <S> storage type
304      */
305     @SuppressWarnings("unchecked")
306     private <T, O, S> T castValue(final Map<ExtendedDataType<?, ?, ?, ?>, Object> extendedData, final ExtendedDataType<?, ?, ?,
307             ?> extendedDataType, final int i) throws SamplingException
308     {
309         // is only called on value directly taken from an ExtendedDataType within range of trajectory
310         ExtendedDataType<T, O, S, ?> edt = (ExtendedDataType<T, O, S, ?>) extendedDataType;
311         return edt.getOutputValue((O) extendedData.get(edt), i);
312     }
313 
314     /**
315      * Defines the compression method for stored data.
316      * <p>
317      * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
318      * <br>
319      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
320      * <p>
321      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 3 mei 2017 <br>
322      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
323      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
324      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
325      */
326     public enum CompressionMethod
327     {
328         /** No compression. */
329         NONE,
330 
331         /** Duplicate info per trajectory is only stored at the first sample, and empty for other samples. */
332         OMIT_DUPLICATE_INFO,
333 
334         /** Zip compression. */
335         ZIP,
336     }
337 
338     /**
339      * Loads sampler data from a file. There are a few limitations with respect to live sampled data:
340      * <ol>
341      * <li>The number of decimals in numeric data is equal to the stored format.</li>
342      * <li>All extended data types are stored as {@code String}.</li>
343      * <li>Meta data types are not recognized, and hence stored as extended data types. Values are always stored as
344      * {@code String}.</li>
345      * </ol>
346      * @param file String; file
347      * @return Sampler data from file
348      */
349     public static SamplerData<?> loadFromFile(final String file)
350     {
351         return loadFromFile(file, new LinkedHashSet<ExtendedDataType<?, ?, ?, ?>>(), new LinkedHashSet<FilterDataType<?>>());
352     }
353 
354     /**
355      * Loads sampler data from a file. There are a few limitations with respect to live sampled data:
356      * <ol>
357      * <li>The number of decimals in numeric data is equal to the stored format.</li>
358      * <li>All extended data types are stored as {@code String}, unless recognized by id as provided.</li>
359      * <li>Meta data types are not recognized, and hence stored as extended data types, unless recognized by id as provided.
360      * Values are always stored as {@code String}.</li>
361      * </ol>
362      * @param file String; file
363      * @param extendedDataTypes Set&lt;ExtendedDataType&lt;?, ?, ?, ?&gt;&gt;; extended data types
364      * @param metaDataTypes Set&lt;MetaDataType&lt;?&gt;&gt;; meta data types
365      * @return Sampler data from file
366      */
367     @SuppressWarnings("unchecked")
368     public static SamplerData<?> loadFromFile(final String file, final Set<ExtendedDataType<?, ?, ?, ?>> extendedDataTypes,
369             final Set<FilterDataType<?>> metaDataTypes)
370     {
371         /*
372         @SuppressWarnings("rawtypes")
373         SamplerData samplerData = new SamplerData();
374 
375         // "traj#,linkId,laneId&dir,gtuId,t,x,v,a" meta data types, extended data types
376 
377         // we can use the default meta data types: cross section, destination, origin, route and GTU type
378 
379         Getter<NodeData> nodes = new Getter<NodeData>((id) -> new NodeData(id));
380         Getter<GtuTypeData> gtuTypes = new Getter<GtuTypeData>((id) -> new GtuTypeData(id));
381         Getter<RouteData> routes = new Getter<RouteData>((id) -> new RouteData(id));
382         Getter<LinkData> links = new Getter<LinkData>((id) -> new LinkData(id));
383         BiGetter<LinkData, LaneData> lanes = new BiGetter<LinkData, LaneData>((id, link) -> new LaneData(id, link));
384         BiGetter<LaneData, KpiLaneDirection> laneDirections = new BiGetter<LaneData, KpiLaneDirection>((dir,
385                 lane) -> new KpiLaneDirection(lane, dir.equals("+") ? KpiGtuDirectionality.DIR_PLUS
386                         : KpiGtuDirectionality.DIR_MINUS));
387         @SuppressWarnings("rawtypes")
388         Function<KpiLaneDirection, TrajectoryGroup> groupFunction = (laneDir) -> new TrajectoryGroup(Time.ZERO, laneDir);
389 
390         String id = null;
391         if (!gtus.containsKey(id))
392         {
393             // NOTE: USE SEPARATE IDS HERE
394             gtus.put(id, new GtuData(id, nodeSupplier.apply(id), nodeSupplier.apply(id), gtuTypeSupplier.apply(id),
395                 routeSupplier.apply(id)));
396         }
397         GtuData gtuData = gtus.get(id);
398 
399         Trajectory<?> trajectory = new Trajectory(gtuData, metaData, extendedDataTypes, kpiLaneDirection);
400 
401         // TODO: set data from outside
402         trajectory.add(position, speed, acceleration, time, gtu);
403 
404         KpiLaneDirection laneDir = null;
405         ((TrajectoryGroup) samplerData.trajectories.computeIfAbsent(laneDir, groupFunction)).addTrajectory(trajectory);
406 
407         return samplerData;
408         */
409         return null;
410     }
411 
412     /**
413      * Returns a value from the map. Creates a value if needed.
414      * @param id String; id of object (key in map)
415      * @param map Map&lt;String, T&gt;; stored values
416      * @param producer Supplier&lt;TT&gt;; producer used if no value exists in the map
417      * @param <T> type
418      * @return value for the id
419      */
420     private final <T> T getOrCreate(final String id, final Map<String, T> map, final Function<String, T> producer)
421     {
422         if (!map.containsKey(id))
423         {
424             map.put(id, producer.apply(id));
425         }
426         return map.get(id);
427     }
428 
429     // TABLE METHODS
430 
431     /** {@inheritDoc} */
432     @Override
433     public Iterator<Record> iterator()
434     {
435         // TODO: local iterator over this.trajectories, trajectories per group, and length of each trajectory
436 
437         // TODO: gathering the extended and filter data types should be done here, these are within the trajectories, and upon
438         // file loading, this should be mimicked
439 
440         Iterator<KpiLaneDirection> laneIterator = this.trajectories.keySet().iterator();
441 
442         return new Iterator<Record>()
443         {
444             private Iterator<Trajectory<G>> trajectoryIterator = laneIterator.hasNext() ? SamplerData.this.trajectories.get(
445                 laneIterator.next()).iterator() : null;
446 
447             private Trajectory<G> trajectory = this.trajectoryIterator != null && this.trajectoryIterator.hasNext()
448                     ? this.trajectoryIterator.next() : null;
449 
450             private Trajectory<G> currentTrajectory;
451 
452             private int index;
453 
454             @Override
455             public boolean hasNext()
456             {
457                 if (this.index == this.currentTrajectory.size())
458                 {
459                     // get next trajectory
460 
461                 }
462                 return true;
463             }
464 
465             @Override
466             public Record next()
467             {
468                 Recording/Record.html#Record">Record record = new Record()
469                 {
470                     @Override
471                     public <T> T getValue(final Column<T> column)
472                     {
473                         return null;
474                     }
475 
476                     @Override
477                     public Object getValue(final String id)
478                     {
479                         return null;
480                     }
481                 };
482                 this.index++;
483                 return record;
484             }
485         };
486     }
487 
488     /** {@inheritDoc} */
489     @Override
490     public boolean isEmpty()
491     {
492         for (TrajectoryGroup<G> group : this.trajectories.values())
493         {
494             for (Trajectory<G> trajectory : group.getTrajectories())
495             {
496                 if (trajectory.size() > 0)
497                 {
498                     return false;
499                 }
500             }
501         }
502         return true;
503     }
504 
505     // LOCAL HELPER CLASSES TO IMPLEMENT INTERFACES //
506 
507     /**
508      * Getter for single {@code String} input.
509      * @param <T> output value type
510      */
511     private static class Getter<T>
512     {
513 
514         /** Map with cached values. */
515         private final Map<String, T> map = new LinkedHashMap<>();
516 
517         /** Provider function. */
518         private Function<String, T> function;
519 
520         /**
521          * Constructor.
522          * @param function Function&lt;String, T&gt;; provider function
523          */
524         Getter(final Function<String, T> function)
525         {
526             this.function = function;
527         }
528 
529         /**
530          * Get value, from cache or provider function.
531          * @param id String; id
532          * @return T; value, from cache or provider function
533          */
534         public T get(final String id)
535         {
536             T t;
537             if (!this.map.containsKey(id))
538             {
539                 t = this.function.apply(id);
540                 this.map.put(id, t);
541             }
542             else
543             {
544                 t = this.map.get(id);
545             }
546             return t;
547         }
548     }
549 
550     /**
551      * Getter for dual {@code String} and {@code O} input.
552      * @param <O> type of second input (besides the first being {@code String})
553      * @param <T> output value type
554      */
555     private static class BiGetter<O, T>
556     {
557 
558         /** Map with cached values. */
559         private final Map<String, T> map = new LinkedHashMap<>();
560 
561         /** Provider function. */
562         private BiFunction<String, O, T> function;
563 
564         /**
565          * Constructor.
566          * @param function BiFunction&lt;String, T&gt;; provider function
567          */
568         BiGetter(final BiFunction<String, O, T> function)
569         {
570             this.function = function;
571         }
572 
573         /**
574          * Get value, from cache or provider function.
575          * @param id String; id
576          * @param o O; other object
577          * @return T; value, from cache or provider function
578          */
579         public T get(final String id, final O o)
580         {
581             T t;
582             if (!this.map.containsKey(id))
583             {
584                 t = this.function.apply(id, o);
585                 this.map.put(id, t);
586             }
587             else
588             {
589                 t = this.map.get(id);
590             }
591             return t;
592         }
593     }
594 
595     /** Helper class LinkData. */
596     private static class LinkData implements LinkDataInterface
597     {
598 
599         /** Length ({@code null} always). */
600         private final Length length = null; // unknown in this context
601 
602         /** Id. */
603         private final String id;
604 
605         /** Lanes. */
606         private final List<LaneData> lanes = new ArrayList<>();
607 
608         /**
609          * @param id String; id
610          */
611         LinkData(final String id)
612         {
613             this.id = id;
614         }
615 
616         /** {@inheritDoc} */
617         @Override
618         public Length getLength()
619         {
620             return this.length;
621         }
622 
623         /** {@inheritDoc} */
624         @Override
625         public List<? extends LaneDataInterface> getLaneDatas()
626         {
627             return this.lanes;
628         }
629 
630         /** {@inheritDoc} */
631         @Override
632         public String getId()
633         {
634             return this.id;
635         }
636 
637     }
638 
639     /** Helper class LaneData. */
640     private static class LaneData implements LaneDataInterface
641     {
642 
643         /** Length ({@code null} always). */
644         private final Length length = null; // unknown in this context
645 
646         /** Id. */
647         private final String id;
648 
649         /** Link. */
650         private final LinkData link;
651 
652         /**
653          * Constructor.
654          * @param id String; id
655          * @param link LinkData; link
656          */
657         @SuppressWarnings("synthetic-access")
658         LaneData(final String id, final LinkData link)
659         {
660             this.id = id;
661             this.link = link;
662             link.lanes.add(this);
663         }
664 
665         /** {@inheritDoc} */
666         @Override
667         public Length getLength()
668         {
669             return this.length;
670         }
671 
672         /** {@inheritDoc} */
673         @Override
674         public LinkData getLinkData()
675         {
676             return this.link;
677         }
678 
679         /** {@inheritDoc} */
680         @Override
681         public String getId()
682         {
683             return this.id;
684         }
685 
686     }
687 
688     /** Helper class NodeData. */
689     private static class NodeData implements NodeDataInterface
690     {
691 
692         /** Node id. */
693         private String id;
694 
695         /**
696          * Constructor.
697          * @param id String; id
698          */
699         NodeData(final String id)
700         {
701             this.id = id;
702         }
703 
704         /** {@inheritDoc} */
705         @Override
706         public String getId()
707         {
708             return null;
709         }
710 
711     }
712 
713     /** Helper class GtuTypeData. */
714     private static class GtuTypeData implements GtuTypeDataInterface
715     {
716 
717         /** Node id. */
718         private String id;
719 
720         /**
721          * Constructor.
722          * @param id String; id
723          */
724         GtuTypeData(final String id)
725         {
726             this.id = id;
727         }
728 
729         /** {@inheritDoc} */
730         @Override
731         public String getId()
732         {
733             return null;
734         }
735 
736     }
737 
738     /** Helper class RouteData. */
739     private static class RouteData implements RouteDataInterface
740     {
741 
742         /** Node id. */
743         private String id;
744 
745         /**
746          * Constructor.
747          * @param id String; id
748          */
749         RouteData(final String id)
750         {
751             this.id = id;
752         }
753 
754         /** {@inheritDoc} */
755         @Override
756         public String getId()
757         {
758             return null;
759         }
760 
761     }
762 
763     /** Helper class GtuData. */
764     private static class GtuData implements GtuDataInterface
765     {
766 
767         /** Id. */
768         private final String id;
769 
770         /** Origin. */
771         private final NodeData origin;
772 
773         /** Destination. */
774         private final NodeData destination;
775 
776         /** GTU type. */
777         private final GtuTypeData gtuType;
778 
779         /** Route. */
780         private final RouteData route;
781 
782         /**
783          * @param id String; id
784          * @param origin NodeData; origin
785          * @param destination NodeData; destination
786          * @param gtuType GtuTypeData; GTU type
787          * @param route RouteData; route
788          */
789         GtuData(final String id, final NodeData origin, final NodeData destination, final GtuTypeData gtuType,
790                 final RouteData route)
791         {
792             this.id = id;
793             this.origin = origin;
794             this.destination = destination;
795             this.gtuType = gtuType;
796             this.route = route;
797         }
798 
799         /** {@inheritDoc} */
800         @Override
801         public String getId()
802         {
803             return this.id;
804         }
805 
806         /** {@inheritDoc} */
807         @Override
808         public NodeDataInterface getOriginNodeData()
809         {
810             return this.origin;
811         }
812 
813         /** {@inheritDoc} */
814         @Override
815         public NodeDataInterface getDestinationNodeData()
816         {
817             return this.destination;
818         }
819 
820         /** {@inheritDoc} */
821         @Override
822         public GtuTypeDataInterface getGtuTypeData()
823         {
824             return this.gtuType;
825         }
826 
827         /** {@inheritDoc} */
828         @Override
829         public RouteDataInterface getRouteData()
830         {
831             return this.route;
832         }
833 
834     }
835 
836 }