2 // Copyright (c) 2010 Anthony Towns
9 import java.util.ArrayList;
10 import java.util.HashMap;
11 import org.jfree.chart.ChartUtilities;
12 import org.jfree.chart.JFreeChart;
13 import org.jfree.chart.axis.AxisLocation;
14 import org.jfree.chart.axis.NumberAxis;
15 import org.jfree.chart.labels.StandardXYToolTipGenerator;
16 import org.jfree.chart.plot.PlotOrientation;
17 import org.jfree.chart.plot.XYPlot;
18 import org.jfree.chart.plot.ValueMarker;
19 import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
20 import org.jfree.chart.renderer.xy.XYItemRenderer;
21 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
22 import org.jfree.data.xy.XYSeries;
23 import org.jfree.data.xy.XYSeriesCollection;
24 import org.jfree.ui.RectangleAnchor;
25 import org.jfree.ui.TextAnchor;
27 class AltosGraphTime extends AltosGraph {
28 static interface Element {
29 void attachGraph(AltosGraphTime g);
30 void gotTimeData(double time, AltosDataPoint d);
31 void addToPlot(AltosGraphTime g, XYPlot plot);
34 static class TimeAxis implements Element {
38 private AxisLocation locn;
39 private double min_y = Double.NaN;
41 public TimeAxis(int axis, String label, Color color, AxisLocation locn)
49 public void setLowerBound(double min_y) {
53 public void attachGraph(AltosGraphTime g) { return; }
54 public void gotTimeData(double time, AltosDataPoint d) { return; }
56 public void addToPlot(AltosGraphTime g, XYPlot plot) {
57 NumberAxis numAxis = new NumberAxis(label);
58 if (!Double.isNaN(min_y))
59 numAxis.setLowerBound(min_y);
60 plot.setRangeAxis(axis, numAxis);
61 plot.setRangeAxisLocation(axis, locn);
62 numAxis.setLabelPaint(color);
63 numAxis.setTickLabelPaint(color);
64 numAxis.setAutoRangeIncludesZero(false);
68 abstract static class TimeSeries implements Element {
69 protected XYSeries series;
70 private String axisName;
73 public TimeSeries(String axisName, String label, Color color) {
74 this.series = new XYSeries(label);
75 this.axisName = axisName;
79 public void attachGraph(AltosGraphTime g) {
80 g.setAxis(this, axisName, color);
82 abstract public void gotTimeData(double time, AltosDataPoint d);
84 public void addToPlot(AltosGraphTime g, XYPlot plot) {
85 XYSeriesCollection dataset = new XYSeriesCollection();
86 dataset.addSeries(this.series);
88 XYItemRenderer renderer = new StandardXYItemRenderer();
89 renderer.setSeriesPaint(0, color);
91 int dataNum = g.getDataNum(this);
92 int axisNum = g.getAxisNum(this);
94 plot.setDataset(dataNum, dataset);
95 plot.mapDatasetToRangeAxis(dataNum, axisNum);
96 plot.setRenderer(dataNum, renderer);
100 static class StateMarker implements Element {
101 private LinkedList<Double> times = new LinkedList<Double>();
104 private int prev_state = Altos.ao_flight_startup;
106 StateMarker(int state, String name) {
111 public void attachGraph(AltosGraphTime g) { return; }
112 public void gotTimeData(double time, AltosDataPoint d) {
113 if (prev_state != state && d.state() == state)
115 prev_state = d.state();
118 public void addToPlot(AltosGraphTime g, XYPlot plot) {
119 for (double time : times) {
120 ValueMarker m = new ValueMarker(time);
122 m.setLabelAnchor(RectangleAnchor.TOP_RIGHT);
123 m.setLabelTextAnchor(TextAnchor.TOP_LEFT);
124 plot.addDomainMarker(m);
129 private String callsign = null;
130 private Integer serial = null;
131 private Integer flight = null;
133 private ArrayList<Element> elements;
134 private HashMap<String,Integer> axes;
135 private HashMap<Element,Integer> datasets;
136 private ArrayList<Integer> datasetAxis;
138 public AltosGraphTime(String title) {
139 this.filename = title.toLowerCase().replaceAll("[^a-z0-9]","_")+".png";
141 this.elements = new ArrayList<Element>();
142 this.axes = new HashMap<String,Integer>();
143 this.datasets = new HashMap<Element,Integer>();
144 this.datasetAxis = new ArrayList<Integer>();
147 public AltosGraphTime addElement(Element e) {
153 public void setAxis(Element ds, String axisName, Color color) {
154 Integer axisNum = axes.get(axisName);
155 int dsNum = datasetAxis.size();
156 if (axisNum == null) {
157 axisNum = newAxis(axisName, color);
159 datasets.put(ds, dsNum);
160 datasetAxis.add(axisNum);
163 public int getAxisNum(Element ds) {
164 return datasetAxis.get( datasets.get(ds) ).intValue();
166 public int getDataNum(Element ds) {
167 return datasets.get(ds).intValue();
170 private Integer newAxis(String name, Color color) {
171 int cnt = axes.size();
172 AxisLocation locn = AxisLocation.BOTTOM_OR_LEFT;
174 locn = AxisLocation.TOP_OR_RIGHT;
176 Integer res = new Integer(cnt);
178 this.addElement(new TimeAxis(cnt, name, color, locn));
182 public void addData(AltosDataPoint d) {
183 double time = d.time();
184 for (Element e : elements) {
185 e.gotTimeData(time, d);
187 if (callsign == null) callsign = d.callsign();
188 if (serial == null) serial = new Integer(d.serial());
189 if (flight == null) flight = new Integer(d.flight());
192 public JFreeChart createChart() {
193 NumberAxis xAxis = new NumberAxis("Time (s)");
194 xAxis.setAutoRangeIncludesZero(false);
195 XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
196 XYPlot plot = new XYPlot();
197 plot.setDomainAxis(xAxis);
198 plot.setRenderer(renderer);
199 plot.setOrientation(PlotOrientation.VERTICAL);
201 if (serial != null && flight != null) {
202 title = serial + "/" + flight + ": " + title;
204 if (callsign != null) {
205 title = callsign + " - " + title;
208 renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
209 JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
211 ChartUtilities.applyCurrentTheme(chart);
213 plot.setDomainPannable(true);
214 plot.setRangePannable(true);
216 for (Element e : elements) {
217 e.addToPlot(this, plot);
223 public void toPNG() throws java.io.IOException {
224 if (axes.size() > 1) {