Reimplement motor handling so the android application relies more heavily on the OR core ThrustCurveMotor class. This involved changing the database schema and querying mechanisms. Rewriting the thrust curve download logic in net.sf.openrocket.android.thrustcurve. Fixing the motor browser, motor details, and burn plot activities. The file parsing now uses the RSE and RSP parsers from OR core.

ExtendedThrustCurveMotor class was created to hold the additional data required by the db ( the id in particular) along with the data which is useful to the browser (case info and impulse class).
This commit is contained in:
Kevin Ruland 2012-01-12 19:51:28 +00:00
parent 4900b84551
commit fe5a8eccfb
20 changed files with 566 additions and 670 deletions

View File

@ -2,7 +2,7 @@
<classpath> <classpath>
<classpathentry kind="src" path="gen"/> <classpathentry kind="src" path="gen"/>
<classpathentry including="l10n/**/*" kind="src" path="core-resources"/> <classpathentry including="l10n/**/*" kind="src" path="core-resources"/>
<classpathentry excluding="net/sf/openrocket/file/CSVExport.java|net/sf/openrocket/file/motor/|net/sf/openrocket/file/rocksim/export/|net/sf/openrocket/gui/|net/sf/openrocket/startup/Startup.java|net/sf/openrocket/startup/Startup2.java|net/sf/openrocket/startup/VersionHelper.java|net/sf/openrocket/utils/" kind="src" path="core"/> <classpathentry excluding="net/sf/openrocket/file/CSVExport.java|net/sf/openrocket/file/rocksim/export/|net/sf/openrocket/gui/|net/sf/openrocket/startup/Startup.java|net/sf/openrocket/startup/Startup2.java|net/sf/openrocket/startup/VersionHelper.java|net/sf/openrocket/utils/|net/sf/openrocket/file/motor/MotorLoaderHelper.java" kind="src" path="core"/>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>

View File

@ -35,6 +35,20 @@
android:editable="false" /> android:editable="false" />
</TableRow> </TableRow>
<TableRow >
<TextView
android:paddingRight="10px"
android:text="Delays" />
<EditText
android:id="@+id/motorDetailsDelays"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.04"
android:editable="false" />
</TableRow>
<TableRow > <TableRow >
<TextView <TextView

View File

@ -1,4 +1,4 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="45dip" android:layout_height="45dip"
android:gravity="center_vertical" android:gravity="center_vertical"
@ -8,7 +8,6 @@
android:id="@+id/motorChildManu" android:id="@+id/motorChildManu"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="45dip" android:layout_height="45dip"
android:layout_alignParentLeft="true"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingLeft="5dip" android:paddingLeft="5dip"
android:paddingRight="5dip" android:paddingRight="5dip"
@ -21,21 +20,48 @@
android:id="@+id/motorChildName" android:id="@+id/motorChildName"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="45dip" android:layout_height="45dip"
android:layout_toRightOf="@id/motorChildManu"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingLeft="5dip" android:paddingLeft="5dip"
android:paddingRight="5dip"
android:text="Motor Name" android:text="Motor Name"
android:textColor="#ffCCCC22" android:textColor="#ffCCCC22"
android:textSize="17dip" android:textSize="17dip"
android:textStyle="bold" > android:textStyle="bold" >
</TextView> </TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="45dip"
android:gravity="center_vertical"
android:text="-"
android:paddingLeft="2dip"
android:paddingRight="2dip"
android:textColor="#ffCCCC22"
android:textSize="17dip"
android:textStyle="bold" >
</TextView>
<TextView
android:id="@+id/motorChildDelays"
android:layout_width="wrap_content"
android:layout_height="45dip"
android:layout_weight="0"
android:gravity="center_vertical"
android:paddingRight="5dip"
android:text=""
android:textColor="#ffCCCC22"
android:textSize="17dip"
android:textStyle="bold" >
</TextView>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2" />
<TextView <TextView
android:id="@+id/motorChildImpulse" android:id="@+id/motorChildImpulse"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="45dip" android:layout_height="45dip"
android:layout_alignParentRight="true"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingLeft="5dip" android:paddingLeft="5dip"
android:paddingRight="5dip" android:paddingRight="5dip"
@ -45,4 +71,4 @@
android:textStyle="bold" > android:textStyle="bold" >
</TextView> </TextView>
</RelativeLayout> </LinearLayout>

View File

