1 package net.sf.openrocket.android.simulation;
\r
3 import java.util.List;
\r
4 import java.util.Vector;
\r
6 import net.sf.openrocket.R;
\r
7 import net.sf.openrocket.simulation.FlightDataBranch;
\r
8 import net.sf.openrocket.simulation.FlightDataType;
\r
9 import net.sf.openrocket.simulation.FlightEvent;
\r
10 import android.app.Activity;
\r
11 import android.graphics.Color;
\r
12 import android.graphics.PointF;
\r
13 import android.os.Bundle;
\r
14 import android.support.v4.app.Fragment;
\r
15 import android.util.Log;
\r
16 import android.view.LayoutInflater;
\r
17 import android.view.MotionEvent;
\r
18 import android.view.ScaleGestureDetector;
\r
19 import android.view.View;
\r
20 import android.view.View.OnTouchListener;
\r
21 import android.view.ViewGroup;
\r
23 import com.androidplot.xy.BoundaryMode;
\r
24 import com.androidplot.xy.LineAndPointFormatter;
\r
25 import com.androidplot.xy.LineAndPointRenderer;
\r
26 import com.androidplot.xy.SimpleXYSeries;
\r
27 import com.androidplot.xy.ValueMarker;
\r
28 import com.androidplot.xy.XValueMarker;
\r
29 import com.androidplot.xy.XYPlot;
\r
31 public class SimulationPlotFragment extends Fragment implements OnTouchListener {
\r
33 private final static String TAG = "SimulationPlot";
\r
35 private XYPlot mySimpleXYPlot;
\r
36 private SimpleXYSeries mySeries;
\r
37 private PointF minXY;
\r
38 private PointF maxXY;
\r
40 private float absMinX;
\r
41 private float absMaxX;
\r
42 private float minNoError;
\r
43 private float maxNoError;
\r
45 private ScaleGestureDetector mScaleDetector;
\r
46 private float mScaleFactor = 1.f;
\r
49 public void onAttach(Activity activity) {
\r
50 super.onAttach(activity);
\r
51 Log.d(TAG,"onAttach");
\r
55 public void onCreate(Bundle savedInstanceState) {
\r
56 Log.d(TAG,"onCreate");
\r
57 super.onCreate(savedInstanceState);
\r
61 public View onCreateView(LayoutInflater inflater, ViewGroup container,
\r
62 Bundle savedInstanceState) {
\r
63 Log.d(TAG,"onCreateView");
\r
64 View v = inflater.inflate(R.layout.motor_burn, container, false);
\r
65 mySimpleXYPlot = (XYPlot) v.findViewById(R.id.xyplot);
\r
66 mySimpleXYPlot.setOnTouchListener(this);
\r
67 mScaleDetector = new ScaleGestureDetector(v.getContext(), new ScaleListener());
\r
68 // Motor motor = getMotor();
\r
73 void init( FlightDataBranch data, FlightDataType selectedSeries, List<FlightEvent> eventsToShow ) {
\r
75 mySimpleXYPlot.clear();
\r
77 if ( data == null || selectedSeries == null || eventsToShow == null ) {
\r
81 mySimpleXYPlot.setUserDomainOrigin(0);
\r
82 mySimpleXYPlot.setUserRangeOrigin(0);
\r
83 mySimpleXYPlot.setRangeLabel("");
\r
84 mySimpleXYPlot.setDomainLabel(FlightDataType.TYPE_TIME.getName() + " (" + FlightDataType.TYPE_TIME.getUnitGroup().getDefaultUnit().toString() + ")");
\r
85 mySimpleXYPlot.setRangeLabel( selectedSeries.getName() + " (" + selectedSeries.getUnitGroup().getDefaultUnit().toString() + ")");
\r
86 mySimpleXYPlot.disableAllMarkup();
\r
88 for ( FlightEvent event : eventsToShow ) {
\r
89 XValueMarker xmarker = new XValueMarker( event.getTime(), event.getType().toString() );
\r
90 xmarker.setTextOrientation( ValueMarker.TextOrientation.VERTICAL );
\r
91 mySimpleXYPlot.addMarker( xmarker );
\r
94 List<Double> yvals = null;
\r
95 List<Double> xvals = null;
\r
97 yvals = data.get(selectedSeries);
\r
98 xvals = data.get(FlightDataType.TYPE_TIME);
\r
99 Log.d("plot","data = " + yvals);
\r
100 } catch ( Exception ex ) {
\r
101 Log.d(TAG, "Exception: " + ex);
\r
103 if ( yvals == null || yvals.size() == 0 ) {
\r
104 yvals = new Vector<Double>();
\r
110 Log.d("plot","data = " + yvals.toString());
\r
112 mySeries = new SimpleXYSeries(xvals, yvals, selectedSeries.toString());
\r
114 mySimpleXYPlot.addSeries(mySeries, LineAndPointRenderer.class,
\r
115 new LineAndPointFormatter(Color.rgb(0, 255, 0), Color.rgb(200, 0, 0), null));
\r
117 //Set of internal variables for keeping track of the boundaries
\r
118 mySimpleXYPlot.calculateMinMaxVals();
\r
120 mySimpleXYPlot.redraw();
\r
122 minXY=new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),mySimpleXYPlot.getCalculatedMinY().floatValue());
\r
123 maxXY=new PointF(mySimpleXYPlot.getCalculatedMaxX().floatValue(),mySimpleXYPlot.getCalculatedMaxY().floatValue());
\r
128 minNoError = Math.round(mySeries.getX(1).floatValue() +2);
\r
129 maxNoError = Math.round(mySeries.getX(mySeries.size() -1).floatValue()) - 2.0f;
\r
132 private float mPosX;
\r
133 private float mPosY;
\r
135 private float mLastTouchX;
\r
136 private float mLastTouchY;
\r
138 private int mActivePointerId = -1;
\r
141 public boolean onTouch(View arg0, MotionEvent event) {
\r
142 mScaleDetector.onTouchEvent(event);
\r
144 final int action = event.getAction();
\r
145 switch ( action & MotionEvent.ACTION_MASK ) {
\r
146 case MotionEvent.ACTION_DOWN: {
\r
147 final float x = event.getX();
\r
148 final float y = event.getY();
\r
153 mActivePointerId = event.getPointerId(0);
\r
157 case MotionEvent.ACTION_MOVE: {
\r
158 final int pointerIndex = event.findPointerIndex(mActivePointerId);
\r
159 final float x = event.getX(pointerIndex);
\r
160 final float y = event.getY(pointerIndex);
\r
162 if (!mScaleDetector.isInProgress()) {
\r
163 final float dx = x - mLastTouchX;
\r
164 final float dy = y - mLastTouchY;
\r
178 case MotionEvent.ACTION_UP: {
\r
179 mActivePointerId = -1;
\r
183 case MotionEvent.ACTION_CANCEL: {
\r
184 mActivePointerId = -1;
\r
188 case MotionEvent.ACTION_POINTER_UP: {
\r
189 final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
\r
190 final int pointerId = event.getPointerId(pointerIndex);
\r
191 if (pointerId == mActivePointerId) {
\r
192 // This was our active pointer going up. choose a new active pointer and adjust accordingly.
\r
193 final int newPointerIndex = pointerIndex ==0 ? 1:0;
\r
194 mLastTouchX = event.getX(newPointerIndex);
\r
195 mLastTouchY = event.getY(newPointerIndex);
\r
196 mActivePointerId = event.getPointerId(newPointerIndex);
\r
204 private void zoom(float scale) {
\r
205 Log.d(TAG,"zoom by " + scale);
\r
206 float domainSpan = absMaxX - absMinX;
\r
207 Log.d(TAG,"domainSpan = " + domainSpan);
\r
208 float domainMidPoint = absMaxX - domainSpan / 2.0f;
\r
209 Log.d(TAG,"domainMidPoint = " + domainMidPoint);
\r
210 float offset = domainSpan / scale;
\r
211 Log.d(TAG,"offset " + offset);
\r
212 minXY.x=domainMidPoint- offset;
\r
213 Log.d(TAG,"min X " + minXY.x);
\r
214 maxXY.x=domainMidPoint+offset;
\r
215 Log.d(TAG,"max X " + maxXY.x);
\r
217 mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
\r
218 mySimpleXYPlot.redraw();
\r
221 private void scroll(float pan) {
\r
222 float domainSpan = maxXY.x - minXY.x;
\r
223 float step = domainSpan / mySimpleXYPlot.getWidth();
\r
224 float offset = pan * step;
\r
228 mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
\r
229 mySimpleXYPlot.redraw();
\r
232 private void checkBoundaries() {
\r
234 if ( minXY.x < absMinX)
\r
236 // else if ( minXY.x > maxNoError )
\r
237 // minXY.x = maxNoError;
\r
239 if ( maxXY.x > absMaxX)
\r
241 // else if ( maxXY.x < minNoError)
\r
242 // maxXY.x = minNoError;
\r
244 private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
\r
246 public boolean onScale( ScaleGestureDetector detector ) {
\r
247 mScaleFactor *= detector.getScaleFactor();
\r
249 mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 5.0f));
\r
250 zoom(mScaleFactor);
\r