1 package org.opentrafficsim.draw.graphs;
2
3 import java.awt.Color;
4
5 import org.djunits.value.vdouble.scalar.Duration;
6 import org.djutils.exceptions.Throw;
7 import org.jfree.chart.JFreeChart;
8 import org.jfree.chart.LegendItem;
9 import org.jfree.chart.LegendItemCollection;
10 import org.jfree.chart.axis.NumberAxis;
11 import org.jfree.chart.plot.XYPlot;
12 import org.jfree.data.DomainOrder;
13 import org.opentrafficsim.draw.BoundsPaintScale;
14 import org.opentrafficsim.draw.graphs.ContourDataSource.ContourDataType;
15 import org.opentrafficsim.draw.graphs.ContourDataSource.Dimension;
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 public abstract class AbstractContourPlot<Z extends Number> extends AbstractSamplerPlot implements XyInterpolatedDataset
31 {
32
33
34 private final BoundsPaintScale paintScale;
35
36
37 private final Z legendStep;
38
39
40 private final String legendFormat;
41
42
43 private final String valueFormat;
44
45
46 private final ContourDataSource dataPool;
47
48
49 private final ContourDataType<Z, ?> contourDataType;
50
51
52 private XyInterpolatedBlockRenderer blockRenderer = null;
53
54
55
56
57
58
59
60
61
62
63
64
65 @SuppressWarnings("parameternumber")
66 public AbstractContourPlot(final String caption, final PlotScheduler scheduler, final ContourDataSource dataPool,
67 final ContourDataType<Z, ?> contourDataType, final BoundsPaintScale paintScale, final Z legendStep,
68 final String legendFormat, final String valueFormat)
69 {
70 super(caption, dataPool.getUpdateInterval(), scheduler, dataPool.getSamplerData(), dataPool.getPath(),
71 dataPool.getDelay());
72 this.dataPool = dataPool;
73 this.contourDataType = contourDataType;
74 this.paintScale = paintScale;
75 this.legendStep = legendStep;
76 this.legendFormat = legendFormat;
77 this.valueFormat = valueFormat;
78 this.blockRenderer = new XyInterpolatedBlockRenderer(this);
79 this.blockRenderer.setPaintScale(this.paintScale);
80 this.blockRenderer.setBlockHeight(dataPool.getGranularity(Dimension.DISTANCE));
81 this.blockRenderer.setBlockWidth(dataPool.getGranularity(Dimension.TIME));
82 dataPool.registerContourPlot(this);
83 setChart(createChart());
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97
98 @SuppressWarnings("parameternumber")
99 public AbstractContourPlot(final String caption, final PlotScheduler scheduler, final ContourDataSource dataPool,
100 final ContourDataType<Z, ?> contourDataType, final Z legendStep, final String legendFormat, final Z minValue,
101 final Z maxValue, final String valueFormat)
102 {
103 this(caption, scheduler, dataPool, contourDataType, createPaintScale(minValue, maxValue), legendStep, legendFormat,
104 valueFormat);
105 }
106
107
108
109
110
111
112
113 private static BoundsPaintScale createPaintScale(final Number minValue, final Number maxValue)
114 {
115 Throw.when(minValue.doubleValue() >= maxValue.doubleValue(), IllegalArgumentException.class,
116 "Minimum value %s is below or equal to maxumum value %s.", minValue, maxValue);
117 double[] boundaries =
118 {minValue.doubleValue(), (minValue.doubleValue() + maxValue.doubleValue()) / 2.0, maxValue.doubleValue()};
119 Color[] colorValues = {Color.RED, Color.YELLOW, Color.GREEN};
120 return new BoundsPaintScale(boundaries, colorValues);
121 }
122
123
124
125
126
127 private JFreeChart createChart()
128 {
129 NumberAxis xAxis = new NumberAxis("Time [s] \u2192");
130 NumberAxis yAxis = new NumberAxis("Distance [m] \u2192");
131 XYPlot plot = new XYPlot(this, xAxis, yAxis, this.blockRenderer);
132 LegendItemCollection legend = new LegendItemCollection();
133 for (int i = 0;; i++)
134 {
135 double value = this.paintScale.getLowerBound() + i * this.legendStep.doubleValue();
136 if (value > this.paintScale.getUpperBound() + 1e-6)
137 {
138 break;
139 }
140 legend.add(new LegendItem(String.format(this.legendFormat, scale(value)), this.paintScale.getPaint(value)));
141 }
142 legend.add(new LegendItem("No data", Color.BLACK));
143 plot.setFixedLegendItems(legend);
144 final JFreeChart chart = new JFreeChart(getCaption(), plot);
145 return chart;
146 }
147
148
149
150
151
152 public double getTimeGranularity()
153 {
154 return this.dataPool.getGranularity(Dimension.TIME);
155 }
156
157
158
159
160
161 public double getSpaceGranularity()
162 {
163 return this.dataPool.getGranularity(Dimension.DISTANCE);
164 }
165
166
167
168
169
170
171 public final void setSpaceGranularity(final double granularity)
172 {
173 this.blockRenderer.setBlockHeight(granularity);
174 this.dataPool.spaceAxis.setGranularity(granularity);
175 }
176
177
178
179
180
181
182 public final void setTimeGranularity(final double granularity)
183 {
184 this.blockRenderer.setBlockWidth(granularity);
185 this.dataPool.timeAxis.setGranularity(granularity);
186 }
187
188
189
190
191
192
193 public final void setInterpolation(final boolean interpolate)
194 {
195 this.blockRenderer.setInterpolate(interpolate);
196 this.dataPool.timeAxis.setInterpolate(interpolate);
197 this.dataPool.spaceAxis.setInterpolate(interpolate);
198 }
199
200
201
202
203
204 public final ContourDataSource getDataPool()
205 {
206 return this.dataPool;
207 }
208
209 @Override
210 public final int getItemCount(final int series)
211 {
212 return this.dataPool.getBinCount(Dimension.DISTANCE) * this.dataPool.getBinCount(Dimension.TIME);
213 }
214
215 @Override
216 public final Number getX(final int series, final int item)
217 {
218 return getXValue(series, item);
219 }
220
221 @Override
222 public final double getXValue(final int series, final int item)
223 {
224 return this.dataPool.getAxisValue(Dimension.TIME, item);
225 }
226
227 @Override
228 public final Number getY(final int series, final int item)
229 {
230 return getYValue(series, item);
231 }
232
233 @Override
234 public final double getYValue(final int series, final int item)
235 {
236 return this.dataPool.getAxisValue(Dimension.DISTANCE, item);
237 }
238
239 @Override
240 public final Number getZ(final int series, final int item)
241 {
242 return getZValue(series, item);
243 }
244
245 @Override
246 public final Comparable<String> getSeriesKey(final int series)
247 {
248 return getCaption();
249 }
250
251 @SuppressWarnings("rawtypes")
252 @Override
253 public final int indexOf(final Comparable seriesKey)
254 {
255 return 0;
256 }
257
258 @Override
259 public final DomainOrder getDomainOrder()
260 {
261 return DomainOrder.ASCENDING;
262 }
263
264 @Override
265 public final double getZValue(final int series, final int item)
266 {
267
268 return getValue(item, this.dataPool.getGranularity(Dimension.DISTANCE), this.dataPool.getGranularity(Dimension.TIME));
269 }
270
271 @Override
272 public final int getSeriesCount()
273 {
274 return 1;
275 }
276
277 @Override
278 public int getRangeBinCount()
279 {
280 return this.dataPool.getBinCount(Dimension.DISTANCE);
281 }
282
283
284
285
286
287
288
289 @Override
290 public final String getStatusLabel(final double domainValue, final double rangeValue)
291 {
292 if (this.dataPool == null)
293 {
294 return String.format("time %.0fs, distance %.0fm", domainValue, rangeValue);
295 }
296 int i = this.dataPool.getAxisBin(Dimension.DISTANCE, rangeValue);
297 int j = this.dataPool.getAxisBin(Dimension.TIME, domainValue);
298 int item = j * this.dataPool.getBinCount(Dimension.DISTANCE) + i;
299 double zValue = scale(
300 getValue(item, this.dataPool.getGranularity(Dimension.DISTANCE), this.dataPool.getGranularity(Dimension.TIME)));
301 return String.format("time %.0fs, distance %.0fm, " + this.valueFormat, domainValue, rangeValue, zValue);
302 }
303
304 @Override
305 protected final void increaseTime(final Duration time)
306 {
307 if (this.dataPool != null)
308 {
309 this.dataPool.increaseTime(time);
310 }
311 }
312
313
314
315
316
317
318
319
320 protected abstract double getValue(int item, double cellLength, double cellSpan);
321
322
323
324
325
326
327 protected abstract double scale(double si);
328
329
330
331
332
333 protected ContourDataType<Z, ?> getContourDataType()
334 {
335 return this.contourDataType;
336 }
337
338
339
340
341
342 public XyInterpolatedBlockRenderer getBlockRenderer()
343 {
344 return this.blockRenderer;
345 }
346
347 }