@ -2,13 +2,11 @@ package net.sf.openrocket.android;
import java.util.Locale; import java.util.Locale;
import android.preference.PreferenceManager;
import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.l10n.DebugTranslator; import net.sf.openrocket.l10n.DebugTranslator;
import net.sf.openrocket.l10n.ResourceBundleTranslator; import net.sf.openrocket.l10n.ResourceBundleTranslator;
import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.l10n.Translator;
import android.preference.PreferenceManager;
public class Application extends android.app.Application { public class Application extends android.app.Application {
@ -17,7 +15,7 @@ public class Application extends android.app.Application {
// Big B boolean so I can synchronize on it. // Big B boolean so I can synchronize on it.
private static Boolean initialized = false; private static Boolean initialized = false;
public static void initialize() { public void initialize() {
synchronized (initialized) { synchronized (initialized) {
if ( initialized == true ) { if ( initialized == true ) {
return; return;
@ -30,13 +28,7 @@ public class Application extends android.app.Application {
net.sf.openrocket.startup.Application.setPreferences( new PreferencesAdapter() ); net.sf.openrocket.startup.Application.setPreferences( new PreferencesAdapter() );
ThrustCurveMotorSetDatabase db = new ThrustCurveMotorSetDatabase(false) { MotorDatabaseAdapter db = new MotorDatabaseAdapter(this);
@Override
protected void loadMotors() {
}
};
db.startLoading();
net.sf.openrocket.startup.Application.setMotorSetDatabase(db); net.sf.openrocket.startup.Application.setMotorSetDatabase(db);
@ -53,7 +45,6 @@ public class Application extends android.app.Application {
} }
public Application() { public Application() {
initialize();
} }
/* (non-Javadoc) /* (non-Javadoc)
@ -62,6 +53,7 @@ public class Application extends android.app.Application {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
initialize();
PreferencesActivity.initializePreferences(this, PreferenceManager.getDefaultSharedPreferences(this)); PreferencesActivity.initializePreferences(this, PreferenceManager.getDefaultSharedPreferences(this));
} }

View File

@ -0,0 +1,45 @@
package net.sf.openrocket.android;
import java.util.Collections;
import java.util.List;
import net.sf.openrocket.android.db.DbAdapter;
import net.sf.openrocket.android.motor.ExtendedThrustCurveMotor;
import net.sf.openrocket.database.MotorDatabase;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.Motor.Type;
import android.content.Context;
import android.util.Log;
public class MotorDatabaseAdapter implements MotorDatabase {
private final static String TAG = "MotorDatabaseAdapter";
private DbAdapter mDbHelper;
public MotorDatabaseAdapter( Context ctx ) {
mDbHelper = new DbAdapter(ctx);
mDbHelper.open();
}
@Override
public List<? extends Motor> findMotors(Type type, String manufacturer,
String designation, double diameter, double length) {
Log.d(TAG,"find motor: type="+ type.toString());
Log.d(TAG,"find motor: manu="+ manufacturer);
Log.d(TAG,"find motor: designation="+ designation);
Log.d(TAG,"find motor: diameter=" +diameter);
Log.d(TAG,"find motor: length="+ length);
try {
ExtendedThrustCurveMotor m = mDbHelper.getMotorDao().fetchMotor(manufacturer, designation);
if ( m != null ) {
return Collections.singletonList(m.getThrustCurveMotor());
}
} catch ( Exception ex ) {
}
return Collections.<Motor>emptyList();
}
}

View File

@ -0,0 +1,57 @@
package net.sf.openrocket.android.db;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import net.sf.openrocket.util.Coordinate;
abstract class ConversionUtils {
static double[] deserializeArrayOfDouble( byte[] bytes ) throws Exception {
double[] data = null;
if (bytes != null ) {
ObjectInputStream is = new ObjectInputStream( new ByteArrayInputStream(bytes));
data = (double[]) is.readObject();
}
return data;
}
static byte[] serializeArrayOfDouble( double[] data ) throws Exception {
byte[] serObj = null;
if ( data != null ) {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(b);
os.writeObject(data);
os.close();
serObj = b.toByteArray();
}
return serObj;
}
static Coordinate[] deserializeArrayOfCoordinate( byte[] bytes ) throws Exception {
Coordinate[] data = null;
if (bytes != null ) {
ObjectInputStream is = new ObjectInputStream( new ByteArrayInputStream(bytes));
data = (Coordinate[]) is.readObject();
}
return data;
}
static byte[] serializeArrayOfCoordinate( Coordinate[] data ) throws Exception {
byte[] serObj = null;
if ( data != null ) {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(b);
os.writeObject(data);
os.close();
serObj = b.toByteArray();
}
return serObj;
}
}

View File

@ -13,7 +13,7 @@ public class DbAdapter {
private SQLiteDatabase mDb; private SQLiteDatabase mDb;
private static final String DATABASE_NAME = "rocketflightnotebook"; private static final String DATABASE_NAME = "rocketflightnotebook";
private static final int DATABASE_VERSION = 5; private static final int DATABASE_VERSION = 2;
private final Context mCtx; private final Context mCtx;

View File

@ -1,12 +1,10 @@
package net.sf.openrocket.android.db; package net.sf.openrocket.android.db;
import java.io.ByteArrayInputStream; import net.sf.openrocket.android.motor.ExtendedThrustCurveMotor;
import java.io.ByteArrayOutputStream; import net.sf.openrocket.motor.Manufacturer;
import java.io.ObjectInputStream; import net.sf.openrocket.motor.Motor;
import java.io.ObjectOutputStream; import net.sf.openrocket.motor.ThrustCurveMotor;
import java.util.Vector; import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.android.motor.Motor;
import android.content.ContentValues; import android.content.ContentValues;
import android.database.Cursor; import android.database.Cursor;
import android.database.SQLException; import android.database.SQLException;
@ -25,7 +23,8 @@ public class MotorDao {
"create table "+ DATABASE_TABLE + " ( " + "create table "+ DATABASE_TABLE + " ( " +
"_id integer primary key, "+ "_id integer primary key, "+
"unique_name text unique, "+ "unique_name text unique, "+
"name text, "+ "designation text, "+
"delays blob, "+
"diameter number, "+ "diameter number, "+
"tot_impulse_ns number, "+ "tot_impulse_ns number, "+
"avg_thrust_n number, "+ "avg_thrust_n number, "+
@ -36,8 +35,11 @@ public class MotorDao {
"tot_mass_g number,"+ "tot_mass_g number,"+
"case_info text,"+ "case_info text,"+
"manufacturer text," + "manufacturer text," +
"type text," +
"impulse_class text," + "impulse_class text," +
"burndata blob"+ "thrust_data blob,"+
"time_data blob," +
"cg_data blob"+
");"; ");";
MotorDao( SQLiteDatabase mDb ) { MotorDao( SQLiteDatabase mDb ) {
@ -52,54 +54,61 @@ public class MotorDao {
public final static String ID = "_id"; public final static String ID = "_id";
public final static String UNIQUE_NAME = "unique_name"; public final static String UNIQUE_NAME = "unique_name";
public final static String NAME = "name"; public final static String DESIGNATION = "designation";
public final static String DELAYS = "delays";
public final static String DIAMETER = "diameter"; public final static String DIAMETER = "diameter";
public final static String TOTAL_IMPULSE = "tot_impulse_ns"; public final static String TOTAL_IMPULSE = "tot_impulse_ns";
public final static String AVG_THRUST = "avg_thrust_n"; public final static String AVG_THRUST = "avg_thrust_n";
public final static String MAX_THRUST = "max_thrust_n"; public final static String MAX_THRUST = "max_thrust_n";
public final static String BURN_TIME = "burn_time_s"; public final static String BURN_TIME = "burn_time_s";
public final static String LENGTH = "length"; public final static String LENGTH = "length";
public final static String PROP_MASS = "prop_mass_g";
public final static String TOT_MASS = "tot_mass_g";
public final static String BURNDATA = "burndata";
public final static String CASE_INFO = "case_info"; public final static String CASE_INFO = "case_info";
public final static String MANUFACTURER = "manufacturer"; public final static String MANUFACTURER = "manufacturer";
public final static String TYPE = "type";
public final static String IMPULSE_CLASS = "impulse_class"; public final static String IMPULSE_CLASS = "impulse_class";
public final static String THRUST_DATA = "thrust_data";
public final static String TIME_DATA = "time_data";
public final static String CG_DATA = "cg_data";
public long insertOrUpdateMotor(Motor mi) { private final static String[] ALL_COLS = new String[] {
ID,
DESIGNATION ,
DELAYS ,
DIAMETER ,
TOTAL_IMPULSE ,
AVG_THRUST ,
MAX_THRUST ,
BURN_TIME ,
LENGTH,
CASE_INFO,
TYPE,
IMPULSE_CLASS,
MANUFACTURER,
THRUST_DATA,
TIME_DATA,
CG_DATA
};
public long insertOrUpdateMotor(ExtendedThrustCurveMotor mi) throws Exception {
ContentValues initialValues = new ContentValues(); ContentValues initialValues = new ContentValues();
initialValues.put(ID, mi.getMotor_id()); final ThrustCurveMotor tcm = mi.getThrustCurveMotor();
initialValues.put(NAME, mi.getName()); initialValues.put(ID, mi.getId());
initialValues.put(DIAMETER,mi.getDiameter()); initialValues.put(UNIQUE_NAME, tcm.getManufacturer()+tcm.getDesignation());
initialValues.put(TOTAL_IMPULSE,mi.getTotalImpulse()); initialValues.put(DESIGNATION, tcm.getDesignation());
initialValues.put(AVG_THRUST,mi.getAvgThrust()); initialValues.put(DELAYS, ConversionUtils.serializeArrayOfDouble(tcm.getStandardDelays()));
initialValues.put(MAX_THRUST,mi.getMaxThrust()); initialValues.put(DIAMETER,tcm.getDiameter());
initialValues.put(BURN_TIME,mi.getBurnTime()); initialValues.put(TOTAL_IMPULSE,tcm.getTotalImpulseEstimate());
initialValues.put(LENGTH, mi.getLength()); initialValues.put(AVG_THRUST,tcm.getAverageThrustEstimate());
initialValues.put(PROP_MASS, mi.getPropMass()); initialValues.put(MAX_THRUST,tcm.getMaxThrustEstimate());
initialValues.put(TOT_MASS,mi.getTotMass()); initialValues.put(BURN_TIME,tcm.getBurnTimeEstimate());
initialValues.put(LENGTH, tcm.getLength());
initialValues.put(CASE_INFO, mi.getCaseInfo()); initialValues.put(CASE_INFO, mi.getCaseInfo());
initialValues.put(MANUFACTURER,mi.getManufacturer()); initialValues.put(TYPE, tcm.getMotorType().getName());
initialValues.put(IMPULSE_CLASS,mi.getImpulseClass()); initialValues.put(IMPULSE_CLASS,mi.getImpulseClass());
initialValues.put(UNIQUE_NAME, mi.getManufacturer()+mi.getName()); initialValues.put(MANUFACTURER,tcm.getManufacturer().getSimpleName());
{ initialValues.put(THRUST_DATA, ConversionUtils.serializeArrayOfDouble(tcm.getThrustPoints()));
// Serialize the Vector of burn data initialValues.put(TIME_DATA,ConversionUtils.serializeArrayOfDouble(tcm.getTimePoints()));
Vector<Double> burndata = mi.getBurndata(); initialValues.put(CG_DATA,ConversionUtils.serializeArrayOfCoordinate(tcm.getCGPoints()));
byte[] serObj = null;
if ( burndata != null ) {
try {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(b);
os.writeObject(burndata);
os.close();
serObj = b.toByteArray();
} catch (Exception ex) {
Log.d(TAG,"unable to serialze burndata");
}
}
initialValues.put(BURNDATA, serObj);
}
Log.d(TAG,"insertOrUpdate Motor"); Log.d(TAG,"insertOrUpdate Motor");
long rv = mDb.insertWithOnConflict(DATABASE_TABLE, null, initialValues,SQLiteDatabase.CONFLICT_REPLACE); long rv = mDb.insertWithOnConflict(DATABASE_TABLE, null, initialValues,SQLiteDatabase.CONFLICT_REPLACE);
@ -126,26 +135,12 @@ public class MotorDao {
*/ */
public Cursor fetchAllInGroups( String groupCol, String groupVal ) { public Cursor fetchAllInGroups( String groupCol, String groupVal ) {
return mDb.query(DATABASE_TABLE, return mDb.query(DATABASE_TABLE,
/* columns */new String[] { /* columns */ ALL_COLS,
ID, /* selection */groupCol + "=?",
NAME, /* selection args*/new String[] {groupVal},
DIAMETER , /* groupby */null,
TOTAL_IMPULSE, /* having*/null,
AVG_THRUST , /* orderby*/ DESIGNATION );
MAX_THRUST ,
BURN_TIME ,
LENGTH,
PROP_MASS,
TOT_MASS,
CASE_INFO,
IMPULSE_CLASS,
MANUFACTURER
},
/* selection */groupCol + "=?",
/* selection args*/new String[] {groupVal},
/* groupby */null,
/* having*/null,
/* orderby*/ NAME );
} }
@ -175,52 +170,61 @@ public class MotorDao {
*/ */
public Cursor fetchAllMotors() { public Cursor fetchAllMotors() {
return mDb.query(DATABASE_TABLE, return mDb.query(DATABASE_TABLE,
/* columns */new String[] { /* columns */ ALL_COLS,
ID, /* selection */null,
NAME, /* selection args*/null,
DIAMETER , /* groupby */null,
TOTAL_IMPULSE, /* having*/null,
AVG_THRUST , /* orderby*/null);
MAX_THRUST ,
BURN_TIME ,
LENGTH,
PROP_MASS,
TOT_MASS,
CASE_INFO,
IMPULSE_CLASS,
MANUFACTURER
},
/* selection */null,
/* selection args*/null,
/* groupby */null,
/* having*/null,
/* orderby*/null);
} }
public Motor fetchMotor(Long id ) throws SQLException { private ExtendedThrustCurveMotor hydrateMotor( Cursor mCursor ) throws Exception {
ExtendedThrustCurveMotor mi = new ExtendedThrustCurveMotor();
mi.setId(mCursor.getLong(mCursor.getColumnIndex(ID)));
mi.setCaseInfo(mCursor.getString(mCursor.getColumnIndex(CASE_INFO)));
mi.setImpulseClass(mCursor.getString(mCursor.getColumnIndex(IMPULSE_CLASS)));
{
String designation = mCursor.getString(mCursor.getColumnIndex(DESIGNATION));
double[] delays = ConversionUtils.deserializeArrayOfDouble( mCursor.getBlob(mCursor.getColumnIndex(DELAYS)));
double diameter = mCursor.getDouble(mCursor.getColumnIndex(DIAMETER));
double totImpulse = mCursor.getDouble(mCursor.getColumnIndex(TOTAL_IMPULSE));
double avgImpulse = mCursor.getDouble(mCursor.getColumnIndex(AVG_THRUST));
double maxThrust = mCursor.getDouble(mCursor.getColumnIndex(MAX_THRUST));
double length = mCursor.getDouble(mCursor.getColumnIndex(LENGTH));
Motor.Type type = Motor.Type.fromName( mCursor.getString(mCursor.getColumnIndex(TYPE)));
Manufacturer manufacturer = Manufacturer.getManufacturer( mCursor.getString( mCursor.getColumnIndex(MANUFACTURER)));
double[] thrustData = ConversionUtils.deserializeArrayOfDouble( mCursor.getBlob(mCursor.getColumnIndex(THRUST_DATA)));
double[] timeData = ConversionUtils.deserializeArrayOfDouble( mCursor.getBlob(mCursor.getColumnIndex(TIME_DATA)));
Coordinate[] cgData = ConversionUtils.deserializeArrayOfCoordinate( mCursor.getBlob(mCursor.getColumnIndex(CG_DATA)));
ThrustCurveMotor tcm = new ThrustCurveMotor(manufacturer,
designation,
"",
type,
delays,
diameter,
length,
timeData,
thrustData,
cgData
);
mi.setThrustCurveMotor(tcm);
}
return mi;
}
public ExtendedThrustCurveMotor fetchMotor(Long id ) throws Exception {
Cursor mCursor = mDb.query(DATABASE_TABLE, Cursor mCursor = mDb.query(DATABASE_TABLE,
/* columns */new String[] { /* columns */ ALL_COLS,
ID, /* selection */ID + "="+id,
NAME , /* selection args*/null,
DIAMETER , /* groupby */null,
TOTAL_IMPULSE , /* having*/null,
AVG_THRUST , /* orderby*/null);
MAX_THRUST ,
BURN_TIME ,
LENGTH,
PROP_MASS,
TOT_MASS,
CASE_INFO,
IMPULSE_CLASS,
MANUFACTURER,
BURNDATA
},
/* selection */ID + "="+id,
/* selection args*/null,
/* groupby */null,
/* having*/null,
/* orderby*/null);
if ( mCursor == null ) { if ( mCursor == null ) {
return null; return null;
} }
@ -229,37 +233,7 @@ public class MotorDao {
return null; return null;
} }
mCursor.moveToFirst(); mCursor.moveToFirst();
Motor mi = new Motor(); return hydrateMotor(mCursor);
mi.setMotor_id(mCursor.getLong(mCursor.getColumnIndex(ID)));
mi.setName(mCursor.getString(mCursor.getColumnIndex(NAME)));
mi.setDiameter(mCursor.getLong(mCursor.getColumnIndex(DIAMETER)));
mi.setTotalImpulse(mCursor.getFloat(mCursor.getColumnIndex(TOTAL_IMPULSE)));
mi.setAvgThrust(mCursor.getFloat(mCursor.getColumnIndex(AVG_THRUST)));
mi.setMaxThrust(mCursor.getFloat(mCursor.getColumnIndex(MAX_THRUST)));
mi.setBurnTime(mCursor.getFloat(mCursor.getColumnIndex(BURN_TIME)));
mi.setLength(mCursor.getFloat(mCursor.getColumnIndex(LENGTH)));
mi.setPropMass(mCursor.getDouble(mCursor.getColumnIndex(PROP_MASS)));
mi.setCaseInfo(mCursor.getString(mCursor.getColumnIndex(CASE_INFO)));
mi.setTotMass(mCursor.getDouble(mCursor.getColumnIndex(TOT_MASS)));
mi.setManufacturer(mCursor.getString(mCursor.getColumnIndex(MANUFACTURER)));
mi.setImpulseClass(mCursor.getString(mCursor.getColumnIndex(IMPULSE_CLASS)));
{
// Deserialize burndata column
byte[] serObj = mCursor.getBlob(mCursor.getColumnIndex(BURNDATA));
Vector<Double> burndata = null;
if (serObj != null ) {
try {
ObjectInputStream is = new ObjectInputStream( new ByteArrayInputStream(serObj));
burndata = (Vector<Double>) is.readObject();
}
catch (Exception ex) {
Log.d(TAG,"cannot deserialize burndata");
}
}
mi.setBurndata(burndata);
}
return mi;
} }
finally { finally {
mCursor.close(); mCursor.close();
@ -267,4 +241,51 @@ public class MotorDao {
} }
public ExtendedThrustCurveMotor fetchMotor(String manufacturerShortName, String designation ) throws Exception {
Cursor mCursor = mDb.query(DATABASE_TABLE,
/* columns */ ALL_COLS,
/* selection */MANUFACTURER + "='"+manufacturerShortName + "' and "+DESIGNATION+"='"+designation+"'",
/* selection args*/null,
/* groupby */null,
/* having*/null,
/* orderby*/null);
if ( mCursor == null ) {
return null;
}
try {
if (mCursor.getCount() == 0) {
return null;
}
mCursor.moveToFirst();
return hydrateMotor(mCursor);
}
finally {
mCursor.close();
}
}
public static String extractPrettyDelayString( Cursor c ) {
byte[] blob = c.getBlob(c.getColumnIndex(MotorDao.DELAYS));
String s = "";
try {
double[] delayarry = ConversionUtils.deserializeArrayOfDouble(blob);
boolean first = true;
for( double d:delayarry ) {
if (!first) {
s += ",";
} else {
first = false;
}
if ( d == Motor.PLUGGED ) {
s+= "P";
} else {
s += Math.round(d);
}
}
} catch ( Exception ex ) {
}
return s;
}
} }

View File

@ -1,5 +1,7 @@
package net.sf.openrocket.android.motor; package net.sf.openrocket.android.motor;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector; import java.util.Vector;
import net.sf.openrocket.R; import net.sf.openrocket.R;
@ -27,28 +29,19 @@ public class BurnPlotFragment extends Fragment implements OnTouchListener {
private final static String TAG = "BurnPlotFragment"; private final static String TAG = "BurnPlotFragment";
private ExtendedThrustCurveMotor motor;
private XYPlot mySimpleXYPlot; private XYPlot mySimpleXYPlot;
private SimpleXYSeries mySeries; private SimpleXYSeries mySeries;
private PointF minXY; private PointF minXY;
private PointF maxXY; private PointF maxXY;
private float absMinX; private float absMinX;
private float absMaxX; private float absMaxX;
private float minNoError;
private float maxNoError;
private ScaleGestureDetector mScaleDetector; private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f; private float mScaleFactor = 1.f;
public static BurnPlotFragment initializeBurnPlotHelper( Motor motor ) {
BurnPlotFragment h = new BurnPlotFragment();
Bundle args = new Bundle();
args.putSerializable("Motor", motor);
h.setArguments(args);
return h;
}
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
@ -69,42 +62,47 @@ public class BurnPlotFragment extends Fragment implements OnTouchListener {
mySimpleXYPlot = (XYPlot) v.findViewById(R.id.xyplot); mySimpleXYPlot = (XYPlot) v.findViewById(R.id.xyplot);
mySimpleXYPlot.setOnTouchListener(this); mySimpleXYPlot.setOnTouchListener(this);
mScaleDetector = new ScaleGestureDetector(v.getContext(), new ScaleListener()); mScaleDetector = new ScaleGestureDetector(v.getContext(), new ScaleListener());
// Motor motor = getMotor();
// init(motor);
return v; return v;
} }
void init( Motor motor ) { private static List<Double> fromArray( double[] arry ) {
List<Double> l = new ArrayList<Double>(arry.length);
for( double d: arry ) {
l.add(d);
}
return l;
}
void init( ExtendedThrustCurveMotor motor ) {
mySimpleXYPlot.setUserDomainOrigin(0); mySimpleXYPlot.setUserDomainOrigin(0);
mySimpleXYPlot.setUserRangeOrigin(0); mySimpleXYPlot.setUserRangeOrigin(0);
mySimpleXYPlot.setRangeLabel("impuse (n)"); mySimpleXYPlot.setRangeLabel("impuse (n)");
mySimpleXYPlot.setDomainLabel("time (s)"); mySimpleXYPlot.setDomainLabel("time (s)");
mySimpleXYPlot.addMarker(new YValueMarker(motor.getAvgThrust(),"average" )); mySimpleXYPlot.addMarker(new YValueMarker(motor.getThrustCurveMotor().getAverageThrustEstimate(),"average" ));
mySimpleXYPlot.disableAllMarkup(); mySimpleXYPlot.disableAllMarkup();
Vector<Double> data = null;
try {
data = motor.getBurndata();
} catch ( Exception ex ) {
}
if ( data == null || data.size() == 0 ) {
data = new Vector<Double>();
data.add(0.0);
data.add(0.0);
data.add(1.0);
data.add(1.0);
}
Log.d("plot","data = " + data.toString());
mySeries = new SimpleXYSeries(data, SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED,motor.getName()); try {
mySeries = new SimpleXYSeries(
fromArray(motor.getThrustCurveMotor().getTimePoints()),
fromArray(motor.getThrustCurveMotor().getThrustPoints()),
motor.getThrustCurveMotor().getDesignation());
} catch ( Exception ex ) {
Vector<Double> data = new Vector<Double>();
data.add(0.0);
data.add(0.0);
data.add(1.0);
data.add(1.0);
mySeries = new SimpleXYSeries(data, SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED,"no data");
}
mySimpleXYPlot.addSeries(mySeries, LineAndPointRenderer.class, mySimpleXYPlot.addSeries(mySeries, LineAndPointRenderer.class,
new LineAndPointFormatter(Color.rgb(0, 255, 0), Color.rgb(200, 0, 0), null)); new LineAndPointFormatter(Color.rgb(0, 255, 0), Color.rgb(200, 0, 0), null));
//Set of internal variables for keeping track of the boundaries //Set of internal variables for keeping track of the boundaries
mySimpleXYPlot.calculateMinMaxVals(); mySimpleXYPlot.calculateMinMaxVals();
mySimpleXYPlot.redraw(); mySimpleXYPlot.redraw();
minXY=new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),mySimpleXYPlot.getCalculatedMinY().floatValue()); minXY=new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),mySimpleXYPlot.getCalculatedMinY().floatValue());
@ -112,9 +110,7 @@ public class BurnPlotFragment extends Fragment implements OnTouchListener {
absMinX = minXY.x; absMinX = minXY.x;
absMaxX = maxXY.x; absMaxX = maxXY.x;
minNoError = Math.round(mySeries.getX(1).floatValue() +2);
maxNoError = Math.round(mySeries.getX(mySeries.size() -1).floatValue()) - 2.0f;
} }
private float mPosX; private float mPosX;
@ -141,7 +137,7 @@ public class BurnPlotFragment extends Fragment implements OnTouchListener {
mActivePointerId = event.getPointerId(0); mActivePointerId = event.getPointerId(0);
break; break;
} }
case MotionEvent.ACTION_MOVE: { case MotionEvent.ACTION_MOVE: {
final int pointerIndex = event.findPointerIndex(mActivePointerId); final int pointerIndex = event.findPointerIndex(mActivePointerId);
final float x = event.getX(pointerIndex); final float x = event.getX(pointerIndex);
@ -150,29 +146,29 @@ public class BurnPlotFragment extends Fragment implements OnTouchListener {
if (!mScaleDetector.isInProgress()) { if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX; final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY; final float dy = y - mLastTouchY;
mPosX += dx; mPosX += dx;
mPosY += dy; mPosY += dy;
scroll(dx); scroll(dx);
// do scroll. // do scroll.
} }
mLastTouchX = x; mLastTouchX = x;
mLastTouchY = y; mLastTouchY = y;
break; break;
} }
case MotionEvent.ACTION_UP: { case MotionEvent.ACTION_UP: {
mActivePointerId = -1; mActivePointerId = -1;
break; break;
} }
case MotionEvent.ACTION_CANCEL: { case MotionEvent.ACTION_CANCEL: {
mActivePointerId = -1; mActivePointerId = -1;
break; break;
} }
case MotionEvent.ACTION_POINTER_UP: { case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
final int pointerId = event.getPointerId(pointerIndex); final int pointerId = event.getPointerId(pointerIndex);
@ -218,16 +214,16 @@ public class BurnPlotFragment extends Fragment implements OnTouchListener {
} }
private void checkBoundaries() { private void checkBoundaries() {
if ( minXY.x < absMinX) if ( minXY.x < absMinX)
minXY.x = absMinX; minXY.x = absMinX;
// else if ( minXY.x > maxNoError ) // else if ( minXY.x > maxNoError )
// minXY.x = maxNoError; // minXY.x = maxNoError;
if ( maxXY.x > absMaxX) if ( maxXY.x > absMaxX)
maxXY.x = absMaxX; maxXY.x = absMaxX;
// else if ( maxXY.x < minNoError) // else if ( maxXY.x < minNoError)
// maxXY.x = minNoError; // maxXY.x = minNoError;
} }
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override @Override

View File

@ -0,0 +1,62 @@
package net.sf.openrocket.android.motor;
import net.sf.openrocket.motor.ThrustCurveMotor;
public class ExtendedThrustCurveMotor {
private Long id;
private String caseInfo;
private String impulseClass;
private ThrustCurveMotor thrustCurveMotor;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the caseInfo
*/
public String getCaseInfo() {
return caseInfo;
}
/**
* @param caseInfo the caseInfo to set
*/
public void setCaseInfo(String caseInfo) {
this.caseInfo = caseInfo;
}
/**
* @return the impulseClass
*/
public String getImpulseClass() {
return impulseClass;
}
/**
* @param impulseClass the impulseClass to set
*/
public void setImpulseClass(String impulseClass) {
this.impulseClass = impulseClass;
}
/**
* @return the thrustCurveMotor
*/
public ThrustCurveMotor getThrustCurveMotor() {
return thrustCurveMotor;
}
/**
* @param thrustCurveMotor the thrustCurveMotor to set
*/
public void setThrustCurveMotor(ThrustCurveMotor thrustCurveMotor) {
this.thrustCurveMotor = thrustCurveMotor;
}
}

View File

@ -1,107 +0,0 @@
package net.sf.openrocket.android.motor;
import java.io.Serializable;
import java.util.Vector;
public class Motor implements Serializable {
private Long motor_id;
private String name;
private String impulseClass;
private String manufacturer;
private Long diameter;
private String caseInfo;
private Float avgThrust;
private Float maxThrust;
private Float totalImpulse;
private Float burnTime;
private Float length;
private Double propMass;
private Double totMass;
private Vector<Double> burndata;
public Long getMotor_id() {
return motor_id;
}
public void setMotor_id(Long motor_id) {
this.motor_id = motor_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getImpulseClass() {
return impulseClass;
}
public void setImpulseClass(String impulseClass) {
this.impulseClass = impulseClass;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public Long getDiameter() {
return diameter;
}
public void setDiameter(Long diameter) {
this.diameter = diameter;
}
public String getCaseInfo() {
return caseInfo;
}
public void setCaseInfo(String caseInfo) {
this.caseInfo = caseInfo;
}
public Float getAvgThrust() {
return avgThrust;
}
public void setAvgThrust(Float avgThrust) {
this.avgThrust = avgThrust;
}
public Float getMaxThrust() {
return maxThrust;
}
public void setMaxThrust(Float maxThrust) {
this.maxThrust = maxThrust;
}
public Float getTotalImpulse() {
return totalImpulse;
}
public void setTotalImpulse(Float totalImpulse) {
this.totalImpulse = totalImpulse;
}
public Float getBurnTime() {
return burnTime;
}
public void setBurnTime(Float burnTime) {
this.burnTime = burnTime;
}
public Float getLength() {
return length;
}
public void setLength(Float length) {
this.length = length;
}
public Double getPropMass() {
return propMass;
}
public void setPropMass(Double propMass) {
this.propMass = propMass;
}
public Double getTotMass() {
return totMass;
}
public void setTotMass(Double totMass) {
this.totMass = totMass;
}
public Vector<Double> getBurndata() {
return burndata;
}
public void setBurndata(Vector<Double> burndata) {
this.burndata = burndata;
}
}

View File

@ -1,6 +1,7 @@
package net.sf.openrocket.android.motor; package net.sf.openrocket.android.motor;
import net.sf.openrocket.R; import net.sf.openrocket.R;
import net.sf.openrocket.android.db.DbAdapter;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
@ -19,7 +20,7 @@ implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListen
private SlidingDrawer slidingDrawer; private SlidingDrawer slidingDrawer;
private ImageView handle; private ImageView handle;
private Motor motor; private ExtendedThrustCurveMotor motor;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -28,7 +29,18 @@ implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListen
setContentView(R.layout.motor_detail); setContentView(R.layout.motor_detail);
Intent i = getIntent(); Intent i = getIntent();
motor = (Motor) i.getSerializableExtra("Motor"); long motorId = i.getLongExtra("Motor",-1);
DbAdapter mDbHelper = new DbAdapter(this);
mDbHelper.open();
try {
motor = mDbHelper.getMotorDao().fetchMotor(motorId);
} catch ( Exception e ) {
}
mDbHelper.close();
BurnPlotFragment burnPlot = (BurnPlotFragment) getSupportFragmentManager().findFragmentById(R.id.burnPlotFragment); BurnPlotFragment burnPlot = (BurnPlotFragment) getSupportFragmentManager().findFragmentById(R.id.burnPlotFragment);
burnPlot.init(motor); burnPlot.init(motor);

View File

@ -1,6 +1,9 @@
package net.sf.openrocket.android.motor; package net.sf.openrocket.android.motor;
import java.util.Arrays;
import net.sf.openrocket.R; import net.sf.openrocket.R;
import net.sf.openrocket.motor.ThrustCurveMotor;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -12,6 +15,7 @@ public class MotorDetailsFragment extends Fragment {
EditText manuField; EditText manuField;
EditText nameField; EditText nameField;
EditText delaysField;
EditText caseField; EditText caseField;
EditText impulseClassField; EditText impulseClassField;
EditText diameterField; EditText diameterField;
@ -23,6 +27,7 @@ public class MotorDetailsFragment extends Fragment {
View v = inflater.inflate(R.layout.motor_detail_form, container, false); View v = inflater.inflate(R.layout.motor_detail_form, container, false);
manuField = (EditText) v.findViewById(R.id.motorDetailsManufacturer); manuField = (EditText) v.findViewById(R.id.motorDetailsManufacturer);
nameField = (EditText) v.findViewById(R.id.motorDetailsName); nameField = (EditText) v.findViewById(R.id.motorDetailsName);
delaysField = (EditText) v.findViewById(R.id.motorDetailsDelays);
caseField = (EditText) v.findViewById(R.id.motorDetailsCaseInfo); caseField = (EditText) v.findViewById(R.id.motorDetailsCaseInfo);
impulseClassField = (EditText) v.findViewById(R.id.motorDetailsImpuseClass); impulseClassField = (EditText) v.findViewById(R.id.motorDetailsImpuseClass);
diameterField = (EditText) v.findViewById(R.id.motorDetailsDiameter); diameterField = (EditText) v.findViewById(R.id.motorDetailsDiameter);
@ -30,13 +35,15 @@ public class MotorDetailsFragment extends Fragment {
return v; return v;
} }
public void init( Motor m ) { public void init( ExtendedThrustCurveMotor m ) {
manuField.setText( m.getManufacturer()); ThrustCurveMotor tcm = m.getThrustCurveMotor();
nameField.setText( m.getName() ); manuField.setText( tcm.getManufacturer().getDisplayName());
nameField.setText( tcm.getDesignation() );
delaysField.setText( Arrays.toString(tcm.getStandardDelays()) );
caseField.setText( m.getCaseInfo()); caseField.setText( m.getCaseInfo());
impulseClassField.setText( m.getImpulseClass()); impulseClassField.setText( m.getImpulseClass());
diameterField.setText( m.getDiameter().toString() ); diameterField.setText( String.valueOf(tcm.getDiameter()*1000.0) );
lengthField.setText( m.getLength().toString() ); lengthField.setText( String.valueOf(tcm.getLength()*1000.0) );
} }

View File

@ -21,7 +21,8 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.CursorTreeAdapter; import android.widget.CursorTreeAdapter;
import android.widget.ExpandableListView; import android.widget.ExpandableListView;
import android.widget.SimpleCursorTreeAdapter; import android.widget.ResourceCursorTreeAdapter;
import android.widget.TextView;
public class MotorHierarchicalBrowser public class MotorHierarchicalBrowser
@ -48,17 +49,15 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
private DbAdapter mDbHelper; private DbAdapter mDbHelper;
public class MotorHierarchicalListAdapter extends SimpleCursorTreeAdapter public class MotorHierarchicalListAdapter extends ResourceCursorTreeAdapter
{ {
// Note that the constructor does not take a Cursor. This is done to avoid querying the // Note that the constructor does not take a Cursor. This is done to avoid querying the
// database on the main thread. // database on the main thread.
public MotorHierarchicalListAdapter(Context context, Cursor cursor, int groupLayout, public MotorHierarchicalListAdapter(Context context, Cursor cursor, int groupLayout,
int childLayout, String[] groupFrom, int[] groupTo, String[] childrenFrom, int childLayout ) {
int[] childrenTo) {
super(context, cursor, groupLayout, groupFrom, groupTo, childLayout, childrenFrom, super(context, cursor, groupLayout, childLayout);
childrenTo);
} }
@Override @Override
@ -77,6 +76,46 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
return groupPosition; return groupPosition;
} }
//new String[] { MotorDao.MANUFACTURER, MotorDao.DESIGNATION, MotorDao.CASE_INFO, MotorDao.TOTAL_IMPULSE }, // Number for child layouts
//new int[] { R.id.motorChildManu, R.id.motorChildName, R.id.motorChildDelays, R.id.motorChildImpulse }
/* (non-Javadoc)
* @see android.widget.CursorTreeAdapter#bindChildView(android.view.View, android.content.Context, android.database.Cursor, boolean)
*/
@Override
protected void bindChildView(View arg0, Context arg1, Cursor arg2,
boolean arg3) {
TextView manu = (TextView) arg0.findViewById(R.id.motorChildManu);
manu.setText( arg2.getString(arg2.getColumnIndex(MotorDao.MANUFACTURER)));
TextView desig = (TextView) arg0.findViewById(R.id.motorChildName);
desig.setText( arg2.getString(arg2.getColumnIndex(MotorDao.DESIGNATION)));
TextView delays = (TextView) arg0.findViewById(R.id.motorChildDelays);
delays.setText( MotorDao.extractPrettyDelayString( arg2 ));
TextView totImpulse = (TextView) arg0.findViewById(R.id.motorChildImpulse);
totImpulse.setText( arg2.getString(arg2.getColumnIndex(MotorDao.TOTAL_IMPULSE)));
}
/* (non-Javadoc)
* @see android.widget.CursorTreeAdapter#bindGroupView(android.view.View, android.content.Context, android.database.Cursor, boolean)
*/
@Override
protected void bindGroupView(View view, Context context, Cursor cursor,
boolean isExpanded) {
TextView v = (TextView) view.findViewById(R.id.motorGroup);
if ( MotorDao.DIAMETER.equals(groupColumn)) {
double d = cursor.getDouble( cursor.getColumnIndex(groupColumn));
v.setText( String.valueOf(Math.round(d * 1000.0)) );
} else {
v.setText( cursor.getString( cursor.getColumnIndex(groupColumn)));
}
}
} }
@Override @Override
@ -167,10 +206,9 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
@Override @Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
super.onChildClick(parent, v, groupPosition, childPosition, id); super.onChildClick(parent, v, groupPosition, childPosition, id);
Motor m = mDbHelper.getMotorDao().fetchMotor(id);
//Intent i = new Intent(this, BurnPlotActivity.class); //Intent i = new Intent(this, BurnPlotActivity.class);
Intent i = new Intent(this,MotorDetails.class); Intent i = new Intent(this,MotorDetails.class);
i.putExtra("Motor", m); i.putExtra("Motor", id);
startActivity(i); startActivity(i);
return true; return true;
} }
@ -221,11 +259,7 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
this, this,
motorCursor, motorCursor,
R.layout.motor_list_group, R.layout.motor_list_group,
R.layout.motor_list_child, R.layout.motor_list_child);
new String[] { groupColumn }, // Name for group layouts
new int[] { R.id.motorGroup },
new String[] { MotorDao.MANUFACTURER, MotorDao.NAME, MotorDao.TOTAL_IMPULSE }, // Number for child layouts
new int[] { R.id.motorChildManu, R.id.motorChildName, R.id.motorChildImpulse });
setListAdapter(mAdapter); setListAdapter(mAdapter);
} }
} }

