--- /dev/null
+package com.billkuker.rocketry.motorsim.visual.openRocket;\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+import javax.measure.quantity.Duration;\r
+import javax.measure.unit.SI;\r
+\r
+import net.sf.openrocket.database.MotorDatabase;\r
+import net.sf.openrocket.models.atmosphere.AtmosphericConditions;\r
+import net.sf.openrocket.motor.Motor;\r
+import net.sf.openrocket.motor.MotorInstance;\r
+import net.sf.openrocket.util.BugException;\r
+import net.sf.openrocket.util.Coordinate;\r
+import net.sf.openrocket.util.Inertia;\r
+import net.sf.openrocket.util.MathUtil;\r
+\r
+import org.jscience.physics.amount.Amount;\r
+\r
+import com.billkuker.rocketry.motorsim.Burn;\r
+import com.billkuker.rocketry.motorsim.Burn.Interval;\r
+import com.billkuker.rocketry.motorsim.BurnSummary;\r
+import com.billkuker.rocketry.motorsim.ICylindricalChamber;\r
+import com.billkuker.rocketry.motorsim.RocketScience;\r
+\r
+public class OneMotorDatabase implements MotorDatabase {\r
+\r
+ static Burn burn;\r
+ static BurnSummary bs;\r
+ static Coordinate cg[];\r
+ static double[] time;\r
+ static double[] thrust;\r
+\r
+ static Motor motor = new Motor() {\r
+\r
+ @Override\r
+ public Type getMotorType() {\r
+ return Type.SINGLE;\r
+ }\r
+\r
+ @Override\r
+ public String getDesignation() {\r
+ return bs.getRating();\r
+ }\r
+\r
+ @Override\r
+ public String getDesignation(double delay) {\r
+ return bs.getRating() + "-" + ((int) delay);\r
+ }\r
+\r
+ @Override\r
+ public String getDescription() {\r
+ if ( burn == null )\r
+ return "NO MOTOR YET";\r
+ return burn.getMotor().getName();\r
+ }\r
+\r
+ @Override\r
+ public double getDiameter() {\r
+ return ((ICylindricalChamber) burn.getMotor().getChamber()).getOD()\r
+ .doubleValue(SI.METER);\r
+ }\r
+\r
+ @Override\r
+ public double getLength() {\r
+ return ((ICylindricalChamber) burn.getMotor().getChamber())\r
+ .getLength().doubleValue(SI.METER);\r
+ }\r
+\r
+ @Override\r
+ public String getDigest() {\r
+ return "WTF";\r
+ }\r
+\r
+ @Override\r
+ public MotorInstance getInstance() {\r
+\r
+ return new MotorInstance() {\r
+\r
+ private int position;\r
+\r
+ // Previous time step value\r
+ private double prevTime;\r
+\r
+ // Average thrust during previous step\r
+ private double stepThrust;\r
+ // Instantaneous thrust at current time point\r
+ private double instThrust;\r
+\r
+ // Average CG during previous step\r
+ private Coordinate stepCG;\r
+ // Instantaneous CG at current time point\r
+ private Coordinate instCG;\r
+\r
+ private final double unitRotationalInertia;\r
+ private final double unitLongitudinalInertia;\r
+\r
+ private int modID = 0;\r
+\r
+ {\r
+ position = 0;\r
+ prevTime = 0;\r
+ instThrust = 0;\r
+ stepThrust = 0;\r
+ instCG = cg[0];\r
+ stepCG = cg[0];\r
+ unitRotationalInertia = Inertia\r
+ .filledCylinderRotational(getDiameter() / 2);\r
+ unitLongitudinalInertia = Inertia\r
+ .filledCylinderLongitudinal(getDiameter() / 2,\r
+ getLength());\r
+ }\r
+\r
+ @Override\r
+ public double getTime() {\r
+ return prevTime;\r
+ }\r
+\r
+ @Override\r
+ public Coordinate getCG() {\r
+ return stepCG;\r
+ }\r
+\r
+ @Override\r
+ public double getLongitudinalInertia() {\r
+ return unitLongitudinalInertia * stepCG.weight;\r
+ }\r
+\r
+ @Override\r
+ public double getRotationalInertia() {\r
+ return unitRotationalInertia * stepCG.weight;\r
+ }\r
+\r
+ @Override\r
+ public double getThrust() {\r
+ return stepThrust;\r
+ }\r
+\r
+ @Override\r
+ public boolean isActive() {\r
+ return prevTime < time[time.length - 1];\r
+ }\r
+\r
+ @Override\r
+ public void step(double nextTime, double acceleration,\r
+ AtmosphericConditions cond) {\r
+\r
+ if (!(nextTime >= prevTime)) {\r
+ // Also catches NaN\r
+ throw new IllegalArgumentException(\r
+ "Stepping backwards in time, current="\r
+ + prevTime + " new=" + nextTime);\r
+ }\r
+ if (MathUtil.equals(prevTime, nextTime)) {\r
+ return;\r
+ }\r
+\r
+ modID++;\r
+\r
+ if (position >= time.length - 1) {\r
+ // Thrust has ended\r
+ prevTime = nextTime;\r
+ stepThrust = 0;\r
+ instThrust = 0;\r
+ stepCG = cg[cg.length - 1];\r
+ return;\r
+ }\r
+\r
+ // Compute average & instantaneous thrust\r
+ if (nextTime < time[position + 1]) {\r
+\r
+ // Time step between time points\r
+ double nextF = MathUtil.map(nextTime, time[position],\r
+ time[position + 1], thrust[position],\r
+ thrust[position + 1]);\r
+ stepThrust = (instThrust + nextF) / 2;\r
+ instThrust = nextF;\r
+\r
+ } else {\r
+\r
+ // Portion of previous step\r
+ stepThrust = (instThrust + thrust[position + 1]) / 2\r
+ * (time[position + 1] - prevTime);\r
+\r
+ // Whole steps\r
+ position++;\r
+ while ((position < time.length - 1)\r
+ && (nextTime >= time[position + 1])) {\r
+ stepThrust += (thrust[position] + thrust[position + 1])\r
+ / 2 * (time[position + 1] - time[position]);\r
+ position++;\r
+ }\r
+\r
+ // End step\r
+ if (position < time.length - 1) {\r
+ instThrust = MathUtil.map(nextTime, time[position],\r
+ time[position + 1], thrust[position],\r
+ thrust[position + 1]);\r
+ stepThrust += (thrust[position] + instThrust) / 2\r
+ * (nextTime - time[position]);\r
+ } else {\r
+ // Thrust ended during this step\r
+ instThrust = 0;\r
+ }\r
+\r
+ stepThrust /= (nextTime - prevTime);\r
+\r
+ }\r
+\r
+ // Compute average and instantaneous CG (simple average\r
+ // between points)\r
+ Coordinate nextCG;\r
+ if (position < time.length - 1) {\r
+ nextCG = MathUtil.map(nextTime, time[position],\r
+ time[position + 1], cg[position],\r
+ cg[position + 1]);\r
+ } else {\r
+ nextCG = cg[cg.length - 1];\r
+ }\r
+ stepCG = instCG.add(nextCG).multiply(0.5);\r
+ instCG = nextCG;\r
+\r
+ // Update time\r
+ prevTime = nextTime;\r
+ }\r
+\r
+ @Override\r
+ public MotorInstance clone() {\r
+ try {\r
+ return (MotorInstance) super.clone();\r
+ } catch (CloneNotSupportedException e) {\r
+ throw new BugException("CloneNotSupportedException", e);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public int getModID() {\r
+ return modID;\r
+ }\r
+ };\r
+\r
+ }\r
+\r
+ @Override\r
+ public Coordinate getLaunchCG() {\r
+ return new Coordinate();\r
+ }\r
+\r
+ @Override\r
+ public Coordinate getEmptyCG() {\r
+ return new Coordinate();\r
+ }\r
+\r
+ @Override\r
+ public double getBurnTimeEstimate() {\r
+ return bs.thrustTime().doubleValue(SI.SECOND);\r
+ }\r
+\r
+ @Override\r
+ public double getAverageThrustEstimate() {\r
+ return bs.averageThrust().doubleValue(SI.NEWTON);\r
+ }\r
+\r
+ @Override\r
+ public double getMaxThrustEstimate() {\r
+ return bs.maxThrust().doubleValue(SI.NEWTON);\r
+ }\r
+\r
+ @Override\r
+ public double getTotalImpulseEstimate() {\r
+ return bs.totalImpulse().doubleValue(RocketScience.NEWTON_SECOND);\r
+ }\r
+\r
+ @Override\r
+ public double[] getTimePoints() {\r
+ return time;\r
+ }\r
+\r
+ @Override\r
+ public double[] getThrustPoints() {\r
+ return thrust;\r
+ }\r
+\r
+ @Override\r
+ public Coordinate[] getCGPoints() {\r
+ return cg;\r
+ }\r
+\r
+ };\r
+\r
+ static void setBurn(Burn b) {\r
+ burn = b;\r
+ bs = new BurnSummary(b);\r
+\r
+ cg = new Coordinate[burn.getData().size()];\r
+ time = new double[burn.getData().size()];\r
+ thrust = new double[burn.getData().size()];\r
+ \r
+ Coordinate c = new Coordinate();\r
+\r
+ for (int i = 0; i < cg.length; i++) {\r
+ cg[i] = c;\r
+ }\r
+\r
+ int i = 0;\r
+ for (Amount<Duration> t : burn.getData().keySet()) {\r
+ time[i++] = t.doubleValue(SI.SECOND);\r
+ }\r
+\r
+ i = 0;\r
+ for (Interval d : burn.getData().values()) {\r
+ double t = d.thrust.doubleValue(SI.NEWTON);\r
+ t = Math.max(t, 0.0001);\r
+ thrust[i++] = t;\r
+ }\r
+ thrust[0] = 0;\r
+ thrust[thrust.length - 1] = 0;\r
+ }\r
+\r
+ public OneMotorDatabase() {\r
+ super();\r
+ }\r
+\r
+ public List<? extends Motor> findMotors(Motor.Type type,\r
+ String manufacturer, String designation, double diameter,\r
+ double length) {\r
+ List<Motor> ret = new Vector<Motor>();\r
+ System.err.println("Returning " + motor.getDescription());\r
+ ret.add(motor);\r
+ return ret;\r
+ }\r
+\r
+}\r