1   package org.opentrafficsim.draw.graphs.road;
2   
3   import java.awt.Color;
4   import java.util.List;
5   
6   import org.djunits.unit.DurationUnit;
7   import org.djunits.unit.LinearDensityUnit;
8   import org.djunits.value.StorageType;
9   import org.djunits.value.ValueException;
10  import org.djunits.value.vdouble.matrix.DurationMatrix;
11  import org.djunits.value.vdouble.scalar.Duration;
12  import org.djunits.value.vdouble.scalar.Length;
13  import org.djunits.value.vdouble.scalar.Time;
14  import org.djunits.value.vfloat.vector.FloatSpeedVector;
15  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
16  import org.opentrafficsim.core.egtf.Converter;
17  import org.opentrafficsim.core.egtf.Quantity;
18  import org.opentrafficsim.draw.core.BoundsPaintScale;
19  import org.opentrafficsim.draw.graphs.AbstractContourPlot;
20  import org.opentrafficsim.draw.graphs.ContourDataSource;
21  import org.opentrafficsim.draw.graphs.ContourDataSource.ContourDataType;
22  import org.opentrafficsim.draw.graphs.GraphType;
23  import org.opentrafficsim.draw.graphs.GraphUtil;
24  import org.opentrafficsim.kpi.sampling.SamplingException;
25  import org.opentrafficsim.kpi.sampling.Trajectory;
26  import org.opentrafficsim.kpi.sampling.TrajectoryGroup;
27  import org.opentrafficsim.road.network.sampling.GtuData;
28  import org.opentrafficsim.road.network.sampling.data.ReferenceSpeed;
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  public class ContourPlotDelay extends AbstractContourPlot<Duration>
49  {
50  
51      
52      private static final long serialVersionUID = 20181010L;
53  
54      
55      private static final Quantity<Duration, DurationMatrix> QUANTITY = new Quantity<>("delay", new Converter<DurationMatrix>()
56      {
57          
58          @Override
59          public DurationMatrix convert(final double[][] filteredData)
60          {
61              try
62              {
63                  return new DurationMatrix(filteredData, DurationUnit.SI, StorageType.DENSE);
64              }
65              catch (ValueException exception)
66              {
67                  
68                  throw new RuntimeException("Unexpected exception while converting duration to output format.", exception);
69              }
70          }
71      });
72  
73      
74      private static final ContourDataType<Duration, Duration> CONTOUR_DATA_TYPE = new ContourDataType<Duration, Duration>()
75      {
76          
77          @Override
78          public Duration identity()
79          {
80              return Duration.ZERO;
81          }
82  
83          
84          @Override
85          public Duration processSeries(final Duration intermediate, final List<TrajectoryGroup<?>> trajectories,
86                  final List<Length> xFrom, final List<Length> xTo, final Time tFrom, final Time tTo)
87          {
88              double sumActualTime = 0.0;
89              double sumRefTime = 0.0;
90              for (int i = 0; i < trajectories.size(); i++)
91              {
92                  TrajectoryGroup<?> trajectoryGroup = trajectories.get(i);
93                  for (Trajectory<?> trajectory : trajectoryGroup.getTrajectories())
94                  {
95                      if (GraphUtil.considerTrajectory(trajectory, tFrom, tTo))
96                      {
97                          trajectory = trajectory.subSet(xFrom.get(i), xTo.get(i), tFrom, tTo);
98                          try
99                          {
100                             FloatSpeedVector ref = trajectory.getExtendedData(ReferenceSpeed.INSTANCE);
101                             float[] v = trajectory.getV();
102                             float[] x = trajectory.getX();
103                             for (int j = 0; j < v.length - 1; j++)
104                             {
105                                 sumRefTime += (x[j + 1] - x[j]) / ref.get(j).si;
106                             }
107                         }
108                         catch (SamplingException | ValueException exception)
109                         {
110                             throw new RuntimeException("Unexpected exception while calculating delay.", exception);
111                         }
112                         sumActualTime += trajectory.getTotalDuration().si;
113                     }
114                 }
115             }
116             return Duration.createSI(intermediate.si + sumActualTime - sumRefTime);
117         }
118 
119         
120         @Override
121         public Duration finalize(final Duration intermediate)
122         {
123             return intermediate;
124         }
125 
126         
127         @SuppressWarnings("synthetic-access")
128         @Override
129         public Quantity<Duration, ?> getQuantity()
130         {
131             return QUANTITY;
132         }
133 
134     };
135 
136     
137 
138 
139 
140 
141 
142     public ContourPlotDelay(final String caption, final OTSSimulatorInterface simulator,
143             final ContourDataSource<GtuData> dataPool)
144     {
145         super(caption, simulator, dataPool, createPaintScale(), new Duration(0.05, DurationUnit.SI), "%.1f/km",
146                 "delay %.1f /km");
147         dataPool.getSampler().registerExtendedDataType(ReferenceSpeed.INSTANCE);
148     }
149 
150     
151 
152 
153 
154     private static BoundsPaintScale createPaintScale()
155     {
156         double[] boundaries = { 0.0, 0.05, 0.2 };
157         Color[] colorValues = BoundsPaintScale.GREEN_RED;
158         return new BoundsPaintScale(boundaries, colorValues);
159     }
160 
161     
162     @Override
163     public GraphType getGraphType()
164     {
165         return GraphType.DELAY_CONTOUR;
166     }
167 
168     
169     @Override
170     protected double scale(final double si)
171     {
172         return LinearDensityUnit.PER_KILOMETER.getScale().fromStandardUnit(si);
173     }
174 
175     
176     @Override
177     protected double getValue(final int item, final double cellLength, final double cellSpan)
178     {
179         return getDataPool().get(item, CONTOUR_DATA_TYPE) / (cellLength * cellSpan);
180     }
181 
182     
183     @Override
184     protected ContourDataType<Duration, Duration> getContourDataType()
185     {
186         return CONTOUR_DATA_TYPE;
187     }
188 
189 }