View File

@ -12,7 +12,7 @@ public class DownloadResponse {
public void add( MotorBurnFile mbd ) { public void add( MotorBurnFile mbd ) {
MotorBurnFile currentData = data.get(mbd.getMotorId()); MotorBurnFile currentData = data.get(mbd.getMotorId());
if ( currentData == null || currentData.getDatapoints().size() < mbd.getDatapoints().size() ) { if ( currentData == null || currentData.getThrustCurveMotor() == null ) {
data.put(mbd.getMotorId(),mbd); data.put(mbd.getMotorId(),mbd);
} }
} }

View File

@ -86,7 +86,7 @@ public class DownloadResponseParser {
new EndTextElementListener() { new EndTextElementListener() {
@Override @Override
public void end(String arg0) { public void end(String arg0) {
currentMotor.setMotor_id(Integer.parseInt(arg0)); currentMotor.setMotorId(Integer.parseInt(arg0));
} }
} }
); );

View File

@ -1,89 +1,91 @@
package net.sf.openrocket.android.thrustcurve; package net.sf.openrocket.android.thrustcurve;
import java.util.Vector; import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import net.sf.openrocket.file.motor.RASPMotorLoader;
import net.sf.openrocket.file.motor.RockSimMotorLoader;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.ThrustCurveMotor;
public class MotorBurnFile { public class MotorBurnFile {
private Integer motor_id; private Integer motorId;
private String filetype; private String filetype;
private Float length; private ThrustCurveMotor thrustCurveMotor;
private String delays;
private Double propWeightG;
private Double totWeightG;
private Vector<Double> datapoints = new Vector<Double>();
public void init() { public void init() {
this.motor_id = null; this.motorId = null;
this.filetype = null; this.filetype = null;
this.length = null; this.thrustCurveMotor = null;
this.delays = null;
this.propWeightG = null;
this.totWeightG = null;
this.datapoints = new Vector<Double>();
} }
@Override @Override
public MotorBurnFile clone() { public MotorBurnFile clone() {
MotorBurnFile clone = new MotorBurnFile(); MotorBurnFile clone = new MotorBurnFile();
clone.motor_id = this.motor_id; clone.motorId = this.motorId;
clone.filetype = this.filetype; clone.filetype = this.filetype;
clone.length = this.length; clone.thrustCurveMotor = this.thrustCurveMotor;
clone.delays = this.delays;
clone.propWeightG = this.propWeightG;
clone.totWeightG = this.totWeightG;
clone.datapoints = this.datapoints;
return clone; return clone;
} }
public void decodeFile(String data){ public void decodeFile(String data) {
if (SupportedFileTypes.RASP_FORMAT.equals(filetype)) { try {
RaspBurnFile.parse(this,data); if (SupportedFileTypes.RASP_FORMAT.equals(filetype)) {
} else if (SupportedFileTypes.ROCKSIM_FORMAT.equals(filetype) ){ RASPMotorLoader loader = new RASPMotorLoader();
RSEBurnFile.parse(this,data); List<Motor> motors = loader.load( new StringReader(data), "download");
this.thrustCurveMotor = (ThrustCurveMotor) motors.get(0);
} else if (SupportedFileTypes.ROCKSIM_FORMAT.equals(filetype) ){
RockSimMotorLoader loader = new RockSimMotorLoader();
List<Motor> motors = loader.load( new StringReader(data), "download");
this.thrustCurveMotor = (ThrustCurveMotor) motors.get(0);
}
} catch ( IOException ex ) {
this.thrustCurveMotor = null;
} }
} }
/**
* @return the motor_id
*/
public Integer getMotorId() { public Integer getMotorId() {
return motor_id; return motorId;
}
public String getFileType() {
return filetype;
}
public Float getLength() {
return length;
}
public String getDelays() {
return delays;
}
public Double getPropWeightG() {
return propWeightG;
}
public Double getTotWeightG() {
return totWeightG;
}
public Vector<Double> getDatapoints() {
return datapoints;
} }
void setMotor_id(Integer motor_id) { /**
this.motor_id = motor_id; * @param motor_id the motor_id to set
*/
public void setMotorId(Integer motorId) {
this.motorId = motorId;
} }
void setFiletype(String filetype ) {
/**
* @return the filetype
*/
public String getFiletype() {
return filetype;
}
/**
* @param filetype the filetype to set
*/
public void setFiletype(String filetype) {
this.filetype = filetype; this.filetype = filetype;
} }
void setLength(Float length) {
this.length = length; /**
* @return the thrustCurveMotor
*/
public ThrustCurveMotor getThrustCurveMotor() {
return thrustCurveMotor;
} }
void setDelays(String delays) {
this.delays = delays; /**
} * @param thrustCurveMotor the thrustCurveMotor to set
void setPropWeightG(Double propWeightG) { */
this.propWeightG = propWeightG; public void setThrustCurveMotor(ThrustCurveMotor thrustCurveMotor) {
} this.thrustCurveMotor = thrustCurveMotor;
void setTotWeightG(Double totWeightG) {
this.totWeightG = totWeightG;
}
void setDatapoints(Vector<Double> datapoints) {
this.datapoints = datapoints;
} }
} }

