<classpathentry kind="src" path="test"/>\r
<classpathentry kind="src" path="motors"/>\r
<classpathentry kind="src" path="gui"/>\r
+ <classpathentry kind="src" path="gpl"/>\r
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>\r
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>\r
<classpathentry kind="con" path="org.eclipse.ajdt.core.ASPECTJRT_CONTAINER"/>\r
--- /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
--- /dev/null
+package com.billkuker.rocketry.motorsim.visual.openRocket;\r
+\r
+import java.awt.event.MouseAdapter;\r
+import java.awt.event.MouseEvent;\r
+import java.io.File;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+import javax.measure.unit.SI;\r
+import javax.swing.JScrollPane;\r
+import javax.swing.JTable;\r
+import javax.swing.SwingUtilities;\r
+import javax.swing.table.AbstractTableModel;\r
+\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.document.Simulation;\r
+import net.sf.openrocket.file.RocketLoadException;\r
+import net.sf.openrocket.file.openrocket.OpenRocketLoader;\r
+import net.sf.openrocket.gui.plot.PlotConfiguration;\r
+import net.sf.openrocket.gui.plot.SimulationPlotDialog;\r
+import net.sf.openrocket.gui.util.SwingPreferences;\r
+import net.sf.openrocket.l10n.ResourceBundleTranslator;\r
+import net.sf.openrocket.rocketcomponent.MotorMount;\r
+import net.sf.openrocket.rocketcomponent.RocketComponent;\r
+import net.sf.openrocket.simulation.exception.SimulationException;\r
+import net.sf.openrocket.startup.Application;\r
+import net.sf.openrocket.unit.UnitGroup;\r
+\r
+import org.jscience.physics.amount.Amount;\r
+\r
+import com.billkuker.rocketry.motorsim.Burn;\r
+import com.billkuker.rocketry.motorsim.Motor;\r
+import com.billkuker.rocketry.motorsim.RocketScience;\r
+import com.billkuker.rocketry.motorsim.RocketScience.UnitPreference;\r
+import com.billkuker.rocketry.motorsim.visual.workbench.BurnWatcher;\r
+\r
+public class RocketSimTable extends JScrollPane implements BurnWatcher,\r
+ RocketScience.UnitPreferenceListener {\r
+ static final long serialVersionUID = 1L;\r
+\r
+ static {\r
+ Application.setBaseTranslator(new ResourceBundleTranslator(\r
+ "l10n.messages"));\r
+ Application.setMotorSetDatabase(new OneMotorDatabase());\r
+ Application.setPreferences(new SwingPreferences());\r
+\r
+ }\r
+\r
+ class Entry {\r
+ Entry(Motor m, Simulation s, Burn b) {\r
+ this.m = m;\r
+ this.s = s;\r
+ this.b = b;\r
+ }\r
+\r
+ boolean ready = false;\r
+ Simulation s;\r
+ Motor m;\r
+ Burn b;\r
+ }\r
+\r
+ List<Entry> entries = new Vector<Entry>();\r
+\r
+ class TM extends AbstractTableModel {\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ @Override\r
+ public String getColumnName(int col) {\r
+ switch (col) {\r
+ case 0:\r
+ return "Motor";\r
+ case 1:\r
+ return "Apogee";\r
+ case 2:\r
+ return "Vmax";\r
+ case 3:\r
+ return "Vdeploy";\r
+ case 4:\r
+ return "Vground";\r
+ case 5:\r
+ return "Tapogee";\r
+ case 6:\r
+ return "Tflight";\r
+ }\r
+ return "??";\r
+ }\r
+\r
+ @Override\r
+ public int getColumnCount() {\r
+ return 7;\r
+ }\r
+\r
+ @Override\r
+ public int getRowCount() {\r
+ return entries.size();\r
+ }\r
+\r
+ @Override\r
+ public Object getValueAt(int row, int col) {\r
+ Entry e = entries.get(row);\r
+ if (e == null)\r
+ return "???";\r
+ if (e.ready == false)\r
+ return "...";\r
+ switch (col) {\r
+ case 0:\r
+ return e.m.getName();\r
+ case 1:\r
+ return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
+ .getSimulatedData().getMaxAltitude(), SI.METER));\r
+ case 2:\r
+ return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
+ .getSimulatedData().getMaxVelocity(),\r
+ SI.METERS_PER_SECOND));\r
+ case 3:\r
+ return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
+ .getSimulatedData().getDeploymentVelocity(),\r
+ SI.METERS_PER_SECOND));\r
+ case 4:\r
+ return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
+ .getSimulatedData().getGroundHitVelocity(),\r
+ SI.METERS_PER_SECOND));\r
+ case 5:\r
+ return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
+ .getSimulatedData().getTimeToApogee(), SI.SECOND));\r
+ case 6:\r
+ return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
+ .getSimulatedData().getFlightTime(), SI.SECOND));\r
+ }\r
+ return "??";\r
+ }\r
+\r
+ }\r
+\r
+ private TM tm = new TM();\r
+ private JTable table = new JTable(tm);\r
+ private OpenRocketDocument doc;\r
+\r
+ public RocketSimTable() {\r
+ setViewportView(table);\r
+ RocketScience.addUnitPreferenceListener(this);\r
+ table.addMouseListener(new MouseAdapter() {\r
+ public void mouseClicked(MouseEvent e) {\r
+ if (e.getClickCount() == 2) {\r
+ Entry entry = entries.get(table.getSelectedRow());\r
+ SimulationPlotDialog.showPlot(SwingUtilities\r
+ .getWindowAncestor(RocketSimTable.this), entry.s,\r
+ PlotConfiguration.DEFAULT_CONFIGURATIONS[0]\r
+ .resetUnits());\r
+ }\r
+ }\r
+ });\r
+ preferredUnitsChanged();\r
+ }\r
+\r
+ public void openRocket(File f) throws RocketLoadException {\r
+ this.doc = new OpenRocketLoader().load(f);\r
+ }\r
+\r
+ private Entry toEntry(Burn b) {\r
+ final Entry e = new Entry(b.getMotor(), doc.getSimulation(0).copy(), b);\r
+ OneMotorDatabase.setBurn(b);\r
+\r
+ e.s.getConfiguration().getMotorConfigurationID();\r
+ Iterator<RocketComponent> iterator = doc.getRocket().iterator();\r
+ while (iterator.hasNext()) {\r
+ RocketComponent c = iterator.next();\r
+ if (c instanceof MotorMount) {\r
+ ((MotorMount) c).setMotorDelay(e.s.getConfiguration()\r
+ .getMotorConfigurationID(), b.getMotor()\r
+ .getEjectionDelay().doubleValue(SI.SECOND));\r
+ }\r
+ }\r
+\r
+ tm.fireTableDataChanged();\r
+ new Thread() {\r
+ @Override\r
+ public void run() {\r
+ try {\r
+ e.s.simulate();\r
+ e.ready = true;\r
+ tm.fireTableDataChanged();\r
+ } catch (SimulationException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+\r
+ }\r
+ }.start();\r
+\r
+ return e;\r
+ }\r
+\r
+ @Override\r
+ public void replace(Burn oldBurn, Burn newBurn) {\r
+ if (doc == null) {\r
+ return; // TODO, deal with changing rockets\r
+ }\r
+\r
+ if (oldBurn != null) {\r
+ for (int i = 0; i < entries.size(); i++) {\r
+ if (entries.get(i).b == oldBurn) {\r
+ if (newBurn != null) {\r
+ entries.set(i, toEntry(newBurn));\r
+ } else {\r
+ entries.remove(i);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ } else {\r
+ entries.add(toEntry(newBurn));\r
+ }\r
+ tm.fireTableDataChanged();\r
+ }\r
+\r
+ @Override\r
+ public void preferredUnitsChanged() {\r
+ tm.fireTableDataChanged();\r
+ if (UnitPreference.getUnitPreference() == UnitPreference.NONSI) {\r
+ System.err.println("NONSI");\r
+ UnitGroup.setDefaultImperialUnits();\r
+ } else {\r
+ System.err.println("SI");\r
+ UnitGroup.setDefaultMetricUnits();\r
+ }\r
+ }\r
+}\r
--- /dev/null
+package com.billkuker.rocketry.motorsim.visual.openRocket;\r
+\r
+import java.io.File;\r
+\r
+import javax.swing.JFrame;\r
+\r
+import com.billkuker.rocketry.motorsim.Burn;\r
+import com.billkuker.rocketry.motorsim.RocketScience.UnitPreference;\r
+import com.billkuker.rocketry.motorsim.motors.kuker.PVC9;\r
+\r
+public class Test {\r
+\r
+ /**\r
+ * @param args\r
+ */\r
+ public static void main(String[] args) throws Exception {\r
+ \r
+ UnitPreference.setUnitPreference(UnitPreference.NONSI);\r
+\r
+ JFrame frame = new JFrame();\r
+ frame.setSize(1024, 768);\r
+\r
+ RocketSimTable st = new RocketSimTable();\r
+ st.openRocket(new File("simple.ork"));\r
+\r
+ com.billkuker.rocketry.motorsim.Motor m = new PVC9();\r
+ Burn b = new Burn(m);\r
+ b.burn();\r
+ st.replace(null, b);\r
+\r
+ frame.setContentPane(st);\r
+ frame.setVisible(true);\r
+\r
+ }\r
+\r
+}\r
+++ /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
+++ /dev/null
-package com.billkuker.rocketry.motorsim.visual.openRocket;\r
-\r
-import java.awt.event.MouseAdapter;\r
-import java.awt.event.MouseEvent;\r
-import java.io.File;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Vector;\r
-\r
-import javax.measure.unit.SI;\r
-import javax.swing.JScrollPane;\r
-import javax.swing.JTable;\r
-import javax.swing.SwingUtilities;\r
-import javax.swing.table.AbstractTableModel;\r
-\r
-import net.sf.openrocket.document.OpenRocketDocument;\r
-import net.sf.openrocket.document.Simulation;\r
-import net.sf.openrocket.file.RocketLoadException;\r
-import net.sf.openrocket.file.openrocket.OpenRocketLoader;\r
-import net.sf.openrocket.gui.plot.PlotConfiguration;\r
-import net.sf.openrocket.gui.plot.SimulationPlotDialog;\r
-import net.sf.openrocket.gui.util.SwingPreferences;\r
-import net.sf.openrocket.l10n.ResourceBundleTranslator;\r
-import net.sf.openrocket.rocketcomponent.MotorMount;\r
-import net.sf.openrocket.rocketcomponent.RocketComponent;\r
-import net.sf.openrocket.simulation.exception.SimulationException;\r
-import net.sf.openrocket.startup.Application;\r
-import net.sf.openrocket.unit.UnitGroup;\r
-\r
-import org.jscience.physics.amount.Amount;\r
-\r
-import com.billkuker.rocketry.motorsim.Burn;\r
-import com.billkuker.rocketry.motorsim.Motor;\r
-import com.billkuker.rocketry.motorsim.RocketScience;\r
-import com.billkuker.rocketry.motorsim.RocketScience.UnitPreference;\r
-import com.billkuker.rocketry.motorsim.visual.workbench.BurnWatcher;\r
-\r
-public class RocketSimTable extends JScrollPane implements BurnWatcher,\r
- RocketScience.UnitPreferenceListener {\r
- static final long serialVersionUID = 1L;\r
-\r
- static {\r
- Application.setBaseTranslator(new ResourceBundleTranslator(\r
- "l10n.messages"));\r
- Application.setMotorSetDatabase(new OneMotorDatabase());\r
- Application.setPreferences(new SwingPreferences());\r
-\r
- }\r
-\r
- class Entry {\r
- Entry(Motor m, Simulation s, Burn b) {\r
- this.m = m;\r
- this.s = s;\r
- this.b = b;\r
- }\r
-\r
- boolean ready = false;\r
- Simulation s;\r
- Motor m;\r
- Burn b;\r
- }\r
-\r
- List<Entry> entries = new Vector<Entry>();\r
-\r
- class TM extends AbstractTableModel {\r
- private static final long serialVersionUID = 1L;\r
-\r
- @Override\r
- public String getColumnName(int col) {\r
- switch (col) {\r
- case 0:\r
- return "Motor";\r
- case 1:\r
- return "Apogee";\r
- case 2:\r
- return "Vmax";\r
- case 3:\r
- return "Vdeploy";\r
- case 4:\r
- return "Vground";\r
- case 5:\r
- return "Tapogee";\r
- case 6:\r
- return "Tflight";\r
- }\r
- return "??";\r
- }\r
-\r
- @Override\r
- public int getColumnCount() {\r
- return 7;\r
- }\r
-\r
- @Override\r
- public int getRowCount() {\r
- return entries.size();\r
- }\r
-\r
- @Override\r
- public Object getValueAt(int row, int col) {\r
- Entry e = entries.get(row);\r
- if (e == null)\r
- return "???";\r
- if (e.ready == false)\r
- return "...";\r
- switch (col) {\r
- case 0:\r
- return e.m.getName();\r
- case 1:\r
- return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
- .getSimulatedData().getMaxAltitude(), SI.METER));\r
- case 2:\r
- return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
- .getSimulatedData().getMaxVelocity(),\r
- SI.METERS_PER_SECOND));\r
- case 3:\r
- return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
- .getSimulatedData().getDeploymentVelocity(),\r
- SI.METERS_PER_SECOND));\r
- case 4:\r
- return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
- .getSimulatedData().getGroundHitVelocity(),\r
- SI.METERS_PER_SECOND));\r
- case 5:\r
- return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
- .getSimulatedData().getTimeToApogee(), SI.SECOND));\r
- case 6:\r
- return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
- .getSimulatedData().getFlightTime(), SI.SECOND));\r
- }\r
- return "??";\r
- }\r
-\r
- }\r
-\r
- private TM tm = new TM();\r
- private JTable table = new JTable(tm);\r
- private OpenRocketDocument doc;\r
-\r
- public RocketSimTable() {\r
- setViewportView(table);\r
- RocketScience.addUnitPreferenceListener(this);\r
- table.addMouseListener(new MouseAdapter() {\r
- public void mouseClicked(MouseEvent e) {\r
- if (e.getClickCount() == 2) {\r
- Entry entry = entries.get(table.getSelectedRow());\r
- SimulationPlotDialog.showPlot(SwingUtilities\r
- .getWindowAncestor(RocketSimTable.this), entry.s,\r
- PlotConfiguration.DEFAULT_CONFIGURATIONS[0]\r
- .resetUnits());\r
- }\r
- }\r
- });\r
- preferredUnitsChanged();\r
- }\r
-\r
- public void openRocket(File f) throws RocketLoadException {\r
- this.doc = new OpenRocketLoader().load(f);\r
- }\r
-\r
- private Entry toEntry(Burn b) {\r
- final Entry e = new Entry(b.getMotor(), doc.getSimulation(0).copy(), b);\r
- OneMotorDatabase.setBurn(b);\r
-\r
- e.s.getConfiguration().getMotorConfigurationID();\r
- Iterator<RocketComponent> iterator = doc.getRocket().iterator();\r
- while (iterator.hasNext()) {\r
- RocketComponent c = iterator.next();\r
- if (c instanceof MotorMount) {\r
- ((MotorMount) c).setMotorDelay(e.s.getConfiguration()\r
- .getMotorConfigurationID(), b.getMotor()\r
- .getEjectionDelay().doubleValue(SI.SECOND));\r
- }\r
- }\r
-\r
- tm.fireTableDataChanged();\r
- new Thread() {\r
- @Override\r
- public void run() {\r
- try {\r
- e.s.simulate();\r
- e.ready = true;\r
- tm.fireTableDataChanged();\r
- } catch (SimulationException e1) {\r
- e1.printStackTrace();\r
- }\r
-\r
- }\r
- }.start();\r
-\r
- return e;\r
- }\r
-\r
- @Override\r
- public void replace(Burn oldBurn, Burn newBurn) {\r
- if (doc == null) {\r
- return; // TODO, deal with changing rockets\r
- }\r
-\r
- if (oldBurn != null) {\r
- for (int i = 0; i < entries.size(); i++) {\r
- if (entries.get(i).b == oldBurn) {\r
- if (newBurn != null) {\r
- entries.set(i, toEntry(newBurn));\r
- } else {\r
- entries.remove(i);\r
- }\r
- break;\r
- }\r
- }\r
- } else {\r
- entries.add(toEntry(newBurn));\r
- }\r
- tm.fireTableDataChanged();\r
- }\r
-\r
- @Override\r
- public void preferredUnitsChanged() {\r
- tm.fireTableDataChanged();\r
- if (UnitPreference.getUnitPreference() == UnitPreference.NONSI) {\r
- System.err.println("NONSI");\r
- UnitGroup.setDefaultImperialUnits();\r
- } else {\r
- System.err.println("SI");\r
- UnitGroup.setDefaultMetricUnits();\r
- }\r
- }\r
-}\r
+++ /dev/null
-package com.billkuker.rocketry.motorsim.visual.openRocket;\r
-\r
-import java.io.File;\r
-\r
-import javax.swing.JFrame;\r
-\r
-import com.billkuker.rocketry.motorsim.Burn;\r
-import com.billkuker.rocketry.motorsim.RocketScience.UnitPreference;\r
-import com.billkuker.rocketry.motorsim.motors.kuker.PVC9;\r
-\r
-public class Test {\r
-\r
- /**\r
- * @param args\r
- */\r
- public static void main(String[] args) throws Exception {\r
- \r
- UnitPreference.setUnitPreference(UnitPreference.NONSI);\r
-\r
- JFrame frame = new JFrame();\r
- frame.setSize(1024, 768);\r
-\r
- RocketSimTable st = new RocketSimTable();\r
- st.openRocket(new File("simple.ork"));\r
-\r
- com.billkuker.rocketry.motorsim.Motor m = new PVC9();\r
- Burn b = new Burn(m);\r
- b.burn();\r
- st.replace(null, b);\r
-\r
- frame.setContentPane(st);\r
- frame.setVisible(true);\r
-\r
- }\r
-\r
-}\r