updates for 0.9.3
[debian/openrocket] / src / net / sf / openrocket / motor / ThrustCurveMotor.java
diff --git a/src/net/sf/openrocket/motor/ThrustCurveMotor.java b/src/net/sf/openrocket/motor/ThrustCurveMotor.java
new file mode 100644 (file)
index 0000000..e495def
--- /dev/null
@@ -0,0 +1,161 @@
+package net.sf.openrocket.motor;
+
+import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.MathUtil;
+
+/**
+ * A class of motors specified by a fixed thrust curve.  This is the most
+ * accurate for solid rocket motors.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class ThrustCurveMotor extends Motor {
+       
+       public static final double MAX_THRUST = 10e6;
+
+       private final double[] time;
+       private final double[] thrust;
+       private final Coordinate[] cg;
+       
+       private final double totalTime;
+       private final double maxThrust;
+       
+
+       /**
+        * Sole constructor.  Sets all the properties of the motor.
+        * 
+        * @param manufacturer  the manufacturer of the motor.
+        * @param designation   the designation of the motor.
+        * @param description   extra description of the motor.
+        * @param diameter      diameter of the motor.
+        * @param length        length of the motor.
+        * @param time          the time points for the thrust curve.
+        * @param thrust        thrust at the time points.
+        * @param cg            cg at the time points.
+        */
+       public ThrustCurveMotor(Manufacturer manufacturer, String designation, String description, 
+                       Motor.Type type, double[] delays, double diameter, double length,
+                       double[] time, double[] thrust, Coordinate[] cg) {
+               super(manufacturer, designation, description, type, delays, diameter, length);
+
+               double max = -1;
+
+               // Check argument validity
+               if ((time.length != thrust.length) || (time.length != cg.length)) {
+                       throw new IllegalArgumentException("Array lengths do not match, " +
+                                       "time:" + time.length + " thrust:" + thrust.length +
+                                       " cg:" + cg.length);
+               }
+               if (time.length < 2) {
+                       throw new IllegalArgumentException("Too short thrust-curve, length=" + 
+                                       time.length);
+               }
+               for (int i=0; i < time.length-1; i++) {
+                       if (time[i+1] < time[i]) {
+                               throw new IllegalArgumentException("Time goes backwards, " +
+                                               "time[" + i + "]=" + time[i] + " " +
+                                               "time[" + (i+1) + "]=" + time[i+1]);
+                       }
+               }
+               if (!MathUtil.equals(time[0], 0)) {
+                       throw new IllegalArgumentException("Curve starts at time " + time[0]);
+               }
+               if (!MathUtil.equals(thrust[0], 0)) {
+                       throw new IllegalArgumentException("Curve starts at thrust " + thrust[0]);
+               }
+               if (!MathUtil.equals(thrust[thrust.length-1], 0)) {
+                       throw new IllegalArgumentException("Curve ends at thrust " + 
+                                       thrust[thrust.length-1]);
+               }
+               for (double t: thrust) {
+                       if (t < 0) {
+                               throw new IllegalArgumentException("Negative thrust.");
+                       }
+                       if (t > MAX_THRUST || Double.isNaN(t)) {
+                               throw new IllegalArgumentException("Invalid thrust " + t);
+                       }
+                       if (t > max)
+                               max = t;
+               }
+               for (Coordinate c: cg) {
+                       if (c.isNaN()) {
+                               throw new IllegalArgumentException("Invalid CG " + c);
+                       }
+                       if (c.x < 0 || c.x > length) {
+                               throw new IllegalArgumentException("Invalid CG position " + c.x);
+                       }
+                       if (c.weight < 0) {
+                               throw new IllegalArgumentException("Negative mass " + c.weight);
+                       }
+               }
+
+               this.maxThrust = max;
+               this.time = time.clone();
+               this.thrust = thrust.clone();
+               this.cg = cg.clone();
+               this.totalTime = time[time.length-1];
+       }
+
+
+       @Override
+       public double getTotalTime() {
+               return totalTime;
+       }
+
+       @Override
+       public double getMaxThrust() {
+               return maxThrust;
+       }
+       
+       @Override
+       public double getThrust(double t) {
+               if ((t < 0) || (t > totalTime))
+                       return 0;
+
+               for (int i=0; i < time.length-1; i++) {
+                       if ((t >= time[i]) && (t <= time[i+1])) {
+                               double delta = time[i+1] - time[i];
+                               if (delta < 0.0001) {
+                                       return thrust[i];
+                               }
+                               t = t - time[i];
+                               return thrust[i] * (1 - t/delta) + thrust[i+1] * (t/delta);
+                       }
+               }
+               assert false : "Should not be reached.";
+               return 0;
+       }
+
+
+       @Override
+       public Coordinate getCG(double t) {
+               if (t <= 0)
+                       return cg[0];
+               if (t >= totalTime)
+                       return cg[cg.length-1];
+               
+               for (int i=0; i < time.length-1; i++) {
+                       if ((t >= time[i]) && (t <= time[i+1])) {
+                               double delta = time[i+1] - time[i];
+                               t = t - time[i];
+                               return cg[i].multiply(1 - t/delta).add(cg[i+1].multiply(t/delta));
+                       }
+               }
+               assert false : "Should not be reached.";
+               return cg[cg.length-1];
+       }
+
+       
+       public double[] getTimePoints() {
+               return time.clone();
+       }
+       
+       public double[] getThrustPoints() {
+               return thrust.clone();
+       }
+       
+       public Coordinate[] getCGPoints() {
+               return cg.clone();
+       }
+       
+}