View File

@ -1,131 +0,0 @@
package net.sf.openrocket.android.thrustcurve;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Vector;
import org.xml.sax.Attributes;
import android.sax.Element;
import android.sax.RootElement;
import android.sax.StartElementListener;
import android.util.Log;
import android.util.Xml;
class RSEBurnFile extends MotorBurnFile {
private final static String TAG = "RSEBurnFile";
static void parse( MotorBurnFile that, String filecontents ) {
parse(that, new ByteArrayInputStream(filecontents.getBytes()) );
}
private final static String root_tag = "engine-database";
private final static String engine_list_tag = "engine-list";
private final static String engine_tag = "engine";
private final static String delays_attr = "delays";
private final static String len_attr = "len";
private final static String propwgt_attr = "propWt";
private final static String totwgt_attr = "initWt";
private final static String data_tag = "data";
private final static String eng_data_tag = "eng-data";
private final static String time_attr="t";
private final static String force_attr="f";
static void parse( final MotorBurnFile that, InputStream in ) {
RootElement rootEl = new RootElement(root_tag);
Element engineEl = rootEl.getChild(engine_list_tag).getChild(engine_tag);
final Vector<Double> datapoints = new Vector<Double>();
Log.d(TAG,"parsing start");
engineEl.setStartElementListener(
new StartElementListener() {
@Override
public void start(Attributes arg0) {
Log.d(TAG,"start engineEl");
that.setPropWeightG(Double.parseDouble(arg0.getValue(propwgt_attr)));
that.setTotWeightG(Double.parseDouble(arg0.getValue(totwgt_attr)));
that.setLength(Float.parseFloat(arg0.getValue(len_attr)));
that.setDelays(arg0.getValue(delays_attr));
Log.d(TAG, "me is now " + that.toString());
}
}
);
Element datapointEl = engineEl.getChild(data_tag).getChild(eng_data_tag);
datapointEl.setStartElementListener(
new StartElementListener() {
@Override
public void start(Attributes attributes) {
Double x = Double.parseDouble(attributes.getValue(time_attr));
Double y = Double.parseDouble(attributes.getValue(force_attr));
Log.d(TAG, "add data point " + x + "," + y);
datapoints.add(x);
datapoints.add(y);
}
}
);
try {
Xml.parse(in, Xml.Encoding.UTF_8, rootEl.getContentHandler());
} catch (Exception e) {
throw new RuntimeException(e);
}
that.setDatapoints(datapoints);
}
}
//
// <engine-database>
// <engine-list>
// <engine FDiv="10" FFix="1" FStep="-1." Isp="202.11" Itot="8.919" Type="single-use" auto-calc-cg="1" auto-calc-mass="1" avgThrust="3.795" burn-time="2.35" cgDiv="10" cgFix="1" cgStep="-1." code="C4" delays="3,5,7" dia="18." exitDia="0." initWt="17." len="50." mDiv="10" mFix="1" mStep="-1." massFrac="26.47" mfg="Apogee" peakThrust="11.31" propWt="4.5" tDiv="10" tFix="1" tStep="-1." throatDia="0.">
// <comments>Apogee C4 RASP.ENG file made from NAR published data
// File produced September 4, 2000
// The total impulse, peak thrust, average thrust and burn time are
// the same as the averaged static test data on the NAR web site in
// the certification file. The curve drawn with these data points is as
// close to the certification curve as can be with such a limited
// number of points (32) allowed with wRASP up to v1.6.
// </comments>
// <data>
// <eng-data cg="25." f="0." m="4.5" t="0."/>
// <eng-data cg="25." f="3.23" m="4.48533" t="0.018"/>
// <eng-data cg="25." f="6.874" m="4.42671" t="0.041"/>
// <eng-data cg="25." f="8.779" m="4.00814" t="0.147"/>
// <eng-data cg="25." f="10.683" m="3.28643" t="0.294"/>
// <eng-data cg="25." f="11.31" m="2.89252" t="0.365"/>
// <eng-data cg="25." f="10.521" m="2.76585" t="0.388"/>
// <eng-data cg="25." f="8.779" m="2.649" t="0.412"/>
// <eng-data cg="25." f="7.04" m="2.53328" t="0.441"/>
// <eng-data cg="25." f="4.555" m="2.46308" t="0.465"/>
// <eng-data cg="25." f="3.479" m="2.33337" t="0.529"/>
// <eng-data cg="25." f="2.981" m="2.1704" t="0.629"/>
// <eng-data cg="25." f="3.23" m="2.1328" t="0.653"/>
// <eng-data cg="25." f="2.816" m="2.03366" t="0.718"/>
// <eng-data cg="25." f="2.733" m="1.84469" t="0.853"/>
// <eng-data cg="25." f="2.65" m="1.5568" t="1.065"/>
// <eng-data cg="25." f="2.567" m="1.30938" t="1.253"/>
// <eng-data cg="25." f="2.401" m="1.05873" t="1.453"/>
// <eng-data cg="25." f="2.484" m="0.761739" t="1.694"/>
// <eng-data cg="25." f="2.484" m="0.636413" t="1.794"/>
// <eng-data cg="25." f="2.733" m="0.612724" t="1.812"/>
// <eng-data cg="25." f="2.401" m="0.575165" t="1.841"/>
// <eng-data cg="25." f="2.401" m="0.446759" t="1.947"/>
// <eng-data cg="25." f="2.401" m="0.246881" t="2.112"/>
// <eng-data cg="25." f="2.401" m="0.0978809" t="2.235"/>
// <eng-data cg="25." f="2.236" m="0.0429024" t="2.282"/>
// <eng-data cg="25." f="1.656" m="0.0134478" t="2.312"/>
// <eng-data cg="25." f="0.662" m="0.003507" t="2.329"/>
// <eng-data cg="25." f="0." m="-0." t="2.35"/>
// </data>
// </engine>
// </engine-list>
// </engine-database>
//

