Wired up computation of CP, CG, liftoff weight and stability to the configuration...
[debian/openrocket] / android / src / net / sf / openrocket / android / rocket / OpenRocketViewer.java
1 package net.sf.openrocket.android.rocket;\r
2 \r
3 \r
4 import java.io.File;\r
5 \r
6 import net.sf.openrocket.R;\r
7 import net.sf.openrocket.aerodynamics.AerodynamicCalculator;\r
8 import net.sf.openrocket.aerodynamics.BarrowmanCalculator;\r
9 import net.sf.openrocket.aerodynamics.FlightConditions;\r
10 import net.sf.openrocket.aerodynamics.WarningSet;\r
11 import net.sf.openrocket.android.Application;\r
12 import net.sf.openrocket.android.PreferencesActivity;\r
13 import net.sf.openrocket.android.motor.MotorHierarchicalBrowser;\r
14 import net.sf.openrocket.android.rocket.RocketComponentTreeAdapter.RocketComponentWithId;\r
15 import net.sf.openrocket.android.simulation.SimulationViewer;\r
16 import net.sf.openrocket.document.OpenRocketDocument;\r
17 import net.sf.openrocket.document.Simulation;\r
18 import net.sf.openrocket.masscalc.BasicMassCalculator;\r
19 import net.sf.openrocket.masscalc.MassCalculator;\r
20 import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;\r
21 import net.sf.openrocket.rocketcomponent.Configuration;\r
22 import net.sf.openrocket.rocketcomponent.Rocket;\r
23 import net.sf.openrocket.rocketcomponent.RocketComponent;\r
24 import net.sf.openrocket.rocketcomponent.RocketUtils;\r
25 import net.sf.openrocket.unit.Unit;\r
26 import net.sf.openrocket.unit.UnitGroup;\r
27 import net.sf.openrocket.util.Coordinate;\r
28 import pl.polidea.treeview.InMemoryTreeStateManager;\r
29 import pl.polidea.treeview.TreeBuilder;\r
30 import pl.polidea.treeview.TreeStateManager;\r
31 import pl.polidea.treeview.TreeViewList;\r
32 import android.app.Activity;\r
33 import android.app.ProgressDialog;\r
34 import android.content.Intent;\r
35 import android.content.SharedPreferences;\r
36 import android.net.Uri;\r
37 import android.os.Bundle;\r
38 import android.preference.PreferenceManager;\r
39 import android.util.Log;\r
40 import android.view.LayoutInflater;\r
41 import android.view.Menu;\r
42 import android.view.MenuInflater;\r
43 import android.view.MenuItem;\r
44 import android.view.View;\r
45 import android.view.ViewGroup;\r
46 import android.widget.AdapterView;\r
47 import android.widget.AdapterView.OnItemClickListener;\r
48 import android.widget.ArrayAdapter;\r
49 import android.widget.ListAdapter;\r
50 import android.widget.ListView;\r
51 import android.widget.Spinner;\r
52 import android.widget.TabHost;\r
53 import android.widget.TextView;\r
54 \r
55 public class OpenRocketViewer extends Activity\r
56 implements SharedPreferences.OnSharedPreferenceChangeListener\r
57 {\r
58 \r
59         private static final String TAG = "OpenRocketViewer";\r
60 \r
61         private ProgressDialog progress;\r
62 \r
63         private Spinner configurationSpinner;\r
64         private TreeViewList componentTree;\r
65         private ListView simulationList;\r
66         \r
67         /* Calculation of CP and CG */\r
68         private AerodynamicCalculator aerodynamicCalculator = new BarrowmanCalculator();\r
69         private MassCalculator massCalculator  = new BasicMassCalculator();\r
70 \r
71         OpenRocketDocument rocketDocument;\r
72         Configuration rocketConfiguration;\r
73 \r
74         private Application app;\r
75 \r
76         private final static int PICK_ORK_FILE_RESULT = 1;\r
77 \r
78         /* (non-Javadoc)\r
79          * @see android.app.Activity#onCreate(android.os.Bundle)\r
80          */\r
81         @Override\r
82         protected void onCreate(Bundle savedInstanceState) {\r
83                 super.onCreate(savedInstanceState);\r
84 \r
85                 Log.d(TAG,"In onCreate");\r
86 \r
87                 app = (Application) this.getApplication();\r
88 \r
89                 setContentView(R.layout.openrocketviewer);\r
90 \r
91                 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);\r
92                 prefs.registerOnSharedPreferenceChangeListener(this);\r
93 \r
94                 TabHost tabs=(TabHost)findViewById(R.id.openrocketviewerTabHost);\r
95 \r
96                 tabs.setup();\r
97 \r
98                 TabHost.TabSpec spec=tabs.newTabSpec("tag1");\r
99 \r
100                 spec.setContent(R.id.openrocketviewerOverview);\r
101                 spec.setIndicator("Overview");\r
102                 tabs.addTab(spec);\r
103 \r
104                 spec=tabs.newTabSpec("tag2");\r
105                 spec.setContent(R.id.openrocketviewerComponentTree);\r
106                 spec.setIndicator("Components");\r
107                 tabs.addTab(spec);      \r
108 \r
109                 spec=tabs.newTabSpec("tag3");\r
110                 spec.setContent(R.id.openrocketviewerSimulationList);\r
111                 spec.setIndicator("Simulations");\r
112                 tabs.addTab(spec);      \r
113 \r
114                 configurationSpinner = (Spinner) findViewById(R.id.openrocketviewerConfigurationSpinner);\r
115                 componentTree = (TreeViewList) findViewById(R.id.openrocketviewerComponentTree);\r
116                 simulationList = (ListView) findViewById(R.id.openrocketviewerSimulationList);\r
117 \r
118                 Intent i = getIntent();\r
119                 Uri file = i.getData();\r
120 \r
121                 if ( file == null ) {\r
122                         Intent intent = new Intent(Intent.ACTION_GET_CONTENT);\r
123                         intent.setType("file/*");\r
124                         startActivityForResult(intent,PICK_ORK_FILE_RESULT);\r
125 \r
126                 } else {\r
127                         loadOrkFile(file);\r
128                 }\r
129         }\r
130 \r
131         @Override\r
132         protected void onDestroy() {\r
133                 if ( progress != null ) {\r
134                         if ( progress.isShowing() ) {\r
135                                 progress.dismiss();\r
136                         }\r
137                         progress = null;\r
138                 }\r
139                 super.onDestroy();\r
140         }\r
141 \r
142         @Override\r
143         protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
144                 // TODO Auto-generated method stub\r
145                 switch(requestCode){\r
146                 case PICK_ORK_FILE_RESULT:\r
147                         if(resultCode==RESULT_OK){\r
148                                 Uri file = data.getData();\r
149                                 loadOrkFile(file);\r
150                         }\r
151                         break;\r
152                 }\r
153         }\r
154 \r
155         private void loadOrkFile( Uri file ) {\r
156                 Log.d(TAG,"Use ork file: " + file);\r
157                 String path = file.getPath();\r
158                 File orkFile = new File(path);\r
159                 progress = ProgressDialog.show(this, "Loading file", "");\r
160 \r
161                 final OpenRocketLoaderTask task = new OpenRocketLoaderTask() {\r
162 \r
163                         /* (non-Javadoc)\r
164                          * @see android.os.AsyncTask#onPostExecute(java.lang.Object)\r
165                          */\r
166                         @Override\r
167                         protected void onPostExecute(OpenRocketDocument result) {\r
168                                 super.onPostExecute(result);\r
169                                 app.setRocketDocument( result );\r
170                                 updateContents();\r
171                         }\r
172 \r
173                 };\r
174 \r
175                 task.execute(orkFile);\r
176 \r
177         }\r
178 \r
179         /* (non-Javadoc)\r
180          * @see android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged(android.content.SharedPreferences, java.lang.String)\r
181          */\r
182         @Override\r
183         public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {\r
184                 // just in case the user changed the units, we redraw.\r
185                 PreferencesActivity.initializePreferences(getApplication(), PreferenceManager.getDefaultSharedPreferences(this));\r
186                 updateContents();\r
187         }\r
188 \r
189         private void updateContents() {\r
190 \r
191                 rocketDocument = app.getRocketDocument();\r
192                 rocketConfiguration = rocketDocument.getDefaultConfiguration();\r
193                 Rocket rocket = rocketDocument.getRocket();\r
194 \r
195                 setTitle(rocket.getName());\r
196 \r
197                 String[] motorConfigs = rocket.getMotorConfigurationIDs();\r
198                 ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item);\r
199                 for( String config: motorConfigs ) {\r
200                         spinnerAdapter.add(rocket.getMotorConfigurationNameOrDescription(config));\r
201                 }\r
202                 \r
203                 configurationSpinner.setAdapter(spinnerAdapter);\r
204                 configurationSpinner.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() {\r
205 \r
206                         /* (non-Javadoc)\r
207                          * @see android.widget.AdapterView.OnItemSelectedListener#onItemSelected(android.widget.AdapterView, android.view.View, int, long)\r
208                          */\r
209                         @Override\r
210                         public void onItemSelected(AdapterView<?> arg0, View arg1,\r
211                                         int arg2, long arg3) {\r
212 \r
213                                 String selectedConfigId = rocketDocument.getRocket().getMotorConfigurationIDs()[arg2];\r
214                                 rocketConfiguration.setMotorConfigurationID(selectedConfigId);\r
215                                 Coordinate cp = aerodynamicCalculator.getWorstCP(rocketConfiguration,\r
216                                                 new FlightConditions(rocketConfiguration),\r
217                                                 new WarningSet());\r
218                                 \r
219                                 Coordinate cg = massCalculator.getCG(rocketConfiguration, MassCalcType.LAUNCH_MASS);\r
220 \r
221                                 Unit lengthUnit = UnitGroup.UNITS_LENGTH.getDefaultUnit();\r
222                                 Unit massUnit = UnitGroup.UNITS_MASS.getDefaultUnit();\r
223                                 Unit stabilityUnit = UnitGroup.stabilityUnits(rocketConfiguration).getDefaultUnit();\r
224 \r
225                                 ((TextView)findViewById(R.id.openrocketviewerCP)).setText(lengthUnit.toStringUnit(cp.x));\r
226                                 ((TextView)findViewById(R.id.openrocketviewerCG)).setText(lengthUnit.toStringUnit(cg.x));\r
227                                 ((TextView)findViewById(R.id.openrocketviewerLiftOffWeight)).setText(massUnit.toStringUnit(cg.weight));\r
228                                 ((TextView)findViewById(R.id.openrocketviewerStabilityMargin)).setText(stabilityUnit.toStringUnit(cp.x-cg.x));\r
229 \r
230                         }\r
231 \r
232                         /* (non-Javadoc)\r
233                          * @see android.widget.AdapterView.OnItemSelectedListener#onNothingSelected(android.widget.AdapterView)\r
234                          */\r
235                         @Override\r
236                         public void onNothingSelected(AdapterView<?> arg0) {\r
237                                 ((TextView)findViewById(R.id.openrocketviewerCP)).setText("");\r
238                                 ((TextView)findViewById(R.id.openrocketviewerCG)).setText("");\r
239                                 ((TextView)findViewById(R.id.openrocketviewerLiftOffWeight)).setText("");\r
240                                 ((TextView)findViewById(R.id.openrocketviewerStabilityMargin)).setText("");\r
241                         }\r
242                         \r
243                 });\r
244                 \r
245                 Unit lengthUnit = UnitGroup.UNITS_LENGTH.getDefaultUnit();\r
246                 Unit massUnit = UnitGroup.UNITS_MASS.getDefaultUnit();\r
247 \r
248                 Coordinate cg = RocketUtils.getCG(rocket, MassCalcType.NO_MOTORS);\r
249                 double length = RocketUtils.getLength(rocket);\r
250                 ((TextView)findViewById(R.id.openrocketviewerDesigner)).setText(rocket.getDesigner());\r
251                 ((TextView)findViewById(R.id.openrocketviewerLength)).setText(lengthUnit.toStringUnit(length));\r
252                 ((TextView)findViewById(R.id.openrocketviewerMass)).setText(massUnit.toStringUnit(cg.weight));\r
253                 ((TextView)findViewById(R.id.openrocketviewerStageCount)).setText(String.valueOf(rocket.getStageCount()));\r
254 \r
255                 \r
256                 ArrayAdapter<Simulation> sims = new ArrayAdapter<Simulation>(this,android.R.layout.simple_list_item_2,rocketDocument.getSimulations()) {\r
257 \r
258                         @Override\r
259                         public View getView(int position, View convertView,     ViewGroup parent) {\r
260                                 View v = convertView;\r
261                                 if ( v == null ) {\r
262                                         LayoutInflater li = getLayoutInflater();\r
263                                         v = li.inflate(android.R.layout.simple_list_item_2,null);\r
264                                 }\r
265                                 Simulation sim = this.getItem(position);\r
266                                 ((TextView)v.findViewById(android.R.id.text1)).setText( sim.getName() );\r
267                                 ((TextView)v.findViewById(android.R.id.text2)).setText( "motors: " + sim.getConfiguration().getMotorConfigurationDescription() + " apogee: " + sim.getSimulatedData().getMaxAltitude() + "m  time: " + sim.getSimulatedData().getFlightTime() + "s");\r
268                                 return v;\r
269                         }\r
270 \r
271                 };\r
272                 simulationList.setOnItemClickListener( new OnItemClickListener() {\r
273                         @Override\r
274                         public void onItemClick(AdapterView l, View v, int position, long id) {\r
275                                 Intent i = new Intent(OpenRocketViewer.this, SimulationViewer.class);\r
276                                 Log.d(TAG,"onItemClick simulation number " + id );\r
277                                 i.putExtra("Simulation",(int)id);\r
278                                 startActivityForResult(i, 1/*magic*/);\r
279                         }\r
280 \r
281                 });\r
282                 simulationList.setAdapter(sims);\r
283 \r
284                 componentTree.setAdapter( buildAdapter( rocket ) );\r
285 \r
286                 if ( progress.isShowing() ) {\r
287                         progress.dismiss();\r
288                 }\r
289         }\r
290 \r
291         @Override\r
292         public boolean onCreateOptionsMenu(Menu menu) {\r
293                 MenuInflater inflater = getMenuInflater();\r
294                 inflater.inflate(R.menu.rocket_viewer_option_menu, menu);\r
295                 return true;\r
296         }\r
297 \r
298         @Override\r
299         public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
300                 Log.d(TAG,"onMenuItemSelected" + item.getItemId());\r
301                 switch(item.getItemId()) {\r
302                 case R.id.motor_list_menu_option:\r
303                         startMotorBrowser();\r
304                         return true;\r
305                 case R.id.preference_menu_option:\r
306                         Intent intent = new Intent().setClass(this, PreferencesActivity.class);\r
307                         this.startActivity(intent);\r
308                         return true;\r
309                 }\r
310                 return super.onMenuItemSelected(featureId, item);\r
311         }\r
312 \r
313         public void startMotorBrowser() {\r
314                 Log.d(TAG,"motorBrowserButton clicked");\r
315                 Intent i = new Intent(OpenRocketViewer.this, MotorHierarchicalBrowser.class);\r
316                 startActivity(i);\r
317         }\r
318 \r
319         private ListAdapter buildAdapter( Rocket rocket ) {\r
320                 /*\r
321                 final int[] DEMO_NODES = new int[] { 0, 0, 1, 1, 1, 2, 2, 1,\r
322                                 1, 2, 1, 0, 0, 0, 1, 2, 3, 2, 0, 0, 1, 2, 0, 1, 2, 0, 1 };\r
323                 final int LEVEL_NUMBER = 4;\r
324 \r
325                 TreeStateManager<Long> manager = new InMemoryTreeStateManager<Long>();\r
326                 final TreeBuilder<Long> treeBuilder = new TreeBuilder<Long>(manager);\r
327                 for (int i = 0; i < DEMO_NODES.length; i++) {\r
328                         treeBuilder.sequentiallyAddNextNode((long) i, DEMO_NODES[i]);\r
329                 }\r
330 \r
331                 return new SimpleStandardAdapter(this, manager, LEVEL_NUMBER);\r
332                 */\r
333                 \r
334                 TreeStateManager<RocketComponentWithId> manager = new InMemoryTreeStateManager<RocketComponentWithId>();\r
335                 TreeBuilder<RocketComponentWithId> treeBuilder = new TreeBuilder<RocketComponentWithId>(manager);\r
336                 \r
337                 int depth = buildRecursive( rocket, treeBuilder, 0 );\r
338                 return new RocketComponentTreeAdapter(this, manager, depth+1);\r
339         }\r
340         \r
341         long id = 0;\r
342         private int buildRecursive( RocketComponent comp, TreeBuilder<RocketComponentWithId> builder, int depth ) {\r
343                 \r
344                 \r
345                 int maxDepth = depth;\r
346                 \r
347                 RocketComponentWithId rcid = new RocketComponentWithId(comp, id++);\r
348                 \r
349                 // Add this component.\r
350                 builder.sequentiallyAddNextNode(rcid, depth);\r
351                 \r
352                 if ( comp.allowsChildren() ) {\r
353                         \r
354                         for( RocketComponent child : comp.getChildren() ) {\r
355                                 int childDepth = buildRecursive( child, builder, depth+1);\r
356                                 if ( childDepth > maxDepth) {\r
357                                         maxDepth = childDepth;\r
358                                 }\r
359                         }\r
360                         \r
361                 }\r
362                 \r
363                 return maxDepth;\r
364         }\r
365 \r
366 \r
367 }\r