<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>\r
<classpathentry kind="lib" path="libs/android-support-v4.jar"/>\r
<classpathentry kind="lib" path="libs/Androidplot-core-0.4.4-release.jar"/>\r
+ <classpathentry kind="lib" path="libs/achartengine-0.7.0.jar" sourcepath="/AChartEngine/src"/>\r
<classpathentry kind="output" path="bin/classes"/>\r
</classpath>\r
<?xml version="1.0" encoding="utf-8"?>\r
<manifest xmlns:android="http://schemas.android.com/apk/res/android"\r
- package="net.sf.openrocket"\r
- android:versionCode="1"\r
- android:versionName="1.0" >\r
-\r
- <uses-sdk\r
- android:minSdkVersion="8"\r
- android:targetSdkVersion="8" />\r
-\r
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />\r
- <uses-permission android:name="android.permission.INTERNET" />\r
-\r
- <application\r
- android:debuggable="true"\r
- android:icon="@drawable/or_launcher"\r
- android:killAfterRestore="true"\r
- android:label="@string/app_name"\r
- android:name=".android.Application" >\r
- <activity android:name=".android.Main" >\r
- <intent-filter >\r
- <action android:name="android.intent.action.MAIN" />\r
-\r
- <category android:name="android.intent.category.LAUNCHER" />\r
- </intent-filter>\r
- </activity>\r
- <activity\r
- android:label="@string/app_name"\r
- android:name=".android.rocket.OpenRocketViewer" >\r
-\r
- <!--\r
- I don't understand why I need to have two different intent filters. Combining the <data> elements\r
- into a single field did not result in a working application.\r
- The first intent-filter (with mimeType wildcard) convinces the file browser to associate the correct launcher\r
- icon.\r
- the second intent-filter is actually invoked when a file is selected.\r\r
- -->\r
- <intent-filter >\r
- <action android:name="android.intent.action.VIEW" />\r
-\r
- <category android:name="android.intent.category.DEFAULT" />\r
-\r
- <data\r
- android:host="*"\r
- android:mimeType="*/*"\r
- android:pathPattern=".*\\.ork"\r
- android:scheme="file" />\r
- </intent-filter>\r
- <intent-filter >\r
- <action android:name="android.intent.action.VIEW" />\r
-\r
- <category android:name="android.intent.category.DEFAULT" />\r
-\r
- <data\r
- android:host="*"\r
- android:pathPattern=".*\\.ork"\r
- android:scheme="file" />\r
- </intent-filter>\r
- </activity>\r
- <activity android:name=".android.PreferencesActivity" >\r
- <intent-filter >\r
- <action android:name="net.sf.openrocket.android.PreferencesActivity" />\r
-\r
- <category android:name="android.intent.category.PREFERENCE" />\r
- </intent-filter>\r
- </activity>\r
- <activity\r
- android:label="@string/MotorListTitle"\r
- android:name=".android.motor.MotorHierarchicalBrowser" >\r
- </activity>\r
- <activity android:name=".android.motor.MotorDetails" />\r
- <activity\r
- android:label="@string/MotorListTitle"\r
- android:name=".android.thrustcurve.TCQueryActivity" >\r
- </activity>\r
- <activity android:name=".android.simulation.SimulationViewer" />\r
- </application>\r
+ package="net.sf.openrocket" android:versionCode="1"\r
+ android:versionName="1.0">\r
+\r
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" />\r
+\r
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />\r
+ <uses-permission android:name="android.permission.INTERNET" />\r
+\r
+ <application android:debuggable="true" android:icon="@drawable/or_launcher"\r
+ android:killAfterRestore="true" android:label="@string/app_name"\r
+ android:name=".android.Application">\r
+ <activity android:name=".android.Main">\r
+ <intent-filter>\r
+ <action android:name="android.intent.action.MAIN" />\r
+\r
+ <category android:name="android.intent.category.LAUNCHER" />\r
+ </intent-filter>\r
+ </activity>\r
+ <activity android:label="@string/app_name" android:name=".android.rocket.OpenRocketViewer">\r
+\r
+ <!-- I don't understand why I need to have two different intent filters. \r
+ Combining the <data> elements into a single field did not result in a working \r
+ application. The first intent-filter (with mimeType wildcard) convinces the \r
+ file browser to associate the correct launcher icon. the second intent-filter \r
+ is actually invoked when a file is selected. -->\r
+ <intent-filter>\r
+ <action android:name="android.intent.action.VIEW" />\r
+\r
+ <category android:name="android.intent.category.DEFAULT" />\r
+\r
+ <data android:host="*" android:mimeType="*/*"\r
+ android:pathPattern=".*\\.ork" android:scheme="file" />\r
+ </intent-filter>\r
+ <intent-filter>\r
+ <action android:name="android.intent.action.VIEW" />\r
+\r
+ <category android:name="android.intent.category.DEFAULT" />\r
+\r
+ <data android:host="*" android:pathPattern=".*\\.ork"\r
+ android:scheme="file" />\r
+ </intent-filter>\r
+ </activity>\r
+ <activity android:name=".android.PreferencesActivity">\r
+ <intent-filter>\r
+ <action android:name="net.sf.openrocket.android.PreferencesActivity" />\r
+\r
+ <category android:name="android.intent.category.PREFERENCE" />\r
+ </intent-filter>\r
+ </activity>\r
+ <activity android:label="@string/MotorListTitle"\r
+ android:name=".android.motor.MotorHierarchicalBrowser" />\r
+ <activity android:name=".android.motor.MotorDetails" />\r
+ <activity android:label="@string/MotorListTitle"\r
+ android:name=".android.thrustcurve.TCQueryActivity" />\r
+ <activity android:name=".android.simulation.SimulationViewer" />\r
+ <activity android:name=".android.simulation.GraphicalActivity" />\r
+\r
+ </application>\r
\r
</manifest>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
- <fragment
- android:id="@+id/simulationPlotFragment"
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:onClick="draw"
+ android:text="Draw" />
+
+ <TabHost
+ android:id="@+id/simulationConfigurationForm"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:layout_marginLeft="0px"
- android:layout_marginRight="0px"
- android:layout_marginTop="5px"
- class="net.sf.openrocket.android.simulation.SimulationPlotFragment"
- title="Simulation" />
-
- <SlidingDrawer
- android:id="@+id/drawer"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="0.4"
- android:content="@+id/simulationConfigurationForm"
- android:handle="@+id/handle" >
+ android:background="@android:color/black" >
- <ImageView
- android:id="@+id/handle"
- android:layout_width="match_parent"
- android:layout_height="30px"
- android:src="@drawable/arrow_up_float"
- android:text="" />
-
- <TabHost
- android:id="@+id/simulationConfigurationForm"
+ <LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:background="@android:color/black" >
+ android:orientation="vertical" >
- <LinearLayout
+ <TabWidget
+ android:id="@android:id/tabs"
android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
+ android:layout_height="wrap_content" />
- <TabWidget
- android:id="@android:id/tabs"
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+
+ <ListView
+ android:id="@+id/simulationEventsList"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
- <FrameLayout
- android:id="@android:id/tabcontent"
+ <LinearLayout
+ android:id="@+id/simulationSeriesSelection"
android:layout_width="fill_parent"
- android:layout_height="fill_parent" >
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/simulationSeries1Label" />
+
+ <Spinner
+ android:id="@+id/simulationSeries1"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:drawSelectorOnTop="true" />
- <ListView
- android:id="@+id/simulationEventsList"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/simulationSeries2Label" />
- <ListView
- android:id="@+id/simulationSeriesList"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- </FrameLayout>
- </LinearLayout>
- </TabHost>
- </SlidingDrawer>
+ <Spinner
+ android:id="@+id/simulationSeries2"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:drawSelectorOnTop="true" />
+ </LinearLayout>
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
-</FrameLayout>
\ No newline at end of file
+</LinearLayout>
\ No newline at end of file
</string-array>\r
\r
<string name="TCMotorSearchFormSubmit">Submit</string>\r
- <string name="tcdownload">Download from ThrustCurve</string>\r
+ <string name="tcdownload">Download from ThrustCurve</string>
+ <string name="simulationSeries1Label">Series 1</string>
+ <string name="simulationSeries2Label">Series 2</string>\r
\r
</resources>
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009, 2010 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package net.sf.openrocket.android.simulation;\r
+\r
+import org.achartengine.ChartFactory;\r
+import org.achartengine.GraphicalView;\r
+import org.achartengine.chart.AbstractChart;\r
+\r
+import android.app.Activity;\r
+import android.os.Bundle;\r
+import android.view.Window;\r
+\r
+/**\r
+ * An activity that encapsulates a graphical view of the chart.\r
+ */\r
+public class GraphicalActivity extends Activity {\r
+ /** The encapsulated graphical view. */\r
+ private GraphicalView mView;\r
+ /** The chart to be drawn. */\r
+ private AbstractChart mChart;\r
+\r
+ @Override\r
+ protected void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+ requestWindowFeature(Window.FEATURE_NO_TITLE);\r
+ Bundle extras = getIntent().getExtras();\r
+ mChart = (AbstractChart) extras.getSerializable(ChartFactory.CHART);\r
+ mView = new GraphicalView(this, mChart);\r
+ String title = extras.getString(ChartFactory.TITLE);\r
+ if (title == null) {\r
+ requestWindowFeature(Window.FEATURE_NO_TITLE);\r
+ } else if (title.length() > 0) {\r
+ setTitle(title);\r
+ }\r
+ setContentView(mView);\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009, 2010 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package net.sf.openrocket.android.simulation;\r
+\r
+import java.util.List;\r
+\r
+import net.sf.openrocket.simulation.FlightDataBranch;\r
+import net.sf.openrocket.simulation.FlightDataType;\r
+import net.sf.openrocket.simulation.FlightEvent;\r
+\r
+import org.achartengine.ChartFactory;\r
+import org.achartengine.chart.LineChart;\r
+import org.achartengine.chart.PointStyle;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYSeriesRenderer;\r
+\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.graphics.Color;\r
+import android.graphics.Paint.Align;\r
+import android.util.Log;\r
+\r
+/**\r
+ * Multiple temperature demo chart.\r
+ */\r
+public class SimulationChart {\r
+ \r
+ private final static String TAG = "SimulationChart";\r
+\r
+ private FlightDataBranch flightDataBranch;\r
+ private FlightDataType series1;\r
+ private FlightDataType series2;\r
+ private final FlightDataType time = FlightDataType.TYPE_TIME;\r
+ private List<FlightEvent> flightEvents;\r
+\r
+ // Define 4 different colors and point styles to use for the series.\r
+ // For now only 2 series are supported though.\r
+ private final static int[] colors = new int[] { Color.BLUE, Color.YELLOW, Color.GREEN, Color.RED };\r
+ private final static PointStyle[] styles = new PointStyle[] { PointStyle.CIRCLE, PointStyle.DIAMOND,\r
+ PointStyle.TRIANGLE, PointStyle.SQUARE };\r
+\r
+ /**\r
+ * @param flightDataBranch the flightDataBranch to set\r
+ */\r
+ public void setFlightDataBranch(FlightDataBranch flightDataBranch) {\r
+ this.flightDataBranch = flightDataBranch;\r
+ }\r
+\r
+ /**\r
+ * @param series1 the series1 to set\r
+ */\r
+ public void setSeries1(FlightDataType series1) {\r
+ this.series1 = series1;\r
+ }\r
+\r
+ /**\r
+ * @param series2 the series2 to set\r
+ */\r
+ public void setSeries2(FlightDataType series2) {\r
+ this.series2 = series2;\r
+ }\r
+\r
+ /**\r
+ * @param flightEvents the flightEvents to set\r
+ */\r
+ public void setFlightEvents(List<FlightEvent> flightEvents) {\r
+ this.flightEvents = flightEvents;\r
+ }\r
+\r
+ private static String formatFlightDataTypeAxisLabel( FlightDataType fdt ) {\r
+ return fdt.getName() + " (" + fdt.getUnitGroup().getDefaultUnit().toString() + ")";\r
+ }\r
+\r
+ /**\r
+ * Executes the chart demo.\r
+ * \r
+ * @param context the context\r
+ * @return the built intent\r
+ */\r
+ public Intent execute(Context context) {\r
+\r
+ int seriesCount = 2;\r
+ // if the same series is selected twice, only plot it once.\r
+ if ( series1 == series2 ) {\r
+ seriesCount = 1;\r
+ }\r
+\r
+ XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer(seriesCount);\r
+\r
+ renderer.setAxisTitleTextSize(16);\r
+ renderer.setChartTitleTextSize(20);\r
+ renderer.setLabelsTextSize(15);\r
+ renderer.setLegendTextSize(15);\r
+ renderer.setPointSize(5f);\r
+ renderer.setXLabels(10);\r
+ renderer.setYLabels(10);\r
+ renderer.setShowGrid(true);\r
+ //renderer.setZoomButtonsVisible(true);\r
+ renderer.setChartTitle("Simulation");\r
+\r
+ renderer.setMargins(new int[] { 50, 30, 0, 20 });\r
+ {\r
+ for (int i = 0; i < seriesCount; i++) {\r
+ XYSeriesRenderer r = new XYSeriesRenderer();\r
+ r.setColor(colors[i]);\r
+ r.setPointStyle(styles[i]);\r
+ r.setFillPoints(true);\r
+ renderer.addSeriesRenderer(r);\r
+ }\r
+ }\r
+\r
+ renderer.setXTitle(formatFlightDataTypeAxisLabel(time));\r
+ renderer.setXLabelsAlign(Align.RIGHT);\r
+\r
+ renderer.setYTitle(formatFlightDataTypeAxisLabel(series1),0);\r
+ renderer.setYLabelsAlign(Align.RIGHT,0);\r
+\r
+ if ( seriesCount > 1 ) {\r
+ renderer.setYTitle(formatFlightDataTypeAxisLabel(series2), 1);\r
+ renderer.setYAxisAlign(Align.RIGHT, 1);\r
+ renderer.setYLabelsAlign(Align.LEFT, 1);\r
+ }\r
+\r
+ renderer.setAxesColor(Color.LTGRAY);\r
+ renderer.setLabelsColor(Color.LTGRAY);\r
+\r
+ XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();\r
+\r
+ List<Double> timevalues = flightDataBranch.get(time);\r
+ List<Double> series1values = flightDataBranch.get(series1);\r
+\r
+ // compute the axis limits using timevalues and series1values.\r
+ double xmin = 0;\r
+ double ymin = 0;\r
+ renderer.setXAxisMin(xmin);\r
+ renderer.setYAxisMin(ymin);\r
+\r
+ double ymax = computeMaxValueWithPadding( series1values );\r
+ double xmax = Math.ceil( timevalues.get( timevalues.size()-1));\r
+ \r
+ Log.d(TAG,"ymax = " + ymax);\r
+ renderer.setXAxisMax(xmax);\r
+ renderer.setYAxisMax(ymax);\r
+\r
+ // Don't allow pan & zoom just yet.\r
+ renderer.setPanEnabled(false,false);\r
+ renderer.setZoomEnabled(false,false);\r
+ //renderer.setPanLimits(new double[] { xmin, xmax, ymin, ymax });\r
+ //renderer.setZoomLimits(new double[] { xmin, xmax, ymin, ymax });\r
+\r
+ // Add first series\r
+ addXYSeries(dataset, series1.getName(), timevalues, series1values, 0);\r
+\r
+ if ( seriesCount > 1 ) {\r
+ // Add second series\r
+ addXYSeries(dataset, series2.getName(), timevalues, flightDataBranch.get(series2), 1);\r
+ }\r
+ Intent intent = getLineChartIntent(context, dataset, renderer,"Simulation");\r
+ return intent;\r
+ }\r
+\r
+ private static void addXYSeries(XYMultipleSeriesDataset dataset, String titles, List<Double> xValues, List<Double> yValues, int scale) {\r
+ XYSeries series = new XYSeries(titles, scale);\r
+ int datasize = xValues.size();\r
+ for( int i = 0; i<datasize; i++ ) {\r
+ series.add(xValues.get(i), yValues.get(i));\r
+ }\r
+ dataset.addSeries(series);\r
+\r
+ }\r
+\r
+ private static Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer, String activityTitle) {\r
+ // checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ XYChart chart = new LineChart(dataset, renderer);\r
+ intent.putExtra(ChartFactory.CHART, chart);\r
+ intent.putExtra(ChartFactory.TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ private static double computeMaxValueWithPadding( List<Double> list ) {\r
+ double max = list.get(0);\r
+ for( double v : list ) {\r
+ if ( v > max ) {\r
+ max = v;\r
+ }\r
+ }\r
+ if ( max <= 0 ) return 1.0;\r
+\r
+ // Do something stupid.\r
+ // return:\r
+ // 10 if max <= 10\r
+ // next 10 if 10 < max < 1000\r
+ // next 100 if 1000 < max < 10,000\r
+ // next 1000 if max >= 10,000\r
+ double numdigits = Math.floor(Math.log10(max));\r
+ \r
+ if ( numdigits <= 1.0 ) {\r
+ return 10.0;\r
+ } else if ( numdigits <= 3.0 ) {\r
+ return 10.0 * ( Math.ceil( max/10.0));\r
+ } else if ( numdigits <= 4.0 ) {\r
+ return 100.0 * ( Math.ceil( max/ 100.0) );\r
+ } else {\r
+ return 1000.0 * ( Math.ceil( max / 1000.0 ));\r
+ }\r
+ \r
+ }\r
+ \r
+}\r
+++ /dev/null
-package net.sf.openrocket.android.simulation;\r
-\r
-import java.util.List;\r
-import java.util.Vector;\r
-\r
-import net.sf.openrocket.R;\r
-import net.sf.openrocket.simulation.FlightDataBranch;\r
-import net.sf.openrocket.simulation.FlightDataType;\r
-import net.sf.openrocket.simulation.FlightEvent;\r
-import android.app.Activity;\r
-import android.graphics.Color;\r
-import android.graphics.PointF;\r
-import android.os.Bundle;\r
-import android.support.v4.app.Fragment;\r
-import android.util.Log;\r
-import android.view.LayoutInflater;\r
-import android.view.MotionEvent;\r
-import android.view.ScaleGestureDetector;\r
-import android.view.View;\r
-import android.view.View.OnTouchListener;\r
-import android.view.ViewGroup;\r
-\r
-import com.androidplot.xy.BoundaryMode;\r
-import com.androidplot.xy.LineAndPointFormatter;\r
-import com.androidplot.xy.LineAndPointRenderer;\r
-import com.androidplot.xy.SimpleXYSeries;\r
-import com.androidplot.xy.ValueMarker;\r
-import com.androidplot.xy.XValueMarker;\r
-import com.androidplot.xy.XYPlot;\r
-\r
-public class SimulationPlotFragment extends Fragment implements OnTouchListener {\r
-\r
- private final static String TAG = "SimulationPlot";\r
-\r
- private XYPlot mySimpleXYPlot;\r
- private SimpleXYSeries mySeries;\r
- private PointF minXY;\r
- private PointF maxXY;\r
- \r
- private float absMinX;\r
- private float absMaxX;\r
- private float minNoError;\r
- private float maxNoError;\r
-\r
- private ScaleGestureDetector mScaleDetector;\r
- private float mScaleFactor = 1.f;\r
-\r
- @Override\r
- public void onAttach(Activity activity) {\r
- super.onAttach(activity);\r
- Log.d(TAG,"onAttach");\r
- }\r
-\r
- @Override\r
- public void onCreate(Bundle savedInstanceState) {\r
- Log.d(TAG,"onCreate");\r
- super.onCreate(savedInstanceState);\r
- }\r
-\r
- @Override\r
- public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
- Bundle savedInstanceState) {\r
- Log.d(TAG,"onCreateView");\r
- View v = inflater.inflate(R.layout.motor_burn, container, false);\r
- mySimpleXYPlot = (XYPlot) v.findViewById(R.id.xyplot);\r
- mySimpleXYPlot.setOnTouchListener(this);\r
- mScaleDetector = new ScaleGestureDetector(v.getContext(), new ScaleListener());\r
- // Motor motor = getMotor();\r
- // init(motor);\r
- return v;\r
- }\r
-\r
- void init( FlightDataBranch data, FlightDataType selectedSeries, List<FlightEvent> eventsToShow ) {\r
-\r
- mySimpleXYPlot.clear();\r
- \r
- if ( data == null || selectedSeries == null || eventsToShow == null ) {\r
- return;\r
- }\r
- \r
- mySimpleXYPlot.setUserDomainOrigin(0);\r
- mySimpleXYPlot.setUserRangeOrigin(0);\r
- mySimpleXYPlot.setRangeLabel("");\r
- mySimpleXYPlot.setDomainLabel(FlightDataType.TYPE_TIME.getName() + " (" + FlightDataType.TYPE_TIME.getUnitGroup().getDefaultUnit().toString() + ")");\r
- mySimpleXYPlot.setRangeLabel( selectedSeries.getName() + " (" + selectedSeries.getUnitGroup().getDefaultUnit().toString() + ")"); \r
- mySimpleXYPlot.disableAllMarkup();\r
-\r
- for ( FlightEvent event : eventsToShow ) {\r
- XValueMarker xmarker = new XValueMarker( event.getTime(), event.getType().toString() );\r
- xmarker.setTextOrientation( ValueMarker.TextOrientation.VERTICAL );\r
- mySimpleXYPlot.addMarker( xmarker );\r
- }\r
- \r
- List<Double> yvals = null;\r
- List<Double> xvals = null;\r
- try {\r
- yvals = data.get(selectedSeries);\r
- xvals = data.get(FlightDataType.TYPE_TIME);\r
- Log.d("plot","data = " + yvals);\r
- } catch ( Exception ex ) {\r
- Log.d(TAG, "Exception: " + ex);\r
- }\r
- if ( yvals == null || yvals.size() == 0 ) {\r
- yvals = new Vector<Double>();\r
- yvals.add(0.0);\r
- yvals.add(0.0);\r
- yvals.add(1.0);\r
- yvals.add(1.0);\r
- }\r
- Log.d("plot","data = " + yvals.toString());\r
-\r
- mySeries = new SimpleXYSeries(xvals, yvals, selectedSeries.toString());\r
-\r
- mySimpleXYPlot.addSeries(mySeries, LineAndPointRenderer.class,\r
- new LineAndPointFormatter(Color.rgb(0, 255, 0), Color.rgb(200, 0, 0), null));\r
-\r
- //Set of internal variables for keeping track of the boundaries\r
- mySimpleXYPlot.calculateMinMaxVals();\r
- \r
- mySimpleXYPlot.redraw();\r
-\r
- minXY=new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),mySimpleXYPlot.getCalculatedMinY().floatValue());\r
- maxXY=new PointF(mySimpleXYPlot.getCalculatedMaxX().floatValue(),mySimpleXYPlot.getCalculatedMaxY().floatValue());\r
-\r
- absMinX = minXY.x;\r
- absMaxX = maxXY.x;\r
- \r
- minNoError = Math.round(mySeries.getX(1).floatValue() +2);\r
- maxNoError = Math.round(mySeries.getX(mySeries.size() -1).floatValue()) - 2.0f;\r
- }\r
-\r
- private float mPosX;\r
- private float mPosY;\r
-\r
- private float mLastTouchX;\r
- private float mLastTouchY;\r
-\r
- private int mActivePointerId = -1;\r
-\r
- @Override\r
- public boolean onTouch(View arg0, MotionEvent event) {\r
- mScaleDetector.onTouchEvent(event);\r
-\r
- final int action = event.getAction();\r
- switch ( action & MotionEvent.ACTION_MASK ) {\r
- case MotionEvent.ACTION_DOWN: {\r
- final float x = event.getX();\r
- final float y = event.getY();\r
-\r
- mLastTouchX = x;\r
- mLastTouchY = y;\r
-\r
- mActivePointerId = event.getPointerId(0);\r
- break;\r
- }\r
- \r
- case MotionEvent.ACTION_MOVE: {\r
- final int pointerIndex = event.findPointerIndex(mActivePointerId);\r
- final float x = event.getX(pointerIndex);\r
- final float y = event.getY(pointerIndex);\r
-\r
- if (!mScaleDetector.isInProgress()) {\r
- final float dx = x - mLastTouchX;\r
- final float dy = y - mLastTouchY;\r
- \r
- mPosX += dx;\r
- mPosY += dy;\r
- scroll(dx);\r
- // do scroll.\r
- \r
- }\r
- mLastTouchX = x;\r
- mLastTouchY = y;\r
- \r
- break;\r
- }\r
- \r
- case MotionEvent.ACTION_UP: {\r
- mActivePointerId = -1;\r
- break;\r
- }\r
- \r
- case MotionEvent.ACTION_CANCEL: {\r
- mActivePointerId = -1;\r
- break;\r
- }\r
- \r
- case MotionEvent.ACTION_POINTER_UP: {\r
- final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;\r
- final int pointerId = event.getPointerId(pointerIndex);\r
- if (pointerId == mActivePointerId) {\r
- // This was our active pointer going up. choose a new active pointer and adjust accordingly.\r
- final int newPointerIndex = pointerIndex ==0 ? 1:0;\r
- mLastTouchX = event.getX(newPointerIndex);\r
- mLastTouchY = event.getY(newPointerIndex);\r
- mActivePointerId = event.getPointerId(newPointerIndex);\r
- }\r
- break;\r
- }\r
- } \r
- return true;\r
- }\r
-\r
- private void zoom(float scale) {\r
- Log.d(TAG,"zoom by " + scale);\r
- float domainSpan = absMaxX - absMinX;\r
- Log.d(TAG,"domainSpan = " + domainSpan);\r
- float domainMidPoint = absMaxX - domainSpan / 2.0f;\r
- Log.d(TAG,"domainMidPoint = " + domainMidPoint);\r
- float offset = domainSpan / scale;\r
- Log.d(TAG,"offset " + offset);\r
- minXY.x=domainMidPoint- offset;\r
- Log.d(TAG,"min X " + minXY.x);\r
- maxXY.x=domainMidPoint+offset;\r
- Log.d(TAG,"max X " + maxXY.x);\r
- checkBoundaries();\r
- mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);\r
- mySimpleXYPlot.redraw();\r
- }\r
-\r
- private void scroll(float pan) {\r
- float domainSpan = maxXY.x - minXY.x;\r
- float step = domainSpan / mySimpleXYPlot.getWidth();\r
- float offset = pan * step;\r
- minXY.x+= offset;\r
- maxXY.x+= offset;\r
- checkBoundaries();\r
- mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);\r
- mySimpleXYPlot.redraw();\r
- }\r
-\r
- private void checkBoundaries() {\r
- \r
- if ( minXY.x < absMinX) \r
- minXY.x = absMinX;\r
-// else if ( minXY.x > maxNoError )\r
-// minXY.x = maxNoError;\r
- \r
- if ( maxXY.x > absMaxX)\r
- maxXY.x = absMaxX;\r
-// else if ( maxXY.x < minNoError)\r
-// maxXY.x = minNoError;\r
- }\r
- private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {\r
- @Override\r
- public boolean onScale( ScaleGestureDetector detector ) {\r
- mScaleFactor *= detector.getScaleFactor();\r
-\r
- mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 5.0f));\r
- zoom(mScaleFactor);\r
- return true;\r
- }\r
- }\r
-}\r
-\r
import net.sf.openrocket.simulation.FlightDataBranch;\r
import net.sf.openrocket.simulation.FlightDataType;\r
import net.sf.openrocket.simulation.FlightEvent;\r
+import android.app.Activity;\r
import android.content.Intent;\r
import android.os.Bundle;\r
-import android.support.v4.app.FragmentActivity;\r
import android.util.Log;\r
import android.util.SparseBooleanArray;\r
import android.view.LayoutInflater;\r
-import android.view.Menu;\r
-import android.view.MenuInflater;\r
-import android.view.MenuItem;\r
import android.view.View;\r
import android.view.ViewGroup;\r
import android.widget.ArrayAdapter;\r
-import android.widget.ImageView;\r
import android.widget.ListView;\r
-import android.widget.SlidingDrawer;\r
+import android.widget.Spinner;\r
import android.widget.TabHost;\r
import android.widget.TextView;\r
\r
-public class SimulationViewer extends FragmentActivity\r
-implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListener {\r
+public class SimulationViewer extends Activity {\r
\r
- private final static String TAG = "MotorDetails";\r
-\r
- private SlidingDrawer slidingDrawer;\r
- private ImageView handle;\r
+ private final static String TAG = "SimulationViewer";\r
\r
private ListView eventList;\r
- private ListView seriesList;\r
-\r
- private SimulationPlotFragment simPlot;\r
+ private Spinner series1Spinner;\r
+ private Spinner series2Spinner;\r
\r
private Simulation sim;\r
private FlightDataBranch data;\r
sim = ((Application)this.getApplication()).getRocketDocument().getSimulation(simnumber);\r
data = sim.getSimulatedData().getBranch(0);\r
\r
- simPlot = (SimulationPlotFragment) getSupportFragmentManager().findFragmentById(R.id.simulationPlotFragment);\r
-\r
- slidingDrawer = (SlidingDrawer) findViewById(R.id.drawer);\r
-\r
- slidingDrawer.setOnDrawerOpenListener(this);\r
- slidingDrawer.setOnDrawerCloseListener(this);\r
-\r
- handle = (ImageView) findViewById(R.id.handle);\r
-\r
TabHost tabs=(TabHost)findViewById(R.id.simulationConfigurationForm);\r
\r
tabs.setup();\r
tabs.addTab(spec);\r
\r
spec=tabs.newTabSpec("tag2");\r
- spec.setContent(R.id.simulationSeriesList);\r
+ spec.setContent(R.id.simulationSeriesSelection);\r
spec.setIndicator("Series");\r
tabs.addTab(spec); \r
\r
eventList = (ListView) findViewById(R.id.simulationEventsList);\r
\r
- seriesList = (ListView) findViewById(R.id.simulationSeriesList);\r
-\r
// Initialize the eventList\r
ArrayAdapter<FlightEvent> events = new ArrayAdapter<FlightEvent>(this,android.R.layout.simple_list_item_multiple_choice,data.getEvents()) {\r
\r
eventList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);\r
eventList.setAdapter(events);\r
\r
+ series1Spinner = (Spinner) findViewById(R.id.simulationSeries1);\r
+ series2Spinner = (Spinner) findViewById(R.id.simulationSeries2);\r
+\r
List<FlightDataType> selectableSeries = new ArrayList<FlightDataType>();\r
for( FlightDataType fdt : data.getTypes() ) {\r
if ( fdt == FlightDataType.TYPE_TIME ) { \r
selectableSeries.add(fdt);\r
}\r
}\r
- ArrayAdapter<FlightDataType> serieses = new ArrayAdapter<FlightDataType>(this,android.R.layout.simple_list_item_multiple_choice,selectableSeries) {\r
+ ArrayAdapter<FlightDataType> serieses = new ArrayAdapter<FlightDataType>(this,android.R.layout.simple_spinner_item,selectableSeries) {\r
\r
@Override\r
public View getView(int position, View convertView,\r
View v = convertView;\r
if ( v == null ) {\r
LayoutInflater li = getLayoutInflater();\r
- v = li.inflate(android.R.layout.simple_list_item_multiple_choice,null);\r
+ v = li.inflate(android.R.layout.simple_spinner_item,null);\r
}\r
FlightDataType fdt = this.getItem(position);\r
((TextView)v.findViewById(android.R.id.text1)).setText( fdt.toString() );\r
}\r
\r
};\r
- seriesList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);\r
- seriesList.setAdapter(serieses);\r
- redraw();\r
-\r
- }\r
+ series1Spinner.setAdapter(serieses);\r
+ series2Spinner.setAdapter(serieses);\r
\r
- @Override\r
- public void onDrawerOpened() {\r
- handle.setImageResource(R.drawable.arrow_down_float);\r
- }\r
-\r
- @Override\r
- public void onDrawerClosed() {\r
- handle.setImageResource(R.drawable.arrow_up_float);\r
- redraw();\r
}\r
\r
- private void redraw() {\r
+ public void draw( View v ) {\r
List<FlightEvent> eventsToShow = new ArrayList<FlightEvent>();\r
{\r
SparseBooleanArray eventsSelected = eventList.getCheckedItemPositions();\r
}\r
}\r
}\r
- FlightDataType selectedSeries = null;\r
- {\r
- int selected = seriesList.getCheckedItemPosition();\r
- if ( selected >= 0 ) {\r
- selectedSeries = (FlightDataType) seriesList.getAdapter().getItem(selected);\r
- }\r
- }\r
-\r
- simPlot.init(data, selectedSeries, eventsToShow );\r
-\r
+ FlightDataType series1 = (FlightDataType) series1Spinner.getSelectedItem();\r
+ Log.d(TAG,"sereis1 = " + series1.toString());\r
+ FlightDataType series2 = (FlightDataType) series2Spinner.getSelectedItem();\r
+ Log.d(TAG,"series2 = " + series2.toString());\r
+\r
+ SimulationChart chart = new SimulationChart();\r
+ chart.setFlightDataBranch(data);\r
+ chart.setSeries1(series1);\r
+ chart.setSeries2(series2);\r
+ chart.setFlightEvents(eventsToShow);\r
+ \r
+ startActivity(chart.execute(this));\r
}\r
\r
}\r