First revision of openRocket sim.
[sw/motorsim] / gui / com / billkuker / rocketry / motorsim / visual / openRocket / OneMotorDatabase.java
diff --git a/gui/com/billkuker/rocketry/motorsim/visual/openRocket/OneMotorDatabase.java b/gui/com/billkuker/rocketry/motorsim/visual/openRocket/OneMotorDatabase.java
new file mode 100644 (file)
index 0000000..09d1f72
--- /dev/null
@@ -0,0 +1,332 @@
+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