View File

@ -1,85 +0,0 @@
package net.sf.openrocket.android.thrustcurve;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StringReader;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.util.Log;
class RaspBurnFile{
private final static String TAG = "RaspBurnFile";
private final static int HEADER = 0;
private final static int DATA = 1;
private final static Pattern headerPattern = Pattern.compile("(\\S*)\\s+(\\S*)\\s+(\\S*)\\s+(\\S*)\\s+(\\S*)\\s+(\\S*)\\s+(\\S*)");
private final static Pattern dataPattern = Pattern.compile("(\\S*)\\s+(\\S*)");
static void parse( MotorBurnFile that, String filecontents ) {
int state = HEADER;
LineNumberReader reader = new LineNumberReader( new StringReader(filecontents));
Vector<Double> datapoints = new Vector<Double>();
String line;
Matcher m;
try {
while ( (line = reader.readLine()) != null ) {
line = line.trim();
Log.d("RASP",line);
if ( line.startsWith(";")) {
continue;
}
switch (state) {
case HEADER:
Log.d("RASP","header");
m = headerPattern.matcher(line);
if ( m.matches() ) {
Log.d("RASP","header matches");
/*motorName = m.group(1);*/
/*diameter = Integer.decode(m.group(2));*/
that.setLength(Float.parseFloat(m.group(3)) );
String delays = m.group(4);
if ( delays != null ) {
delays = delays.replace("-", ",");
that.setDelays(delays);
}
that.setPropWeightG(Double.parseDouble(m.group(5))*1000.0);
that.setTotWeightG(Double.parseDouble(m.group(6))*1000.0);
/*manufacturer = m.group(7);*/
}
state = DATA;
break;
case DATA:
Log.d("RASP","data");
m = dataPattern.matcher(line);
if ( m.matches() ) {
Log.d("RASP","data matches");
Double x = Double.parseDouble(m.group(1));
Double y = Double.parseDouble(m.group(2));
Log.d("RASP","data matches ("+x+","+y+")");
datapoints.add(x);
datapoints.add(y);
}
break;
}
that.setDatapoints(datapoints);
}
} catch (IOException ex ) {
Log.d(TAG,"Unable to parse Rasp file: " + ex);
}
}
}

