1 package nl.tudelft.simulation.dsol.swing.charts.xy;
2
3 import java.util.ArrayList;
4 import java.util.Calendar;
5 import java.util.Iterator;
6 import java.util.List;
7
8 import org.djutils.event.Event;
9 import org.djutils.event.EventListener;
10 import org.djutils.event.EventType;
11 import org.djutils.event.TimedEvent;
12 import org.djutils.logger.CategoryLogger;
13 import org.jfree.data.general.AbstractDataset;
14
15 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
16 import nl.tudelft.simulation.language.filters.FilterInterface;
17 import nl.tudelft.simulation.language.filters.ZeroFilter;
18
19
20
21
22
23
24
25
26
27
28
29
30
31 public class XYSeries extends AbstractDataset implements EventListener
32 {
33
34 private static final long serialVersionUID = 1L;
35
36
37 public static final EventType LOWER_RANGE_EVENT = new EventType("LOWER_RANGE_EVENT");
38
39
40 public static final EventType UPPER_RANGE_EVENT = new EventType("UPPER_RANGE_EVENT");
41
42
43 private String name = null;
44
45
46 protected List<double[]> entries = new ArrayList<double[]>();
47
48
49 private final SimulatorInterface<?> simulator;
50
51
52 private short axisType = XYChart.XLINEAR_YLINEAR;
53
54
55 private FilterInterface filter = new ZeroFilter();
56
57
58 private final double PERIOD;
59
60
61
62
63
64
65
66
67 public XYSeries(final String name, final SimulatorInterface<?> simulator, final short axisType, final double period)
68 {
69 this.axisType = axisType;
70 this.name = name;
71 this.simulator = simulator;
72 this.PERIOD = period;
73 this.fireDatasetChanged();
74 }
75
76
77 @Override
78 public synchronized void notify(final Event event)
79 {
80 Number timeStamp;
81 if (event instanceof TimedEvent)
82 {
83 TimedEvent<?> timedEvent = (TimedEvent<?>) event;
84 if (timedEvent.getTimeStamp() instanceof Number)
85 {
86 timeStamp = (Number) timedEvent.getTimeStamp();
87 }
88 else if (timedEvent.getTimeStamp() instanceof Calendar)
89 {
90 timeStamp = ((Calendar) timedEvent.getTimeStamp()).getTimeInMillis();
91 }
92 else
93 {
94 throw new IllegalArgumentException("TimedEvent has timestamp other than Number or Calendar");
95 }
96 }
97 else
98 {
99 timeStamp = (Number) this.simulator.getSimulatorTime();
100 }
101
102
103 if (this.axisType == XYChart.XLOGARITHMIC_YLINEAR || this.axisType == XYChart.XLOGARITHMIC_YLOGARITHMIC)
104 {
105 if (timeStamp.doubleValue() <= 0.0)
106 {
107 CategoryLogger.always().warn("notify: refusing xvalue of {} on logrithmic chart", event);
108 return;
109 }
110 }
111 if (this.axisType == XYChart.XLINEAR_YLOGARITHMIC || this.axisType == XYChart.XLOGARITHMIC_YLOGARITHMIC)
112 {
113 if (((Number) event.getContent()).doubleValue() <= 0.0)
114 {
115 CategoryLogger.always().warn("notify: refusing yValue of {} on logrithmic chart", event);
116 return;
117 }
118 }
119 double[] point = {timeStamp.doubleValue(), ((Number) event.getContent()).doubleValue()};
120 if (!this.filter.accept(point))
121 {
122 return;
123 }
124 this.entries.add(point);
125 if (!(Double.isInfinite(this.PERIOD)))
126 {
127 double lowerBounds = point[0] - this.PERIOD;
128 for (Iterator<double[]> i = this.entries.iterator(); i.hasNext();)
129 {
130 double[] entry = i.next();
131 if (entry[0] < lowerBounds)
132 {
133 i.remove();
134 }
135 else
136 {
137 break;
138 }
139 }
140 }
141 this.fireDatasetChanged();
142 }
143
144
145
146
147
148 public int getItemCount()
149 {
150 return this.entries.size();
151 }
152
153
154
155
156
157
158 public synchronized double getXValue(int item)
159 {
160 item = Math.min(item, this.entries.size() - 1);
161 return this.entries.get(item)[0];
162 }
163
164
165
166
167
168
169 public double getYValue(int item)
170 {
171 item = Math.min(item, this.entries.size() - 1);
172 return this.entries.get(item)[1];
173 }
174
175
176
177
178
179 public String getSeriesName()
180 {
181 return this.name;
182 }
183
184
185
186
187
188 public void setFilter(final FilterInterface filter)
189 {
190 this.filter = filter;
191 }
192 }