View Javadoc
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&lt;Section&lt;S&gt;&gt;; 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&lt;String&gt;; names of series
65       * @param sections List&lt;Section&lt;S&gt;&gt;; 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&lt;S&gt;; Section&lt;S&gt; 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&lt;S&gt;; 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&lt;Section&lt;S&gt;&gt;; 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 }