1 package net.sf.openrocket.android.motor;
\r
3 import java.util.ArrayList;
\r
4 import java.util.List;
\r
5 import java.util.Vector;
\r
7 import net.sf.openrocket.R;
\r
8 import net.sf.openrocket.android.db.DbAdapter;
\r
9 import net.sf.openrocket.android.util.AndroidLogWrapper;
\r
10 import android.graphics.Color;
\r
11 import android.graphics.Paint;
\r
12 import android.graphics.PointF;
\r
13 import android.os.Bundle;
\r
14 import android.support.v4.app.Fragment;
\r
15 import android.view.LayoutInflater;
\r
16 import android.view.MotionEvent;
\r
17 import android.view.ScaleGestureDetector;
\r
18 import android.view.View;
\r
19 import android.view.View.OnTouchListener;
\r
20 import android.view.ViewGroup;
\r
22 import com.androidplot.xy.BoundaryMode;
\r
23 import com.androidplot.xy.LineAndPointFormatter;
\r
24 import com.androidplot.xy.LineAndPointRenderer;
\r
25 import com.androidplot.xy.SimpleXYSeries;
\r
26 import com.androidplot.xy.XYPlot;
\r
27 import com.androidplot.xy.YValueMarker;
\r
29 public class BurnPlotFragment extends Fragment implements OnTouchListener {
\r
31 private ExtendedThrustCurveMotor motor;
\r
32 private long motorId;
\r
34 private XYPlot mySimpleXYPlot;
\r
35 private SimpleXYSeries mySeries;
\r
36 private PointF minXY;
\r
37 private PointF maxXY;
\r
39 private float absMinX;
\r
40 private float absMaxX;
\r
42 private ScaleGestureDetector mScaleDetector;
\r
43 private float mScaleFactor = 1.f;
\r
45 public static BurnPlotFragment newInstance( long motorId ) {
\r
46 BurnPlotFragment frag = new BurnPlotFragment();
\r
47 Bundle bundle = new Bundle();
\r
48 bundle.putLong("motorId", motorId);
\r
49 frag.setArguments(bundle);
\r
54 public void onCreate(Bundle savedInstanceState) {
\r
55 AndroidLogWrapper.d(BurnPlotFragment.class,"onCreate");
\r
57 if ( savedInstanceState!= null) {
\r
58 motorId = savedInstanceState.getLong("motorId",-1);
\r
60 Bundle b = getArguments();
\r
61 motorId = b.getLong("motorId");
\r
64 DbAdapter mDbHelper = new DbAdapter(getActivity());
\r
68 motor = mDbHelper.getMotorDao().fetchMotor(motorId);
\r
69 } catch ( Exception e ) {
\r
74 super.onCreate(savedInstanceState);
\r
78 public void onSaveInstanceState(Bundle outState) {
\r
79 super.onSaveInstanceState(outState);
\r
80 outState.putLong("motorId", motorId);
\r
84 public View onCreateView(LayoutInflater inflater, ViewGroup container,
\r
85 Bundle savedInstanceState) {
\r
86 AndroidLogWrapper.d(BurnPlotFragment.class,"onCreateView");
\r
87 View v = inflater.inflate(R.layout.motor_burn, container, false);
\r
88 mySimpleXYPlot = (XYPlot) v.findViewById(R.id.xyplot);
\r
89 mySimpleXYPlot.setOnTouchListener(this);
\r
90 mScaleDetector = new ScaleGestureDetector(v.getContext(), new ScaleListener());
\r
95 private static List<Double> fromArray( double[] arry ) {
\r
96 List<Double> l = new ArrayList<Double>(arry.length);
\r
97 for( double d: arry ) {
\r
103 private void init( ExtendedThrustCurveMotor motor ) {
\r
105 mySimpleXYPlot.setUserDomainOrigin(0);
\r
106 mySimpleXYPlot.setUserRangeOrigin(0);
\r
107 mySimpleXYPlot.setRangeLabel("impuse (n)");
\r
108 mySimpleXYPlot.setDomainLabel("time (s)");
\r
109 YValueMarker average = new YValueMarker(motor.getThrustCurveMotor().getAverageThrustEstimate(),"average" );
\r
110 average.getLinePaint().setColor(Color.BLACK);
\r
111 average.getTextPaint().setColor(Color.BLACK);
\r
112 mySimpleXYPlot.addMarker( average );
\r
113 mySimpleXYPlot.disableAllMarkup();
\r
116 mySeries = new SimpleXYSeries(
\r
117 fromArray(motor.getThrustCurveMotor().getTimePoints()),
\r
118 fromArray(motor.getThrustCurveMotor().getThrustPoints()),
\r
119 motor.getThrustCurveMotor().getManufacturer().getDisplayName() + " " + motor.getThrustCurveMotor().getDesignation()
\r
121 } catch ( Exception ex ) {
\r
123 Vector<Double> data = new Vector<Double>();
\r
128 mySeries = new SimpleXYSeries(data, SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED,"no data");
\r
131 LineAndPointFormatter formatter= new LineAndPointFormatter(Color.RED, Color.GREEN, Color.GREEN);
\r
133 formatter.getLinePaint().setShadowLayer(0, 0, 0, 0);
\r
134 formatter.getVertexPaint().setShadowLayer(0, 0, 0, 0);
\r
135 mySimpleXYPlot.addSeries(mySeries, LineAndPointRenderer.class,formatter);
\r
137 //Set of internal variables for keeping track of the boundaries
\r
138 mySimpleXYPlot.calculateMinMaxVals();
\r
140 mySimpleXYPlot.redraw();
\r
142 minXY=new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),mySimpleXYPlot.getCalculatedMinY().floatValue());
\r
143 maxXY=new PointF(mySimpleXYPlot.getCalculatedMaxX().floatValue(),mySimpleXYPlot.getCalculatedMaxY().floatValue());
\r
150 private float mPosX;
\r
151 private float mPosY;
\r
153 private float mLastTouchX;
\r
154 private float mLastTouchY;
\r
156 private int mActivePointerId = -1;
\r
159 public boolean onTouch(View arg0, MotionEvent event) {
\r
160 mScaleDetector.onTouchEvent(event);
\r
162 final int action = event.getAction();
\r
163 switch ( action & MotionEvent.ACTION_MASK ) {
\r
164 case MotionEvent.ACTION_DOWN: {
\r
165 final float x = event.getX();
\r
166 final float y = event.getY();
\r
171 mActivePointerId = event.getPointerId(0);
\r
175 case MotionEvent.ACTION_MOVE: {
\r
176 final int pointerIndex = event.findPointerIndex(mActivePointerId);
\r
177 final float x = event.getX(pointerIndex);
\r
178 final float y = event.getY(pointerIndex);
\r
180 if (!mScaleDetector.isInProgress()) {
\r
181 final float dx = x - mLastTouchX;
\r
182 final float dy = y - mLastTouchY;
\r
196 case MotionEvent.ACTION_UP: {
\r
197 mActivePointerId = -1;
\r
201 case MotionEvent.ACTION_CANCEL: {
\r
202 mActivePointerId = -1;
\r
206 case MotionEvent.ACTION_POINTER_UP: {
\r
207 final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
\r
208 final int pointerId = event.getPointerId(pointerIndex);
\r
209 if (pointerId == mActivePointerId) {
\r
210 // This was our active pointer going up. choose a new active pointer and adjust accordingly.
\r
211 final int newPointerIndex = pointerIndex ==0 ? 1:0;
\r
212 mLastTouchX = event.getX(newPointerIndex);
\r
213 mLastTouchY = event.getY(newPointerIndex);
\r
214 mActivePointerId = event.getPointerId(newPointerIndex);
\r
222 private void zoom(float scale) {
\r
223 AndroidLogWrapper.d(BurnPlotFragment.class,"zoom by " + scale);
\r
224 float domainSpan = absMaxX - absMinX;
\r
225 AndroidLogWrapper.d(BurnPlotFragment.class,"domainSpan = " + domainSpan);
\r
226 float domainMidPoint = absMaxX - domainSpan / 2.0f;
\r
227 AndroidLogWrapper.d(BurnPlotFragment.class,"domainMidPoint = " + domainMidPoint);
\r
228 float offset = domainSpan / scale;
\r
229 AndroidLogWrapper.d(BurnPlotFragment.class,"offset " + offset);
\r
230 minXY.x=domainMidPoint- offset;
\r
231 AndroidLogWrapper.d(BurnPlotFragment.class,"min X " + minXY.x);
\r
232 maxXY.x=domainMidPoint+offset;
\r
233 AndroidLogWrapper.d(BurnPlotFragment.class,"max X " + maxXY.x);
\r
235 mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
\r
236 mySimpleXYPlot.redraw();
\r
239 private void scroll(float pan) {
\r
240 float domainSpan = maxXY.x - minXY.x;
\r
241 float step = domainSpan / mySimpleXYPlot.getWidth();
\r
242 float offset = pan * step;
\r
246 mySimpleXYPlot.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
\r
247 mySimpleXYPlot.redraw();
\r
250 private void checkBoundaries() {
\r
252 if ( minXY.x < absMinX)
\r
254 // else if ( minXY.x > maxNoError )
\r
255 // minXY.x = maxNoError;
\r
257 if ( maxXY.x > absMaxX)
\r
259 // else if ( maxXY.x < minNoError)
\r
260 // maxXY.x = minNoError;
\r
262 private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
\r
264 public boolean onScale( ScaleGestureDetector detector ) {
\r
265 mScaleFactor *= detector.getScaleFactor();
\r
267 mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 5.0f));
\r
268 zoom(mScaleFactor);
\r