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