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