Merge commit '42b2e5ca519766e37ce6941ba4faecc9691cc403' into upstream
[debian/openrocket] / core / src / net / sf / openrocket / simulation / customexpression / RangeExpression.java
diff --git a/core/src/net/sf/openrocket/simulation/customexpression/RangeExpression.java b/core/src/net/sf/openrocket/simulation/customexpression/RangeExpression.java
new file mode 100644 (file)
index 0000000..1667b61
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * A range expression contains two indexExpressions for the beginning and end time index of a range
+ */
+
+package net.sf.openrocket.simulation.customexpression;
+
+import java.util.List;
+
+import de.congrace.exp4j.Calculable;
+import de.congrace.exp4j.ExpressionBuilder;
+import de.congrace.exp4j.Variable;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.ArrayUtils;
+import net.sf.openrocket.util.LinearInterpolator;
+import net.sf.openrocket.util.MathUtil;
+
+public class RangeExpression extends CustomExpression {
+       private static final LogHelper log = Application.getLogger();
+
+       private ExpressionBuilder startBuilder, endBuilder;
+       
+       public RangeExpression(OpenRocketDocument doc, String startTime, String endTime, String variableType) {
+               super(doc);
+               
+               if ("".equals(startTime.trim())){
+                       startTime = "0";
+               }
+               if ("".equals(endTime.trim())){
+                       endTime = "t";
+               }
+               
+               this.setName("");
+               this.setSymbol(variableType);
+               this.setExpressions(startTime, endTime);
+               this.expression = variableType+startTime+endTime; // this is used just for generating the hash
+               
+               log.info("New range expression, "+startTime + " to "+endTime);
+       }
+       
+       /*
+        * Sets the actual expression string for this expression
+        */
+       private void setExpressions(String start, String end){
+               
+               startBuilder = new ExpressionBuilder(start);
+               endBuilder = new ExpressionBuilder(end);
+               for (String n : getAllSymbols()){
+                       startBuilder.withVariable(new Variable(n));
+                       endBuilder.withVariable(new Variable(n));
+               }
+       }
+       
+       @Override
+       public Variable evaluate(SimulationStatus status){
+               
+               Calculable startCalc = buildExpression(startBuilder);
+               Calculable endCalc = buildExpression(endBuilder);
+               if (startCalc == null || endCalc == null){
+                       return new Variable("Unknown");
+               }
+               
+               // Set the variables in the start and end calculators
+               for (FlightDataType type : status.getFlightData().getTypes()){
+                       double value = status.getFlightData().getLast(type); 
+                       startCalc.setVariable( new Variable(type.getSymbol(), value ) );
+                       endCalc.setVariable( new Variable(type.getSymbol(), value ) );
+               }               
+               
+               // From the given datatype, get the time and function values and make an interpolator
+
+               //Note: must get in a way that flight data system will figure out units. Otherwise there will be a type conflict when we get the new data.
+               FlightDataType type = FlightDataType.getType(null, getSymbol(), null);
+               
+               List<Double> data = status.getFlightData().get(type);
+               List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
+               LinearInterpolator interp = new LinearInterpolator(time, data); 
+               
+               // Evaluate the expression to get the start and end of the range
+               double startTime, endTime;
+               try{
+                       startTime = startCalc.calculate().getDoubleValue();
+                       startTime = MathUtil.clamp(startTime, 0, Double.MAX_VALUE);
+                       
+                       endTime = endCalc.calculate().getDoubleValue();
+                       endTime = MathUtil.clamp(endTime, 0, time.get(time.size()-1));
+               }
+               catch (java.util.EmptyStackException e){
+                       log.user("Unable to calculate time index for range expression "+getSymbol()+" due to empty stack exception");
+                       return new Variable("Unknown");
+               }
+               
+               // generate an array representing the range
+               double step = status.getSimulationConditions().getSimulation().getOptions().getTimeStep();
+               double[] t = ArrayUtils.range(startTime, endTime,  step);
+               double[] y = new double[t.length]; 
+               int i = 0;
+               for (double tval : t){
+                       y[i] = interp.getValue( tval );
+                       i++;
+               }
+                               
+               Variable result;
+               if (y.length == 0){
+                       result = new Variable("Unknown");
+               }
+               else {
+                       result = new Variable(hash(), y, startTime, step);
+               }
+               
+               return result;
+       }
+}