GraphPath.java

  1. package org.opentrafficsim.draw.graphs;

  2. import java.util.ArrayList;
  3. import java.util.Iterator;
  4. import java.util.List;
  5. import java.util.NoSuchElementException;

  6. import org.djunits.value.vdouble.scalar.Length;
  7. import org.djunits.value.vdouble.scalar.Speed;
  8. import org.djunits.value.vdouble.scalar.Time;
  9. import org.djutils.exceptions.Throw;
  10. import org.djutils.immutablecollections.Immutable;
  11. import org.djutils.immutablecollections.ImmutableArrayList;
  12. import org.djutils.immutablecollections.ImmutableList;
  13. import org.opentrafficsim.base.WeightedMeanAndSum;
  14. import org.opentrafficsim.kpi.sampling.KpiLaneDirection;
  15. import org.opentrafficsim.kpi.sampling.Sampler;
  16. import org.opentrafficsim.kpi.sampling.SpaceTimeRegion;

  17. /**
  18.  * A {@code GraphPath} defines the spatial dimension of graphs. It has a number of sections, each of which may have one or more
  19.  * source objects depending on the number of series. For example, a 3-lane road may result in a few sections each having 3
  20.  * series. Graphs can aggregate the series, or show multiple series.
  21.  * <p>
  22.  * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  23.  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  24.  * <p>
  25.  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 19 okt. 2018 <br>
  26.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  27.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  28.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  29.  * @param <S> underlying type of path sections
  30.  */
  31. public class GraphPath<S> extends AbstractGraphSpace<S>
  32. {

  33.     /** Sections. */
  34.     private final List<Section<S>> sections;

  35.     /** Start distance per section. */
  36.     private final List<Length> startDistances = new ArrayList<>();

  37.     /** Total path length. */
  38.     private final Length totalLength;

  39.     /** Mean speed limit over the entire path. */
  40.     private final Speed speedLimit;

  41.     /**
  42.      * Constructor for a one-series path.
  43.      * @param name String; name
  44.      * @param sections List&lt;Section&lt;S&gt;&gt;; sections
  45.      */
  46.     public GraphPath(final String name, final List<Section<S>> sections)
  47.     {
  48.         this(new ArrayList<String>()
  49.         {
  50.             /** */
  51.             private static final long serialVersionUID = 20181020L;
  52.             {
  53.                 add(name);
  54.             }
  55.         }, sections);
  56.     }

  57.     /**
  58.      * Constructor.
  59.      * @param seriesNames List&lt;String&gt;; names of series
  60.      * @param sections List&lt;Section&lt;S&gt;&gt;; sections
  61.      */
  62.     public GraphPath(final List<String> seriesNames, final List<Section<S>> sections)
  63.     {
  64.         super(seriesNames);
  65.         this.sections = sections;
  66.         Length cumulativeLength = Length.ZERO;
  67.         for (Section<S> section : sections)
  68.         {
  69.             this.startDistances.add(cumulativeLength);
  70.             cumulativeLength = cumulativeLength.plus(section.getLength());
  71.         }
  72.         this.totalLength = cumulativeLength;
  73.         WeightedMeanAndSum<Double, Double> mean = new WeightedMeanAndSum<>();
  74.         for (Section<S> section : sections)
  75.         {
  76.             mean.add(section.getSpeedLimit().si, section.getLength().si);
  77.         }
  78.         this.speedLimit = Speed.instantiateSI(mean.getMean());
  79.     }

  80.     /**
  81.      * Returns the start distance of the section.
  82.      * @param section Section&lt;S&gt;; Section&lt;S&gt; section
  83.      * @return Length; start distance of the section
  84.      */
  85.     public Length getStartDistance(final Section<S> section)
  86.     {
  87.         int index = this.sections.indexOf(section);
  88.         Throw.when(index == -1, IllegalArgumentException.class, "Section is not part of the path.");
  89.         return this.startDistances.get(index);
  90.     }

  91.     /**
  92.      * Returns the total path length.
  93.      * @return Length; total path length
  94.      */
  95.     public Length getTotalLength()
  96.     {
  97.         return this.totalLength;
  98.     }

  99.     /**
  100.      * Returns the mean speed over the entire section.
  101.      * @return Speed; mean speed over the entire section
  102.      */
  103.     public Speed getSpeedLimit()
  104.     {
  105.         return this.speedLimit;
  106.     }

  107.     /**
  108.      * Returns a section.
  109.      * @param index int; index of section
  110.      * @return Section&lt;S&gt;; section
  111.      */
  112.     public Section<S> get(final int index)
  113.     {
  114.         return this.sections.get(index);
  115.     }

  116.     /** {@inheritDoc} */
  117.     @Override
  118.     public Iterator<S> iterator()
  119.     {
  120.         return new Iterator<S>()
  121.         {

  122.             /** Section iterator. */
  123.             private Iterator<Section<S>> sectionIterator = getSections().iterator();

  124.             /** Source object iterator per section. */
  125.             private Iterator<S> sourceIterator = this.sectionIterator.hasNext() ? this.sectionIterator.next().iterator() : null;

  126.             /** {@inheritDoc} */
  127.             @Override
  128.             public boolean hasNext()
  129.             {
  130.                 if (this.sourceIterator != null && this.sourceIterator.hasNext())
  131.                 {
  132.                     return true;
  133.                 }
  134.                 while (this.sectionIterator.hasNext())
  135.                 {
  136.                     Iterator<S> it = this.sectionIterator.next().iterator();
  137.                     if (it.hasNext())
  138.                     {
  139.                         this.sourceIterator = it;
  140.                         return true;
  141.                     }
  142.                 }
  143.                 this.sourceIterator = null;
  144.                 return false;
  145.             }

  146.             /** {@inheritDoc} */
  147.             @Override
  148.             public S next()
  149.             {
  150.                 Throw.when(!hasNext(), NoSuchElementException.class, "No more element left.");
  151.                 return this.sourceIterator.next();
  152.             }
  153.         };
  154.     }

  155.     /** {@inheritDoc} */
  156.     @Override
  157.     public Iterator<S> iterator(final int series)
  158.     {
  159.         List<S> list = new ArrayList<>();
  160.         for (Section<S> section : this.sections)
  161.         {
  162.             list.add(section.getSource(series));
  163.         }
  164.         return new ImmutableArrayList<>(list, Immutable.WRAP).iterator();
  165.     }

  166.     /**
  167.      * Returns an immutable list of the sections.
  168.      * @return ImmutableList&lt;Section&lt;S&gt;&gt;; sections
  169.      */
  170.     public ImmutableList<Section<S>> getSections()
  171.     {
  172.         return new ImmutableArrayList<>(this.sections, Immutable.WRAP);
  173.     }

  174.     /** {@inheritDoc} */
  175.     @Override
  176.     public String toString()
  177.     {
  178.         return "GraphPath [sections=" + this.sections + ", startDistances=" + this.startDistances + ", totalLength="
  179.             + this.totalLength + ", speedLimit=" + this.speedLimit + "]";
  180.     }

  181.     /**
  182.      * Start recording along path.
  183.      * @param sampler Sampler&lt;?&gt;; sampler
  184.      * @param path GraphPath&lt;KpiLaneDirection&gt;; path
  185.      */
  186.     public static void initRecording(final Sampler<?> sampler, final GraphPath<KpiLaneDirection> path)
  187.     {
  188.         for (Section<KpiLaneDirection> section : path.getSections())
  189.         {
  190.             for (KpiLaneDirection kpiLaneDirection : section)
  191.             {
  192.                 sampler.registerSpaceTimeRegion(new SpaceTimeRegion(kpiLaneDirection, Length.ZERO,
  193.                         kpiLaneDirection.getLaneData().getLength(), Time.ZERO, Time.instantiateSI(Double.MAX_VALUE)));
  194.             }
  195.         }
  196.     }

  197.     /**
  198.      * Interface for sections.
  199.      * <p>
  200.      * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
  201.      * <br>
  202.      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  203.      * <p>
  204.      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 20 okt. 2018 <br>
  205.      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  206.      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  207.      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  208.      * @param <S> underlying type
  209.      */
  210.     public interface Section<S> extends Iterable<S>
  211.     {
  212.         /**
  213.          * Returns the section length.
  214.          * @return Length; section length
  215.          */
  216.         Length getLength();

  217.         /**
  218.          * Returns the speed limit on the section.
  219.          * @return Speed; speed limit on the section
  220.          */
  221.         Speed getSpeedLimit();

  222.         /**
  223.          * Returns the source object.
  224.          * @param series int; number
  225.          * @return S; underlying object of the series
  226.          */
  227.         S getSource(int series);
  228.     }

  229. }