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 @Override
203 public final int getItemCount(final int series)
204 {
205 return this.dataPool.getBinCount(Dimension.DISTANCE) * this.dataPool.getBinCount(Dimension.TIME);
206 }
207
208 @Override
209 public final Number getX(final int series, final int item)
210 {
211 return getXValue(series, item);
212 }
213
214 @Override
215 public final double getXValue(final int series, final int item)
216 {
217 return this.dataPool.getAxisValue(Dimension.TIME, item);
218 }
219
220 @Override
221 public final Number getY(final int series, final int item)
222 {
223 return getYValue(series, item);
224 }
225
226 @Override
227 public final double getYValue(final int series, final int item)
228 {
229 return this.dataPool.getAxisValue(Dimension.DISTANCE, item);
230 }
231
232 @Override
233 public final Number getZ(final int series, final int item)
234 {
235 return getZValue(series, item);
236 }
237
238 @Override
239 public final Comparable<String> getSeriesKey(final int series)
240 {
241 return getCaption();
242 }
243
244 @SuppressWarnings("rawtypes")
245 @Override
246 public final int indexOf(final Comparable seriesKey)
247 {
248 return 0;
249 }
250
251 @Override
252 public final DomainOrder getDomainOrder()
253 {
254 return DomainOrder.ASCENDING;
255 }
256
257 @Override
258 public final double getZValue(final int series, final int item)
259 {
260
261 return getValue(item, this.dataPool.getGranularity(Dimension.DISTANCE), this.dataPool.getGranularity(Dimension.TIME));
262 }
263
264 @Override
265 public final int getSeriesCount()
266 {
267 return 1;
268 }
269
270 @Override
271 public int getRangeBinCount()
272 {
273 return this.dataPool.getBinCount(Dimension.DISTANCE);
274 }
275
276
277
278
279
280
281
282 @Override
283 public final String getStatusLabel(final double domainValue, final double rangeValue)
284 {
285 if (this.dataPool == null)
286 {
287 return String.format("time %.0fs, distance %.0fm", domainValue, rangeValue);
288 }
289 int i = this.dataPool.getAxisBin(Dimension.DISTANCE, rangeValue);
290 int j = this.dataPool.getAxisBin(Dimension.TIME, domainValue);
291 int item = j * this.dataPool.getBinCount(Dimension.DISTANCE) + i;
292 double zValue = scale(
293 getValue(item, this.dataPool.getGranularity(Dimension.DISTANCE), this.dataPool.getGranularity(Dimension.TIME)));
294 return String.format("time %.0fs, distance %.0fm, " + this.valueFormat, domainValue, rangeValue, zValue);
295 }
296
297 @Override
298 protected final void increaseTime(final Time time)
299 {
300 if (this.dataPool != null)
301 {
302 this.dataPool.increaseTime(time);
303 }
304 }
305
306
307
308
309
310
311
312
313 protected abstract double getValue(int item, double cellLength, double cellSpan);
314
315
316
317
318
319
320 protected abstract double scale(double si);
321
322
323
324
325
326 protected abstract ContourDataType<Z, ?> getContourDataType();
327
328
329
330
331
332 public XyInterpolatedBlockRenderer getBlockRenderer()
333 {
334 return this.blockRenderer;
335 }
336
337 @Override
338 public final void actionPerformed(final ActionEvent actionEvent)
339 {
340 String command = actionEvent.getActionCommand();
341 if (command.equalsIgnoreCase("setSpaceGranularity"))
342 {
343
344 double granularity = (double) actionEvent.getSource();
345 setSpaceGranularity(granularity);
346 }
347 else if (command.equalsIgnoreCase("setTimeGranularity"))
348 {
349
350 double granularity = (double) actionEvent.getSource();
351 setTimeGranularity(granularity);
352 }
353 else
354 {
355 throw new RuntimeException("Unhandled ActionEvent (actionCommand is " + actionEvent.getActionCommand() + "\")");
356 }
357 }
358
359 }