--- /dev/null
+/*
+ * 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;
+ }
+}