Change Simulation plotting functionality to use AChartEngine instead of AndroidPlot...
authorkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Fri, 6 Jan 2012 03:12:27 +0000 (03:12 +0000)
committerkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Fri, 6 Jan 2012 03:12:27 +0000 (03:12 +0000)
Removed the sliding drawer from the configuration.  Instead a new activity is launched containing the plot.

git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@275 180e2498-e6e9-4542-8430-84ac67f01cd8

android/.classpath
android/AndroidManifest.xml
android/libs/achartengine-0.7.0.jar [new file with mode: 0644]
android/res/layout/simulation_detail.xml
android/res/values/strings.xml
src/net/sf/openrocket/android/simulation/GraphicalActivity.java [new file with mode: 0644]
src/net/sf/openrocket/android/simulation/SimulationChart.java [new file with mode: 0644]
src/net/sf/openrocket/android/simulation/SimulationPlotFragment.java [deleted file]
src/net/sf/openrocket/android/simulation/SimulationViewer.java

index 1f6c7ff44a25d2597e992dd58b38935d4fc0bba6..a69f6427a78720cf050e733b80790bdc1bad8d7d 100644 (file)
@@ -7,5 +7,6 @@
        <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
index 511447eddb6910c967b2f4d912797d35becdaf6e..e660bb6f7a4237cf34f1c0a6226a69f40977d2ae 100644 (file)
@@ -1,79 +1,62 @@
 <?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
diff --git a/android/libs/achartengine-0.7.0.jar b/android/libs/achartengine-0.7.0.jar
new file mode 100644 (file)
index 0000000..63af27a
Binary files /dev/null and b/android/libs/achartengine-0.7.0.jar differ
index 605f4e74fd135eb9acba39d7a2342b02e7f0dc10..88c3649bbb93c39202165839b32c77667838b286 100644 (file)
@@ -1,67 +1,71 @@
 <?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
index 60e3d8fb2d689d7c26ad1940c042b187c7a3465d..5ff1044950308f12d26b32dd667ad1c2b5047235 100644 (file)
@@ -93,6 +93,8 @@
     </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
diff --git a/src/net/sf/openrocket/android/simulation/GraphicalActivity.java b/src/net/sf/openrocket/android/simulation/GraphicalActivity.java
new file mode 100644 (file)
index 0000000..8335bd8
--- /dev/null
@@ -0,0 +1,51 @@
+/**\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
diff --git a/src/net/sf/openrocket/android/simulation/SimulationChart.java b/src/net/sf/openrocket/android/simulation/SimulationChart.java
new file mode 100644 (file)
index 0000000..75d5dde
--- /dev/null
@@ -0,0 +1,227 @@
+/**\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
diff --git a/src/net/sf/openrocket/android/simulation/SimulationPlotFragment.java b/src/net/sf/openrocket/android/simulation/SimulationPlotFragment.java
deleted file mode 100644 (file)
index d91e135..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-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
index a3e59038b3e7429f494e5af3960938b3e803e13c..3746cb5fc69655679a3885c00ce5074380bd4477 100644 (file)
@@ -9,36 +9,27 @@ import net.sf.openrocket.document.Simulation;
 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
@@ -54,15 +45,6 @@ implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListen
                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
@@ -74,14 +56,12 @@ implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListen
                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
@@ -102,6 +82,9 @@ implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListen
                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
@@ -110,7 +93,7 @@ implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListen
                                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
@@ -118,7 +101,7 @@ implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListen
                                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
@@ -126,24 +109,12 @@ implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListen
                        }\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
@@ -154,16 +125,18 @@ implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListen
                                }\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