1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package de.desy.acop.displayers.chart;
24
25 import java.awt.Color;
26 import java.beans.Beans;
27 import java.beans.PropertyChangeSupport;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Map;
31
32 import javax.swing.SwingUtilities;
33
34 import com.cosylab.gui.displayers.CommonDisplayer;
35 import com.cosylab.gui.displayers.Displayer;
36 import com.cosylab.util.CommonException;
37
38 import de.desy.acop.displayers.AcopTrendChart;
39 import de.desy.acop.displayers.selector.SelectorUtilities;
40 import de.desy.acop.displayers.tools.AcopGraphHistoryParameters;
41 import de.desy.acop.displayers.tools.AcopGraphParameters;
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public class AcopTrendChartConsumer extends AcopChartConsumer {
56
57 public static final String SEQUENCE_LENGTH = "sequenceLength";
58 public static final String SEQUENCE_INDEX = "sequenceIndex";
59
60 public static final int MAX_POINTS = 524288;
61
62 private PropertyChangeSupport propertyChangeSupport;
63
64 private int sequenceLength = 0;
65 private int sequenceIndex = 0;
66
67 private int plotLength = 0;
68 private double maxHistoryTimestamp = 0;
69 private HistoryDataConverter historyDataConverter;
70
71 private boolean normalized = false;
72
73 private double[] visibleYData;
74
75
76
77
78
79
80
81 public AcopTrendChartConsumer(AcopTrendChart acopTrendChart, String name) {
82 super(acopTrendChart, name);
83 super.setTrendChart(true);
84 xData = new double[0];
85 yData = new double[0];
86 visibleYData = new double[0];
87 historyDataConverter = new HistoryDataConverter();
88 }
89
90 protected void updateChart() {
91 if (acopChartReorg == null) return;
92
93 Runnable r = new Runnable(){
94 public void run() {
95 trimData();
96 prepareYData();
97
98 synchronized(acopChartReorg) {
99 if (acopChartReorg == null) return;
100 if (displayHandle < 0) {
101 applyParameters();
102 displayHandle = acopChartReorg.getAcop().draw(visibleYData,xData);
103 plotLength = xData.length;
104 }
105 else {
106 if (plotLength == xData.length) {
107 acopChartReorg.getAcop().refreshScreen(visibleYData, displayHandle, arraySize, 0, xData);
108 }
109 else reinitializePlot();
110 }
111 getAcopChart().autoScale();
112 }
113 }
114 };
115 if (SwingUtilities.isEventDispatchThread()) {
116 r.run();
117 } else {
118 SwingUtilities.invokeLater(r);
119 }
120
121 }
122
123
124
125
126 @Override
127 public void setCharacteristics(Map characteristics) {
128
129 if (acopChartReorg == null) {
130 return;
131 }
132
133 Object o1 = null;
134 Object o2 = null;
135
136 o1 = characteristics.get(CommonDisplayer.C_GRAPH_MAX);
137
138 if (o1 == null) {
139 o1 = characteristics.get(CommonDisplayer.C_MAXIMUM);
140 }
141
142 o2 = characteristics.get(CommonDisplayer.C_GRAPH_MIN);
143
144 if (o2 == null) {
145 o2 = characteristics.get(CommonDisplayer.C_MINIMUM);
146 }
147
148 if (o1 != null || o2 != null) {
149 double max = o1 != null ? ((Number)o1).doubleValue()
150 : acopChartReorg.getYRangeMax();
151 double min = o2 != null ? ((Number)o2).doubleValue()
152 : acopChartReorg.getYRangeMin();
153
154 setPreferredYMax(max);
155 setPreferredYMin(min);
156 acopChartReorg.updateYScale(this);
157 }
158
159 o1 = characteristics.get(CommonDisplayer.C_DISPLAY_NAME);
160
161 String newName = (String) o1;
162 if (newName != null && !newName.equals(acopChartReorg.getTitle())) {
163
164
165 acopChartReorg.setTitle(newName);
166 }
167
168 o1 = characteristics.get(Displayer.C_UNITS);
169 if (o1 != null) {
170 acopChartReorg.getAcop().setYAxisLabel((String)o1);
171 }
172
173
174
175 o1 = characteristics.get(Displayer.C_COLOR);
176
177 if (o1 != null) {
178 color = (Color) o1;
179 acopChartReorg.getAcop().setForeground(color);
180 }
181
182 o1 = characteristics.get("xLabels");
183
184 o1 = characteristics.get(CommonDisplayer.C_SEQUENCE_LENGTH);
185 setSequenceLength((Integer) o1);
186
187 if (!Beans.isDesignTime()) {
188 acopChartReorg.updateXScale(this);
189 }
190 acopChartReorg.repaint();
191 }
192
193
194
195
196 @Override
197 public void setDisplayerParameters(AcopGraphParameters displayerParameters) {
198 this.displayerParameters = displayerParameters;
199 this.color = displayerParameters.getColor() != null ? displayerParameters.getColor() : acopChartReorg.getAcop().getForeground();
200 this.width = displayerParameters.getWidth();
201 this.dispalyMode = displayerParameters.getMode() > -1 ? displayerParameters.getMode() : acopChartReorg.getAcop().getDisplayMode();
202 setSequenceLength(SelectorUtilities.getSequenceLength(displayerParameters.getConnectionParameters()));
203 setSequenceIndex(displayerParameters.getArrayIndex());
204 historyDataConverter.useConverter(displayerParameters.getConverter());
205 }
206
207 private long lastLocalTimestamp;
208 private long lastDrawnTimestamp;
209 private long lastNow;
210
211
212
213 @Override
214 public void updateValue(long timestamp, double[] value) throws CommonException {
215 long now = System.currentTimeMillis();
216 if (lastTimestamp != timestamp) {
217 lastTimestamp = timestamp;
218 lastLocalTimestamp = now;
219 } else {
220 timestamp = lastTimestamp + now - lastLocalTimestamp;
221 }
222 if (lastDrawnTimestamp > timestamp) {
223 timestamp = lastDrawnTimestamp + now - lastNow;
224 }
225
226
227 setSequenceLength(value.length);
228 ((AcopTrendChart) acopChartReorg).setLastTimestamp(timestamp/1000.);
229 appendPoint(timestamp/1000., value[getSequenceIndex()]);
230 lastDrawnTimestamp = timestamp;
231 lastNow = now;
232 updateChart();
233 }
234
235
236
237
238 @Override
239 public boolean isTrendChart() {
240 return true;
241 }
242
243
244
245
246 @Override
247 public void setTrendChart(boolean isTrendChart) {
248
249 }
250
251 private void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
252 getPropertyChangeSupport().firePropertyChange(propertyName, oldValue, newValue);
253 }
254
255 private PropertyChangeSupport getPropertyChangeSupport() {
256 if (propertyChangeSupport == null) {
257 propertyChangeSupport = new PropertyChangeSupport(this);
258 }
259 return propertyChangeSupport;
260 }
261
262
263
264
265
266
267
268
269 public void setNormalizedData(boolean normalized) {
270 if (this.normalized == normalized) return;
271 this.normalized = normalized;
272 firePropertyChange("normalizedData", !normalized, normalized);
273 updateChart();
274 }
275
276
277
278
279
280
281 public boolean isNormalizedData() {
282 return normalized;
283 }
284
285 private void trimData() {
286 if (acopChartReorg == null) return;
287 synchronized(acopChartReorg) {
288 if (!((AcopTrendChart) acopChartReorg).isAutoScaleToLiveData()) {
289 int index;
290 double presentTime = ((AcopTrendChart) acopChartReorg).getLastTimestamp();
291 double timeSpan = ((AcopTrendChart) acopChartReorg).getTimeSpan();
292 double startTime = presentTime-timeSpan;
293 for (index = 0; index < xData.length; index++) {
294 if (xData[index] > startTime) {
295 break;
296 }
297 }
298 if (index != 0) {
299 if (index > xData.length) index = xData.length;
300 double[] xDataCopy = Arrays.copyOf(xData, xData.length);
301 double[] yDataCopy = Arrays.copyOf(yData, yData.length);
302 xData = new double[xData.length-index];
303 yData = new double[yData.length-index];
304 System.arraycopy(xDataCopy, index, xData, 0, xDataCopy.length-index);
305 System.arraycopy(yDataCopy, index, yData, 0, yDataCopy.length-index);
306 }
307 }
308 if (xData.length > MAX_POINTS) {
309 int i;
310 for (i = 0; i < xData.length; i++) {
311 if (xData[i] > maxHistoryTimestamp) {
312 i--;
313 break;
314 }
315 }
316 if (i < 0 || i > MAX_POINTS) i = 0;
317 double[] xDataCopy = Arrays.copyOf(xData, xData.length);
318 double[] yDataCopy = Arrays.copyOf(yData, yData.length);
319 xData = new double[MAX_POINTS];
320 yData = new double[MAX_POINTS];
321 System.arraycopy(xDataCopy, 0, xData, 0, i);
322 System.arraycopy(yDataCopy, 0, yData, 0, i);
323 System.arraycopy(xDataCopy, xDataCopy.length-(MAX_POINTS-i), xData, i, MAX_POINTS-i);
324 System.arraycopy(yDataCopy, yDataCopy.length-(MAX_POINTS-i), yData, i, MAX_POINTS-i);
325 acopChartReorg.autoScaleXOnce();
326 }
327 }
328
329 }
330
331 private void prepareYData() {
332 synchronized(acopChartReorg) {
333 if (isNormalizedData()) {
334 visibleYData = new double[yData.length];
335 double min = getPreferredYMin();
336 double scale = (getPreferredYMax() - min)/100.;
337 for (int i = 0; i < visibleYData.length; i++) {
338 visibleYData[i] = (yData[i] - min)/scale;
339 }
340 } else {
341 visibleYData = yData;
342 }
343 }
344 }
345
346 private void mergeData(double[][] historyData) {
347 synchronized(acopChartReorg) {
348 ArrayList<Double> xList = new ArrayList<Double>();
349 ArrayList<Double> yList = new ArrayList<Double>();
350 boolean skip = false;
351 for (int i = 0; i < historyData[0].length; i++) {
352 double t = historyData[0][i];
353 for (int j = 0; j < xList.size(); j++) {
354 if (xList.get(j) >= t) {
355 if (xList.get(j) > t) {
356 xList.add(j, t);
357 yList.add(j, historyData[1][i]);
358 }
359 skip = true;
360 break;
361 }
362 }
363 if (skip) {
364 skip = false;
365 continue;
366 }
367 xList.add(t);
368 yList.add(historyData[1][i]);
369 }
370 for (int i = 0; i < xData.length; i++) {
371 double t = xData[i];
372 for (int j = 0; j < xList.size(); j++) {
373 if (xList.get(j) >= t) {
374 if (xList.get(j) > t) {
375 xList.add(j, t);
376 yList.add(j, yData[i]);
377 }
378 skip = true;
379 break;
380 }
381 }
382 if (skip) {
383 skip = false;
384 continue;
385 }
386 xList.add(t);
387 yList.add(yData[i]);
388 }
389 if (historyData[0].length > 0) maxHistoryTimestamp = historyData[0][historyData[0].length-1];
390 xData = new double[xList.size()];
391 yData = new double[yList.size()];
392 for (int i = 0; i < xList.size(); i++) {
393 xData[i] = xList.get(i);
394 yData[i] = yList.get(i);
395 }
396 }
397 }
398
399 private void appendPoint(double x, double y) {
400 synchronized (acopChartReorg) {
401 double[] xDataCopy = Arrays.copyOf(xData, xData.length);
402 double[] yDataCopy = Arrays.copyOf(yData, yData.length);
403 xData = new double[xData.length+1];
404 yData = new double[yData.length+1];
405 System.arraycopy(xDataCopy, 0, xData, 0, xDataCopy.length);
406 System.arraycopy(yDataCopy, 0, yData, 0, yDataCopy.length);
407 xData[xData.length-1] = x;
408 yData[yData.length-1] = y;
409 }
410 }
411
412
413
414
415 @Override
416 public double[][] dumpData() {
417 double[][] clone = new double[2][xData.length];
418 System.arraycopy(xData, 0, clone[0] ,0,xData.length);
419 System.arraycopy(yData, 0, clone[1] ,0,xData.length);
420 return clone;
421 }
422
423
424
425
426
427 public int getSequenceIndex() {
428 return sequenceIndex;
429 }
430
431
432
433
434
435 public void setSequenceIndex(int sequenceIndex) {
436 if (this.sequenceIndex == sequenceIndex) return;
437 int oldIndex = getSequenceIndex();
438 if (sequenceIndex >= getSequenceLength() || sequenceIndex < 0) {
439 sequenceIndex = 0;
440 }
441 this.sequenceIndex = sequenceIndex;
442 firePropertyChange(SEQUENCE_INDEX, oldIndex, getSequenceIndex());
443 }
444
445
446
447
448
449 public int getSequenceLength() {
450 return sequenceLength;
451 }
452
453
454
455
456
457 public void setSequenceLength(int sequenceLength) {
458 if (this.sequenceLength == sequenceLength) return;
459 int oldLength = getSequenceLength();
460 this.sequenceLength = sequenceLength;
461 if (getSequenceIndex() >= getSequenceLength()) {
462 setSequenceIndex(0);
463 }
464 firePropertyChange(SEQUENCE_LENGTH, oldLength, getSequenceLength());
465 }
466
467
468
469
470
471
472 public HistoryParameters getHistoryParameters() {
473 AcopGraphParameters parameters = getDisplayerParameters();
474 if (parameters instanceof AcopGraphHistoryParameters) return ((AcopGraphHistoryParameters) parameters).getHistoryParameters();
475 return null;
476 }
477
478
479
480
481
482
483
484
485 public void loadHistoryData(double[][] historyData) {
486 double[] convertedHistoryData = historyDataConverter.convertHistoryData(historyData[1]);
487 historyData[1] = convertedHistoryData;
488 mergeData(historyData);
489 updateChart();
490 }
491
492 }