/* * 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.Markers; import net.sf.openrocket.simulation.customexpression.CustomExpression; import net.sf.openrocket.simulation.FlightDataType; import net.sf.openrocket.simulation.SimulationStatus; import net.sf.openrocket.util.ArrayUtils; import net.sf.openrocket.util.LinearInterpolator; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.StringUtil; public class RangeExpression extends CustomExpression { private static final Logger log = LoggerFactory.getLogger(RangeExpression.class); private ExpressionBuilder startBuilder, endBuilder; public RangeExpression(OpenRocketDocument doc, String startTime, String endTime, String variableType) { super(doc); if (StringUtil.isEmpty(startTime)){ startTime = "0"; } if (StringUtil.isEmpty(endTime)){ 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.info(Markers.USER_MARKER, "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; } }