Changed package name from altosui to AltosUI
[fw/altos] / altosui / AltosGraphTime.java
1
2 // Copyright (c) 2010 Anthony Towns
3 // GPL v2 or later
4
5 package AltosUI;
6
7 import java.lang.*;
8 import java.io.*;
9 import java.util.concurrent.*;
10 import java.util.*;
11 import java.text.*;
12 import java.awt.Color;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import org.altusmetrum.AltosLib.*;
16
17 import org.jfree.chart.ChartUtilities;
18 import org.jfree.chart.JFreeChart;
19 import org.jfree.chart.axis.AxisLocation;
20 import org.jfree.chart.axis.NumberAxis;
21 import org.jfree.chart.labels.StandardXYToolTipGenerator;
22 import org.jfree.chart.plot.PlotOrientation;
23 import org.jfree.chart.plot.XYPlot;
24 import org.jfree.chart.plot.ValueMarker;
25 import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
26 import org.jfree.chart.renderer.xy.XYItemRenderer;
27 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
28 import org.jfree.data.xy.XYSeries;
29 import org.jfree.data.xy.XYSeriesCollection;
30 import org.jfree.ui.RectangleAnchor;
31 import org.jfree.ui.TextAnchor;
32
33 class AltosGraphTime extends AltosGraph {
34     static interface Element {
35         void attachGraph(AltosGraphTime g);
36         void gotTimeData(double time, AltosDataPoint d);
37         void addToPlot(AltosGraphTime g, XYPlot plot);
38     }
39
40     static class TimeAxis implements Element {
41         private int axis;
42         private Color color;
43         private String label;
44         private AxisLocation locn;
45         private double min_y = Double.NaN;
46
47         public TimeAxis(int axis, String label, Color color, AxisLocation locn)
48         {
49             this.axis = axis;
50             this.color = color;
51             this.label = label;
52             this.locn = locn;
53         }
54
55         public void setLowerBound(double min_y) {
56             this.min_y = min_y;
57         }
58
59         public void attachGraph(AltosGraphTime g) { return; }
60         public void gotTimeData(double time, AltosDataPoint d) { return; }
61
62         public void addToPlot(AltosGraphTime g, XYPlot plot) {
63             NumberAxis numAxis = new NumberAxis(label);
64             if (!Double.isNaN(min_y))
65                 numAxis.setLowerBound(min_y);
66             plot.setRangeAxis(axis, numAxis);
67             plot.setRangeAxisLocation(axis, locn);
68             numAxis.setLabelPaint(color);
69             numAxis.setTickLabelPaint(color);
70             numAxis.setAutoRangeIncludesZero(false);
71         }
72     }
73
74     abstract static class TimeSeries implements Element {
75         protected XYSeries series;
76         private String axisName;
77         private Color color;
78
79         public TimeSeries(String axisName, String label, Color color) {
80             this.series = new XYSeries(label);
81             this.axisName = axisName;
82             this.color = color;
83         }
84
85         public void attachGraph(AltosGraphTime g) {
86             g.setAxis(this, axisName, color);
87         }
88         abstract public void gotTimeData(double time, AltosDataPoint d);
89
90         public void addToPlot(AltosGraphTime g, XYPlot plot) {
91             XYSeriesCollection dataset = new XYSeriesCollection();
92             dataset.addSeries(this.series);
93
94             XYItemRenderer renderer = new StandardXYItemRenderer();
95             renderer.setSeriesPaint(0, color);
96
97             int dataNum = g.getDataNum(this);
98             int axisNum = g.getAxisNum(this);
99
100             plot.setDataset(dataNum, dataset);
101             plot.mapDatasetToRangeAxis(dataNum, axisNum);
102             plot.setRenderer(dataNum, renderer);
103         }
104     }
105
106     static class StateMarker implements Element {
107         private LinkedList<Double> times = new LinkedList<Double>();
108         private String name;
109         private int state;
110         private int prev_state = Altos.ao_flight_startup;
111
112         StateMarker(int state, String name) {
113             this.state = state;
114             this.name = name;
115         }
116
117         public void attachGraph(AltosGraphTime g) { return; }
118         public void gotTimeData(double time, AltosDataPoint d) {
119             if (prev_state != state && d.state() == state)
120                 times.add(time);
121             prev_state = d.state();
122         }
123
124         public void addToPlot(AltosGraphTime g, XYPlot plot) {
125             for (double time : times) {
126                 ValueMarker m = new ValueMarker(time);
127                 m.setLabel(name);
128                 m.setLabelAnchor(RectangleAnchor.TOP_RIGHT);
129                 m.setLabelTextAnchor(TextAnchor.TOP_LEFT);
130                 plot.addDomainMarker(m);
131             }
132         }
133     }
134
135     private String callsign = null;
136     private Integer serial = null;
137     private Integer flight = null; 
138
139     private ArrayList<Element> elements;
140     private HashMap<String,Integer> axes;
141     private HashMap<Element,Integer> datasets;
142     private ArrayList<Integer> datasetAxis;
143
144     public AltosGraphTime(String title) {
145         this.filename = title.toLowerCase().replaceAll("[^a-z0-9]","_")+".png";
146         this.title = title;
147         this.elements = new ArrayList<Element>();
148         this.axes = new HashMap<String,Integer>();
149         this.datasets = new HashMap<Element,Integer>();
150         this.datasetAxis = new ArrayList<Integer>();
151     }
152
153     public AltosGraphTime addElement(Element e) {
154         e.attachGraph(this);
155         elements.add(e);
156         return this;
157     }
158
159     public void setAxis(Element ds, String axisName, Color color) {
160         Integer axisNum = axes.get(axisName);
161         int dsNum = datasetAxis.size();
162         if (axisNum == null) {
163             axisNum = newAxis(axisName, color);
164         }
165         datasets.put(ds, dsNum);
166         datasetAxis.add(axisNum);
167     }
168
169     public int getAxisNum(Element ds) {
170         return datasetAxis.get( datasets.get(ds) ).intValue();
171     }
172     public int getDataNum(Element ds) {
173         return datasets.get(ds).intValue();
174     }
175
176     private Integer newAxis(String name, Color color) {
177         int cnt = axes.size();
178         AxisLocation locn = AxisLocation.BOTTOM_OR_LEFT;
179         if (cnt > 0) {
180             locn = AxisLocation.TOP_OR_RIGHT;
181         }
182         Integer res = new Integer(cnt);
183         axes.put(name, res);
184         this.addElement(new TimeAxis(cnt, name, color, locn));
185         return res;
186     }
187
188     public void addData(AltosDataPoint d) {
189         double time = d.time();
190         for (Element e : elements) {
191             e.gotTimeData(time, d);
192         }
193         if (callsign == null) callsign = d.callsign();
194         if (serial == null) serial = new Integer(d.serial());
195         if (flight == null) flight = new Integer(d.flight());
196     }
197
198     public JFreeChart createChart() {
199         NumberAxis xAxis = new NumberAxis("Time (s)");
200         xAxis.setAutoRangeIncludesZero(false);
201         XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
202         XYPlot plot = new XYPlot();
203         plot.setDomainAxis(xAxis);
204         plot.setRenderer(renderer);
205         plot.setOrientation(PlotOrientation.VERTICAL);
206
207         if (serial != null && flight != null) {
208             title = serial + "/" + flight + ": " + title;
209         }
210         if (callsign != null) {
211             title = callsign + " - " + title;
212         }
213
214         renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
215         JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
216                                 plot, true);
217         ChartUtilities.applyCurrentTheme(chart);
218
219         plot.setDomainPannable(true);
220         plot.setRangePannable(true);
221    
222         for (Element e : elements) {
223             e.addToPlot(this, plot);
224         }
225
226         return chart;
227     }
228
229     public void toPNG() throws java.io.IOException {
230         if (axes.size() > 1) {
231             toPNG(800, 500);
232         } else {
233             toPNG(300, 500);
234         }
235     }
236 }