View File

@ -1,10 +1,8 @@
package net.sf.openrocket.android.thrustcurve; package net.sf.openrocket.android.thrustcurve;
import java.util.Vector;
import net.sf.openrocket.R; import net.sf.openrocket.R;
import net.sf.openrocket.android.db.DbAdapter; import net.sf.openrocket.android.db.DbAdapter;
import net.sf.openrocket.android.motor.Motor; import net.sf.openrocket.android.motor.ExtendedThrustCurveMotor;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
@ -161,29 +159,12 @@ public class TCQueryActivity extends Activity {
MotorBurnFile b = new ThrustCurveAPI().downloadData(mi.getMotor_id()); MotorBurnFile b = new ThrustCurveAPI().downloadData(mi.getMotor_id());
if ( b != null ) {
if ( b.getLength() != null ) {
mi.setLength( b.getLength() );
}
if ( b.getPropWeightG() != null ) {
mi.setProp_mass_g(b.getPropWeightG());
}
if ( b.getTotWeightG() != null ) {
mi.setTot_mass_g(b.getTotWeightG());
}
if ( b.getDelays() != null ) {
mi.setDelays(b.getDelays());
}
mi.setBurndata(b.getDatapoints());
}
Log.d(TAG, mi.toString()); Log.d(TAG, mi.toString());
// convert to Motors. One per delay. ExtendedThrustCurveMotor m = new ExtendedThrustCurveMotor();
Motor m = new Motor();
// Base name of motor. m.setThrustCurveMotor( b.getThrustCurveMotor() );
String name = mi.getCommon_name() + "-";
m.setManufacturer(mi.getManufacturer_abbr());
// Convert impulse class. ThrustCurve puts mmx, 1/4a and 1/2a as A. // Convert impulse class. ThrustCurve puts mmx, 1/4a and 1/2a as A.
m.setImpulseClass(mi.getImpulse_class()); m.setImpulseClass(mi.getImpulse_class());
if ( "a".equalsIgnoreCase(mi.getImpulse_class())) { if ( "a".equalsIgnoreCase(mi.getImpulse_class())) {
@ -195,15 +176,7 @@ public class TCQueryActivity extends Activity {
m.setImpulseClass("1/8A"); m.setImpulseClass("1/8A");
} }
} }
m.setAvgThrust(mi.getAvg_thrust_n());
m.setBurndata(mi.getBurndata());
m.setBurnTime(mi.getBurn_time_s());
m.setDiameter(mi.getDiameter() == null ? null : mi.getDiameter().longValue());
m.setLength(mi.getLength());
m.setMaxThrust(mi.getMax_thrust_n());
m.setPropMass(mi.getProp_mass_g());
m.setTotalImpulse(mi.getTot_impulse_ns());
m.setTotMass(mi.getTot_mass_g());
// Convert Case Info. // Convert Case Info.
if ( mi.getCase_info() == null if ( mi.getCase_info() == null
|| "single use".equalsIgnoreCase(mi.getCase_info()) || "single use".equalsIgnoreCase(mi.getCase_info())
@ -213,31 +186,9 @@ public class TCQueryActivity extends Activity {
m.setCaseInfo(mi.getCase_info()); m.setCaseInfo(mi.getCase_info());
} }
Vector<String> delays = new Vector<String>(); Log.d(TAG,"adding motor " + m.toString());
{ // Write motor.
String delaysString = mi.getDelays(); mDbHelper.getMotorDao().insertOrUpdateMotor(m);
if ( delaysString != null ) {
delaysString = delaysString.trim();
}
if ( delaysString == null || "".equals(delaysString)) {
delays.add("");
} else {
String[] delayString = delaysString.split(",");
for( String d : delayString ) {
delays.add( d.trim() );
}
}
}
for( String d: delays ) {
if ( "100".equals(d) ) {
m.setName(name + "P");
} else {
m.setName(name + d);
}
mDbHelper.getMotorDao().insertOrUpdateMotor(m);
}
} }
if ( total < res.getMatches() ) { if ( total < res.getMatches() ) {
handler.post( new Error( total + " motors downloaded, " + res.getMatches() + " matched. Try restricting the query more.") ); handler.post( new Error( total + " motors downloaded, " + res.getMatches() + " matched. Try restricting the query more.") );