Move the android package from the main trunk/src directory to trunk/android/src.
[debian/openrocket] / android / src / net / sf / openrocket / android / simulation / SimulationChart.java
1 /**\r
2  * Copyright (C) 2009, 2010 SC 4ViewSoft SRL\r
3  *  \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *  \r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *  \r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 package net.sf.openrocket.android.simulation;\r
17 \r
18 import java.util.List;\r
19 \r
20 import net.sf.openrocket.simulation.FlightDataBranch;\r
21 import net.sf.openrocket.simulation.FlightDataType;\r
22 import net.sf.openrocket.simulation.FlightEvent;\r
23 \r
24 import org.achartengine.ChartFactory;\r
25 import org.achartengine.chart.LineChart;\r
26 import org.achartengine.chart.PointStyle;\r
27 import org.achartengine.chart.XYChart;\r
28 import org.achartengine.model.XYMultipleSeriesDataset;\r
29 import org.achartengine.model.XYSeries;\r
30 import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
31 import org.achartengine.renderer.XYSeriesRenderer;\r
32 \r
33 import android.content.Context;\r
34 import android.content.Intent;\r
35 import android.graphics.Color;\r
36 import android.graphics.Paint.Align;\r
37 import android.util.Log;\r
38 \r
39 /**\r
40  * Multiple temperature demo chart.\r
41  */\r
42 public class SimulationChart {\r
43         \r
44         private final static String TAG = "SimulationChart";\r
45 \r
46         private FlightDataBranch flightDataBranch;\r
47         private FlightDataType series1;\r
48         private FlightDataType series2;\r
49         private final FlightDataType time = FlightDataType.TYPE_TIME;\r
50         private List<FlightEvent> flightEvents;\r
51 \r
52         // Define 4 different colors and point styles to use for the series.\r
53         // For now only 2 series are supported though.\r
54         private final static int[] colors = new int[] { Color.BLUE, Color.YELLOW, Color.GREEN, Color.RED };\r
55         private final static PointStyle[] styles = new PointStyle[] { PointStyle.CIRCLE, PointStyle.DIAMOND,\r
56                 PointStyle.TRIANGLE, PointStyle.SQUARE };\r
57 \r
58         /**\r
59          * @param flightDataBranch the flightDataBranch to set\r
60          */\r
61         public void setFlightDataBranch(FlightDataBranch flightDataBranch) {\r
62                 this.flightDataBranch = flightDataBranch;\r
63         }\r
64 \r
65         /**\r
66          * @param series1 the series1 to set\r
67          */\r
68         public void setSeries1(FlightDataType series1) {\r
69                 this.series1 = series1;\r
70         }\r
71 \r
72         /**\r
73          * @param series2 the series2 to set\r
74          */\r
75         public void setSeries2(FlightDataType series2) {\r
76                 this.series2 = series2;\r
77         }\r
78 \r
79         /**\r
80          * @param flightEvents the flightEvents to set\r
81          */\r
82         public void setFlightEvents(List<FlightEvent> flightEvents) {\r
83                 this.flightEvents = flightEvents;\r
84         }\r
85 \r
86         private static String formatFlightDataTypeAxisLabel( FlightDataType fdt ) {\r
87                 return fdt.getName() + " (" + fdt.getUnitGroup().getDefaultUnit().toString() + ")";\r
88         }\r
89 \r
90         /**\r
91          * Executes the chart demo.\r
92          * \r
93          * @param context the context\r
94          * @return the built intent\r
95          */\r
96         public Intent execute(Context context) {\r
97 \r
98                 /*\r
99                  * TODO -\r
100                  * Figure out why you can pan all over the place even where there are no visible points.\r
101                  */\r
102                 int seriesCount = 2;\r
103                 // if the same series is selected twice, only plot it once.\r
104                 if ( series1 == series2 ) {\r
105                         seriesCount = 1;\r
106                 }\r
107 \r
108                 XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer(seriesCount);\r
109 \r
110                 renderer.setAxisTitleTextSize(16);\r
111                 renderer.setChartTitleTextSize(20);\r
112                 renderer.setLabelsTextSize(15);\r
113                 renderer.setLegendTextSize(15);\r
114                 renderer.setPointSize(5f);\r
115                 renderer.setXLabels(10);\r
116                 renderer.setYLabels(10);\r
117                 renderer.setShowGrid(true);\r
118                 renderer.setZoomButtonsVisible(true);\r
119                 renderer.setChartTitle("Simulation");\r
120 \r
121                 renderer.setMargins(new int[] { 50, 30, 0, 20 });\r
122                 {\r
123                         for (int i = 0; i < seriesCount; i++) {\r
124                                 XYSeriesRenderer r = new XYSeriesRenderer();\r
125                                 r.setColor(colors[i]);\r
126                                 r.setPointStyle(styles[i]);\r
127                                 r.setFillPoints(true);\r
128                                 renderer.addSeriesRenderer(r);\r
129                                 // setting the YAximMin to 0 locks the origins.\r
130                                 renderer.setYAxisMin(0.0, i);\r
131                         }\r
132                 }\r
133 \r
134                 renderer.setXTitle(formatFlightDataTypeAxisLabel(time));\r
135                 renderer.setXLabelsAlign(Align.RIGHT);\r
136 \r
137                 renderer.setYTitle(formatFlightDataTypeAxisLabel(series1),0);\r
138                 renderer.setYLabelsAlign(Align.RIGHT,0);\r
139 \r
140                 if ( seriesCount > 1 ) {\r
141                         renderer.setYTitle(formatFlightDataTypeAxisLabel(series2), 1);\r
142                         renderer.setYAxisAlign(Align.RIGHT, 1);\r
143                         renderer.setYLabelsAlign(Align.LEFT, 1);\r
144                 }\r
145 \r
146                 renderer.setAxesColor(Color.LTGRAY);\r
147                 renderer.setLabelsColor(Color.LTGRAY);\r
148 \r
149                 XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();\r
150 \r
151                 List<Double> timevalues = flightDataBranch.get(time);\r
152                 List<Double> series1values = flightDataBranch.get(series1);\r
153 \r
154                 // compute the axis limits using timevalues and series1values.\r
155                 double xmin = 0;\r
156                 double ymin = 0;\r
157                 renderer.setXAxisMin(xmin);\r
158                 renderer.setYAxisMin(ymin);\r
159 \r
160                 double ymax = computeMaxValueWithPadding( series1values );\r
161                 double xmax = Math.ceil( timevalues.get( timevalues.size()-1));\r
162                 \r
163                 Log.d(TAG,"ymax = " + ymax);\r
164                 renderer.setXAxisMax(xmax);\r
165                 renderer.setYAxisMax(ymax);\r
166 \r
167                 // These configurations don't really work well just now.\r
168                 //renderer.setPanLimits(new double[] { xmin, xmax, ymin, ymax });\r
169                 //renderer.setZoomLimits(new double[] { xmin, xmax, ymin, ymax });\r
170 \r
171                 // Add first series\r
172                 addXYSeries(dataset, series1.getName(), timevalues, series1values, 0);\r
173 \r
174                 if ( seriesCount > 1 ) {\r
175                         // Add second series\r
176                         addXYSeries(dataset, series2.getName(), timevalues, flightDataBranch.get(series2), 1);\r
177                 }\r
178                 Intent intent = getLineChartIntent(context, dataset, renderer,"Simulation");\r
179                 return intent;\r
180         }\r
181 \r
182         private static void addXYSeries(XYMultipleSeriesDataset dataset, String titles, List<Double> xValues, List<Double> yValues, int scale) {\r
183                 XYSeries series = new XYSeries(titles, scale);\r
184                 int datasize = xValues.size();\r
185                 for( int i = 0; i<datasize; i++ ) {\r
186                         series.add(xValues.get(i), yValues.get(i));\r
187                 }\r
188                 dataset.addSeries(series);\r
189 \r
190         }\r
191 \r
192         private static Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
193                         XYMultipleSeriesRenderer renderer, String activityTitle) {\r
194                 //                  checkParameters(dataset, renderer);\r
195                 Intent intent = new Intent(context, GraphicalActivity.class);\r
196                 XYChart chart = new LineChart(dataset, renderer);\r
197                 intent.putExtra(ChartFactory.CHART, chart);\r
198                 intent.putExtra(ChartFactory.TITLE, activityTitle);\r
199                 return intent;\r
200         }\r
201 \r
202         private static double computeMaxValueWithPadding( List<Double> list ) {\r
203                 double max = list.get(0);\r
204                 for( double v : list ) {\r
205                         if ( v > max ) {\r
206                                 max = v;\r
207                         }\r
208                 }\r
209                 if ( max <= 0 ) return 1.0;\r
210 \r
211                 // Do something stupid.\r
212                 // return:\r
213                 //  10 if max <= 10\r
214                 //  next 10 if 10 < max < 1000\r
215                 //  next 100 if 1000 < max < 10,000\r
216                 //  next 1000 if max >= 10,000\r
217                 double numdigits = Math.floor(Math.log10(max));\r
218                 \r
219                 if ( numdigits <= 1.0 ) {\r
220                         return 10.0;\r
221                 } else if ( numdigits <= 3.0 ) {\r
222                         return 10.0 * ( Math.ceil( max/10.0));\r
223                 } else if ( numdigits <= 4.0 ) {\r
224                         return 100.0 * ( Math.ceil( max/ 100.0) );\r
225                 } else {\r
226                         return 1000.0 * ( Math.ceil( max / 1000.0 ));\r
227                 }\r
228                 \r
229         }\r
230         \r
231 }\r