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.djutils.exceptions.Throw;
11 import org.djutils.immutablecollections.Immutable;
12 import org.djutils.immutablecollections.ImmutableArrayList;
13 import org.djutils.immutablecollections.ImmutableList;
14 import org.opentrafficsim.base.WeightedMeanAndSum;
15
16 /**
17 * A {@code GraphPath} defines the spatial dimension of graphs. It has a number of sections, each of which may have one or more
18 * source objects depending on the number of series. For example, a 3-lane road may result in a few sections each having 3
19 * series. Graphs can aggregate the series, or show multiple series.
20 * <p>
21 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
22 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
23 * <p>
24 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 19 okt. 2018 <br>
25 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
26 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
27 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
28 * @param <S> underlying type of path sections
29 */
30 public class GraphPath<S> extends AbstractGraphSpace<S>
31 {
32
33 /** Sections. */
34 private final List<Section<S>> sections;
35
36 /** Start distance per section. */
37 private final List<Length> startDistances = new ArrayList<>();
38
39 /** Total path length. */
40 private final Length totalLength;
41
42 /** Mean speed limit over the entire path. */
43 private final Speed speedLimit;
44
45 /**
46 * Constructor for a one-series path.
47 * @param name String; name
48 * @param sections List<Section<S>>; sections
49 */
50 public GraphPath(final String name, final List<Section<S>> sections)
51 {
52 this(new ArrayList<String>()
53 {
54 /** */
55 private static final long serialVersionUID = 20181020L;
56 {
57 add(name);
58 }
59 }, sections);
60 }
61
62 /**
63 * Constructor.
64 * @param seriesNames List<String>; names of series
65 * @param sections List<Section<S>>; sections
66 */
67 public GraphPath(final List<String> seriesNames, final List<Section<S>> sections)
68 {
69 super(seriesNames);
70 this.sections = sections;
71 Length start = Length.ZERO;
72 for (Section<S> section : sections)
73 {
74 this.startDistances.add(start);
75 start = start.plus(section.getLength());
76 }
77 this.totalLength = start;
78 WeightedMeanAndSum<Double, Double> mean = new WeightedMeanAndSum<>();
79 for (Section<S> section : sections)
80 {
81 mean.add(section.getSpeedLimit().si, section.getLength().si);
82 }
83 this.speedLimit = Speed.createSI(mean.getMean());
84 }
85
86 /**
87 * Returns the start distance of the section.
88 * @param section Section<S>; Section<S> section
89 * @return Length; start distance of the section
90 */
91 public final Length getStartDistance(final Section<S> section)
92 {
93 int index = this.sections.indexOf(section);
94 Throw.when(index == -1, IllegalArgumentException.class, "Section is not part of the path.");
95 return this.startDistances.get(index);
96 }
97
98 /**
99 * Returns the total path length.
100 * @return Length; total path length
101 */
102 public final Length getTotalLength()
103 {
104 return this.totalLength;
105 }
106
107 /**
108 * Returns the mean speed over the entire section.
109 * @return Speed; mean speed over the entire section
110 */
111 public final Speed getSpeedLimit()
112 {
113 return this.speedLimit;
114 }
115
116 /**
117 * Returns a section.
118 * @param index int; index of section
119 * @return Section<S>; section
120 */
121 public Section<S> get(final int index)
122 {
123 return this.sections.get(index);
124 }
125
126 /** {@inheritDoc} */
127 @Override
128 public Iterator<S> iterator()
129 {
130 return new Iterator<S>()
131 {
132
133 /** Section iterator. */
134 private Iterator<Section<S>> sectionIterator = getSections().iterator();
135
136 /** Source object iterator per section. */
137 private Iterator<S> sourceIterator = this.sectionIterator.hasNext() ? this.sectionIterator.next().iterator() : null;
138
139 /** {@inheritDoc} */
140 @Override
141 public boolean hasNext()
142 {
143 if (this.sourceIterator != null && this.sourceIterator.hasNext())
144 {
145 return true;
146 }
147 while (this.sectionIterator.hasNext())
148 {
149 Iterator<S> it = this.sectionIterator.next().iterator();
150 if (it.hasNext())
151 {
152 this.sourceIterator = it;
153 return true;
154 }
155 }
156 this.sourceIterator = null;
157 return false;
158 }
159
160 /** {@inheritDoc} */
161 @Override
162 public S next()
163 {
164 Throw.when(!hasNext(), NoSuchElementException.class, "No more element left.");
165 return this.sourceIterator.next();
166 }
167 };
168 }
169
170 /** {@inheritDoc} */
171 @Override
172 public Iterator<S> iterator(final int series)
173 {
174 List<S> list = new ArrayList<>();
175 for (Section<S> section : this.sections)
176 {
177 list.add(section.getSource(series));
178 }
179 return new ImmutableArrayList<>(list, Immutable.WRAP).iterator();
180 }
181
182 /**
183 * Returns an immutable list of the sections.
184 * @return ImmutableList<Section<S>>; sections
185 */
186 public ImmutableList<Section<S>> getSections()
187 {
188 return new ImmutableArrayList<>(this.sections, Immutable.WRAP);
189 }
190
191 /**
192 * Interface for sections.
193 * <p>
194 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
195 * <br>
196 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
197 * <p>
198 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 20 okt. 2018 <br>
199 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
200 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
201 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
202 * @param <S> underlying type
203 */
204 public interface Section<S> extends Iterable<S>
205 {
206 /**
207 * Returns the section length.
208 * @return Length; section length
209 */
210 Length getLength();
211
212 /**
213 * Returns the speed limit on the section.
214 * @return Speed; speed limit on the section
215 */
216 Speed getSpeedLimit();
217
218 /**
219 * Returns the source object.
220 * @param series int; number
221 * @return S; underlying object of the series
222 */
223 S getSource(int series);
224 }
225
226 /** {@inheritDoc} */
227 @Override
228 public String toString()
229 {
230 return "GraphPath [sections=" + this.sections + ", startDistances=" + this.startDistances + ", totalLength="
231 + this.totalLength + ", speedLimit=" + this.speedLimit + "]";
232 }
233
234 }