1 package org.opentrafficsim.draw.graphs;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6 import java.util.NoSuchElementException;
7
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.djunits.value.vdouble.scalar.Speed;
10 import org.djunits.value.vdouble.scalar.Time;
11 import org.djutils.exceptions.Throw;
12 import org.djutils.immutablecollections.Immutable;
13 import org.djutils.immutablecollections.ImmutableArrayList;
14 import org.djutils.immutablecollections.ImmutableList;
15 import org.djutils.means.ArithmeticMean;
16 import org.opentrafficsim.kpi.interfaces.LaneData;
17 import org.opentrafficsim.kpi.sampling.Sampler;
18 import org.opentrafficsim.kpi.sampling.SpaceTimeRegion;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public class GraphPath<S> extends AbstractGraphSpace<S>
34 {
35
36
37 private final List<Section<S>> sections;
38
39
40 private final List<Length> startDistances = new ArrayList<>();
41
42
43 private final Length totalLength;
44
45
46 private final Speed speedLimit;
47
48
49
50
51
52
53 public GraphPath(final String name, final List<Section<S>> sections)
54 {
55 this(new ArrayList<String>()
56 {
57
58 private static final long serialVersionUID = 20181020L;
59 {
60 add(name);
61 }
62 }, sections);
63 }
64
65
66
67
68
69
70 public GraphPath(final List<String> seriesNames, final List<Section<S>> sections)
71 {
72 super(seriesNames);
73 this.sections = sections;
74 Length cumulativeLength = Length.ZERO;
75 for (Section<S> section : sections)
76 {
77 this.startDistances.add(cumulativeLength);
78 cumulativeLength = cumulativeLength.plus(section.length());
79 }
80 this.totalLength = cumulativeLength;
81 ArithmeticMean<Double, Double> mean = new ArithmeticMean<>();
82 for (Section<S> section : sections)
83 {
84 mean.add(section.speedLimit().si, section.length().si);
85 }
86 this.speedLimit = Speed.instantiateSI(mean.getMean());
87 }
88
89
90
91
92
93
94 public Length getStartDistance(final Section<?> section)
95 {
96 int index = this.sections.indexOf(section);
97 Throw.when(index == -1, IllegalArgumentException.class, "Section is not part of the path.");
98 return this.startDistances.get(index);
99 }
100
101
102
103
104
105 public Length getTotalLength()
106 {
107 return this.totalLength;
108 }
109
110
111
112
113
114 public Speed getSpeedLimit()
115 {
116 return this.speedLimit;
117 }
118
119
120
121
122
123
124 public Section<S> get(final int index)
125 {
126 return this.sections.get(index);
127 }
128
129
130 @Override
131 public Iterator<S> iterator()
132 {
133 return new Iterator<S>()
134 {
135
136
137 private Iterator<Section<S>> sectionIterator = getSections().iterator();
138
139
140 private Iterator<S> sourceIterator = this.sectionIterator.hasNext() ? this.sectionIterator.next().iterator() : null;
141
142
143 @Override
144 public boolean hasNext()
145 {
146 if (this.sourceIterator != null && this.sourceIterator.hasNext())
147 {
148 return true;
149 }
150 while (this.sectionIterator.hasNext())
151 {
152 Iterator<S> it = this.sectionIterator.next().iterator();
153 if (it.hasNext())
154 {
155 this.sourceIterator = it;
156 return true;
157 }
158 }
159 this.sourceIterator = null;
160 return false;
161 }
162
163
164 @Override
165 public S next()
166 {
167 Throw.when(!hasNext(), NoSuchElementException.class, "No more element left.");
168 return this.sourceIterator.next();
169 }
170 };
171 }
172
173
174 @Override
175 public Iterator<S> iterator(final int series)
176 {
177 List<S> list = new ArrayList<>();
178 for (Section<S> section : this.sections)
179 {
180 list.add(section.getSource(series));
181 }
182 return new ImmutableArrayList<>(list, Immutable.WRAP).iterator();
183 }
184
185
186
187
188
189 public ImmutableList<Section<S>> getSections()
190 {
191 return new ImmutableArrayList<>(this.sections, Immutable.WRAP);
192 }
193
194
195 @Override
196 public String toString()
197 {
198 return "GraphPath [sections=" + this.sections + ", startDistances=" + this.startDistances + ", totalLength="
199 + this.totalLength + ", speedLimit=" + this.speedLimit + "]";
200 }
201
202
203
204
205
206
207
208 public static <L extends LaneData<L>> void initRecording(final Sampler<?, L> sampler, final GraphPath<L> path)
209 {
210 for (Section<L> section : path.getSections())
211 {
212 for (L lane : section)
213 {
214 sampler.registerSpaceTimeRegion(new SpaceTimeRegion<>(lane, Length.ZERO, lane.getLength(), Time.ZERO,
215 Time.instantiateSI(Double.MAX_VALUE)));
216 }
217 }
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235 public static record Section<L>(Length length, Speed speedLimit, List<L> sections) implements Iterable<L>
236 {
237
238
239
240
241
242 public L getSource(final int series)
243 {
244 return this.sections.get(series);
245 }
246
247
248 @Override
249 public Iterator<L> iterator()
250 {
251 return this.sections.iterator();
252 }
253 }
254
255 }