1 package org.opentrafficsim.animation.graphs;
2
3 import java.util.List;
4 import java.util.function.Function;
5
6 import org.djunits.unit.Unit;
7 import org.djunits.value.vdouble.scalar.Duration;
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.djunits.value.vdouble.scalar.base.DoubleScalarRel;
10 import org.djutils.exceptions.Throw;
11 import org.djutils.math.means.ArithmeticMean;
12 import org.opentrafficsim.animation.BoundsPaintScale;
13 import org.opentrafficsim.animation.egtf.Quantity;
14 import org.opentrafficsim.animation.graphs.ContourDataSource.ContourAdditionalDataType;
15 import org.opentrafficsim.animation.graphs.ContourDataSource.ContourDataType;
16 import org.opentrafficsim.kpi.sampling.SamplingException;
17 import org.opentrafficsim.kpi.sampling.Trajectory;
18 import org.opentrafficsim.kpi.sampling.TrajectoryGroup;
19 import org.opentrafficsim.kpi.sampling.data.ExtendedDataNumber;
20 import org.opentrafficsim.kpi.sampling.data.ExtendedDataType;
21
22
23
24
25
26
27
28
29
30
31
32 public class ContourPlotExtendedData<Z extends Number> extends AbstractContourPlot<Z>
33 {
34
35
36
37
38
39
40
41
42
43
44 public ContourPlotExtendedData(final String caption, final ContourDataSource source,
45 final ExtendedDataNumber<?> extendedDataType, final Function<Double, Z> valueConverter, final Bounds<Z> bounds,
46 final LabelData<Z> labelData)
47 {
48 super(caption, source, constructDataType(extendedDataType, valueConverter), bounds, labelData);
49 }
50
51
52
53
54
55
56
57
58
59
60 public ContourPlotExtendedData(final String caption, final ContourDataSource source,
61 final ExtendedDataNumber<?> extendedDataType, final Function<Double, Z> valueConverter,
62 final BoundsPaintScale paintScale, final LabelData<Z> labelData)
63 {
64 super(caption, source, constructDataType(extendedDataType, valueConverter), paintScale, labelData);
65 }
66
67
68
69
70
71
72
73
74
75
76 private static <Z extends Number> ExtendedContourDataType<Z> constructDataType(final ExtendedDataNumber<?> extendedDataType,
77 final Function<Double, Z> valueConverter)
78 {
79 Quantity<Z, double[][]> quantity = Quantity.si("extended_data_" + extendedDataType.getId());
80 return new ExtendedContourDataType<>(extendedDataType, quantity, valueConverter);
81 }
82
83 @Override
84 public GraphType getGraphType()
85 {
86 return GraphType.OTHER;
87 }
88
89 @Override
90 protected double scale(final double si)
91 {
92 return si;
93 }
94
95 @Override
96 public String toString()
97 {
98 return "ContourPlotExtendedData [" + getCaption() + "]";
99 }
100
101
102
103
104
105 private static class ExtendedContourDataType<Z extends Number>
106 implements ContourAdditionalDataType<Z, ArithmeticMean<Double, Double>>
107 {
108
109
110 private final ExtendedDataType<?, ? extends float[], ?, ?> dataType;
111
112
113 private final Quantity<Z, ?> quantity;
114
115
116 private final Function<Double, Z> valueConverter;
117
118
119
120
121
122
123
124 ExtendedContourDataType(final ExtendedDataType<?, ? extends float[], ?, ?> dataType, final Quantity<Z, ?> quantity,
125 final Function<Double, Z> valueConverter)
126 {
127 this.dataType = dataType;
128 this.quantity = quantity;
129 this.valueConverter = valueConverter;
130 }
131
132 @Override
133 public ArithmeticMean<Double, Double> identity()
134 {
135 return new ArithmeticMean<>();
136 }
137
138 @Override
139 public ArithmeticMean<Double, Double> processSeries(final ArithmeticMean<Double, Double> intermediate,
140 final List<TrajectoryGroup<?>> trajectories, final List<Length> xFrom, final List<Length> xTo,
141 final Duration tFrom, final Duration tTo)
142 {
143 for (int i = 0; i < trajectories.size(); i++)
144 {
145 TrajectoryGroup<?> trajectoryGroup = trajectories.get(i);
146 for (Trajectory<?> trajectory : trajectoryGroup.getTrajectories())
147 {
148 if (GraphUtil.considerTrajectory(trajectory, tFrom, tTo))
149 {
150 trajectory = trajectory.subSet(xFrom.get(i), xTo.get(i), tFrom, tTo);
151 try
152 {
153 ContourDataType.weightedNaN(trajectory.getExtendedData(this.dataType), trajectory.getX(),
154 intermediate);
155 }
156 catch (SamplingException ex)
157 {
158 throw new RuntimeException(ex);
159 }
160 }
161 }
162 }
163 return intermediate;
164 }
165
166 @Override
167 public Z finalize(final ArithmeticMean<Double, Double> intermediate)
168 {
169 return this.valueConverter.apply(intermediate.getMean());
170 }
171
172 @Override
173 public Quantity<Z, ?> getQuantity()
174 {
175 return this.quantity;
176 }
177
178 @Override
179 public boolean normalize()
180 {
181 return false;
182 }
183
184 };
185
186
187
188
189
190
191
192
193 public static class UnitPlot<U extends Unit<U>, Z extends DoubleScalarRel<U, Z>> extends ContourPlotExtendedData<Z>
194 {
195
196
197 private static final char[] SUPER =
198 {'\u2070', '\u00B9', '\u00B2', '\u00B3', '\u2074', '\u2075', '\u2076', '\u2077', '\u2078', '\u2079'};
199
200
201 private final Z one;
202
203
204 private final U unit;
205
206
207
208
209
210
211
212
213
214
215 public UnitPlot(final String caption, final ContourDataSource source, final ExtendedDataNumber<?> extendedDataType,
216 final Bounds<Z> bounds, final Z legendStep, final U unit)
217 {
218 super(caption, source, extendedDataType, getConverter(legendStep), bounds, constructLabelData(legendStep, unit));
219 this.one = legendStep.divide(legendStep.si);
220 this.unit = unit;
221 }
222
223
224
225
226
227
228
229
230
231
232 public UnitPlot(final String caption, final ContourDataSource source, final ExtendedDataNumber<?> extendedDataType,
233 final BoundsPaintScale paintScale, final Z legendStep, final U unit)
234 {
235 super(caption, source, extendedDataType, getConverter(legendStep), paintScale,
236 constructLabelData(legendStep, unit));
237 this.one = legendStep.divide(legendStep.si);
238 this.unit = unit;
239 }
240
241
242
243
244
245
246
247
248 private static <U extends Unit<U>, Z extends DoubleScalarRel<U, Z>> Function<Double, Z> getConverter(final Z legendStep)
249 {
250
251 Throw.whenNull(legendStep, "legendStep");
252 Z one = legendStep.divide(legendStep.si);
253 return (v) -> one.times(v);
254 }
255
256
257
258
259
260
261
262
263
264
265 private static <U extends Unit<U>, Z extends DoubleScalarRel<U, Z>> LabelData<Z> constructLabelData(final Z legendStep,
266 final U unit)
267 {
268 String unitString = unit.getId();
269
270 if (unitString != null && !unitString.isEmpty())
271 {
272 int last = unitString.length() - 1;
273 char c = unitString.charAt(last);
274 if (Character.isDigit(c))
275 {
276 unitString = unitString.substring(0, last) + SUPER[c - '0'];
277 }
278 }
279 return new LabelData<>(legendStep, "%.1f" + unitString,
280 "%.2f " + unit.getQuantity().getName().toLowerCase() + " " + unitString);
281 }
282
283 @Override
284 protected double scale(final double si)
285 {
286
287 return this.one.times(si).getInUnit(this.unit);
288 }
289
290 }
291 }