1 package org.opentrafficsim.draw.graphs;
2
3 import java.awt.Color;
4 import java.awt.Font;
5 import java.awt.Graphics2D;
6 import java.awt.geom.AffineTransform;
7 import java.awt.geom.Rectangle2D;
8 import java.awt.image.BufferedImage;
9 import java.io.IOException;
10 import java.util.LinkedHashSet;
11 import java.util.Set;
12 import java.util.UUID;
13
14 import org.djunits.value.vdouble.scalar.Duration;
15 import org.djunits.value.vdouble.scalar.Time;
16 import org.djutils.event.EventType;
17 import org.jfree.chart.ChartUtils;
18 import org.jfree.chart.JFreeChart;
19 import org.jfree.chart.plot.XYPlot;
20 import org.jfree.chart.title.TextTitle;
21 import org.jfree.data.general.Dataset;
22 import org.jfree.data.general.DatasetChangeEvent;
23 import org.jfree.data.general.DatasetChangeListener;
24 import org.jfree.data.general.DatasetGroup;
25 import org.opentrafficsim.base.Identifiable;
26 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
27
28 import nl.tudelft.simulation.dsol.SimRuntimeException;
29 import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEventInterface;
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public abstract class AbstractPlot implements Identifiable, Dataset
44 {
45
46
47
48
49
50 public static final EventType GRAPH_ADD_EVENT = new EventType("GRAPH.ADD");
51
52
53
54
55
56 public static final EventType GRAPH_REMOVE_EVENT = new EventType("GRAPH.REMOVE");
57
58
59 public static final Time DEFAULT_INITIAL_UPPER_TIME_BOUND = Time.instantiateSI(300.0);
60
61
62 private final OTSSimulatorInterface simulator;
63
64
65 private final String id = UUID.randomUUID().toString();
66
67
68 private final String caption;
69
70
71 private JFreeChart chart;
72
73
74 private Set<DatasetChangeListener> listeners = new LinkedHashSet<>();
75
76
77 private final Duration delay;
78
79
80 private Time updateTime;
81
82
83 private int updates = 0;
84
85
86 private Duration updateInterval;
87
88
89 private SimEventInterface<Duration> updateEvent;
90
91
92
93
94
95
96
97
98 public AbstractPlot(final OTSSimulatorInterface simulator, final String caption, final Duration updateInterval,
99 final Duration delay)
100 {
101 this.simulator = simulator;
102 this.caption = caption;
103 this.updateInterval = updateInterval;
104 this.delay = delay;
105 this.updates = (int) (simulator.getSimulatorTime().si / updateInterval.si);
106 update();
107 }
108
109
110
111
112
113 @SuppressWarnings("methodlength")
114 protected void setChart(final JFreeChart chart)
115 {
116 this.chart = chart;
117
118
119 chart.setTitle(new TextTitle(chart.getTitle().getText(), new Font("SansSerif", java.awt.Font.BOLD, 16)));
120
121
122 chart.getPlot().setBackgroundPaint(Color.LIGHT_GRAY);
123 chart.setBackgroundPaint(Color.WHITE);
124 if (chart.getPlot() instanceof XYPlot)
125 {
126 chart.getXYPlot().setDomainGridlinePaint(Color.WHITE);
127 chart.getXYPlot().setRangeGridlinePaint(Color.WHITE);
128 }
129
130 }
131
132
133
134
135
136
137
138
139
140 public byte[] encodeAsPng(final int width, final int height, final double fontSize) throws IOException
141 {
142
143
144 double baseWidth = width / (fontSize / 16);
145 double baseHeight = height / (fontSize / 16);
146
147 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
148 Graphics2D g2 = image.createGraphics();
149
150 AffineTransform saved = g2.getTransform();
151 g2.transform(AffineTransform.getScaleInstance(width / baseWidth, height / baseHeight));
152 getChart().draw(g2, new Rectangle2D.Double(0, 0, baseWidth, baseHeight), null, null);
153 g2.setTransform(saved);
154 g2.dispose();
155 return ChartUtils.encodeAsPNG(image);
156 }
157
158
159 @Override
160 public final DatasetGroup getGroup()
161 {
162 return null;
163 }
164
165
166 @Override
167 public final void setGroup(final DatasetGroup group)
168 {
169
170 }
171
172
173
174
175
176
177
178
179 public void setAutoBoundDomain(final XYPlot plot)
180 {
181
182 }
183
184
185
186
187
188
189
190
191 public void setAutoBoundRange(final XYPlot plot)
192 {
193
194 }
195
196
197
198
199
200 public abstract GraphType getGraphType();
201
202
203
204
205
206
207
208 public abstract String getStatusLabel(double domainValue, double rangeValue);
209
210
211
212
213
214 protected abstract void increaseTime(Time time);
215
216
217
218
219 public final void notifyPlotChange()
220 {
221 DatasetChangeEvent event = new DatasetChangeEvent(this, this);
222 for (DatasetChangeListener dcl : this.listeners)
223 {
224 dcl.datasetChanged(event);
225 }
226 }
227
228
229
230
231
232 public final JFreeChart getChart()
233 {
234 return this.chart;
235 }
236
237
238 @Override
239 public final String getId()
240 {
241 return this.id;
242 }
243
244
245 @Override
246 public final void addChangeListener(final DatasetChangeListener listener)
247 {
248 this.listeners.add(listener);
249 }
250
251
252 @Override
253 public final void removeChangeListener(final DatasetChangeListener listener)
254 {
255 this.listeners.remove(listener);
256 }
257
258
259
260
261
262 public OTSSimulatorInterface getSimulator()
263 {
264 return this.simulator;
265 }
266
267
268
269
270
271 public final void setUpdateInterval(final Duration interval)
272 {
273 if (this.updateEvent != null)
274 {
275 this.simulator.cancelEvent(this.updateEvent);
276 }
277 this.updates = (int) (this.simulator.getSimulatorTime().si / interval.si);
278 this.updateInterval = interval;
279 this.updateTime = Time.instantiateSI(this.updates * this.updateInterval.si);
280 scheduleNextUpdateEvent();
281 }
282
283
284
285
286
287 public final Time getUpdateTime()
288 {
289 return this.updateTime;
290 }
291
292
293
294
295 protected void update()
296 {
297
298 this.updateTime = this.simulator.getSimulatorAbsTime();
299 increaseTime(this.updateTime.minus(this.delay));
300 notifyPlotChange();
301 scheduleNextUpdateEvent();
302 }
303
304
305
306
307 private void scheduleNextUpdateEvent()
308 {
309 try
310 {
311 this.updates++;
312
313 this.updateEvent = this.simulator.scheduleEventAbsTime(
314 Time.instantiateSI(this.updateInterval.si * this.updates + this.delay.si), this, this, "update", null);
315 }
316 catch (SimRuntimeException exception)
317 {
318 throw new RuntimeException("Unexpected exception while updating plot.", exception);
319 }
320 }
321
322
323
324
325
326 public String getCaption()
327 {
328 return this.caption;
329 }
330
331 }