Big update to custom expression feature.
[debian/openrocket] / core / src / net / sf / openrocket / simulation / customexpression / RangeExpression.java
1 /*
2  * A range expression contains two indexExpressions for the beginning and end time index of a range
3  */
4
5 package net.sf.openrocket.simulation.customexpression;
6
7 import java.util.List;
8
9 import de.congrace.exp4j.Calculable;
10 import de.congrace.exp4j.ExpressionBuilder;
11 import de.congrace.exp4j.Variable;
12 import net.sf.openrocket.document.OpenRocketDocument;
13 import net.sf.openrocket.logging.LogHelper;
14 import net.sf.openrocket.simulation.customexpression.CustomExpression;
15 import net.sf.openrocket.simulation.FlightDataType;
16 import net.sf.openrocket.simulation.SimulationStatus;
17 import net.sf.openrocket.startup.Application;
18 import net.sf.openrocket.util.ArrayUtils;
19 import net.sf.openrocket.util.LinearInterpolator;
20 import net.sf.openrocket.util.MathUtil;
21
22 public class RangeExpression extends CustomExpression {
23         private static final LogHelper log = Application.getLogger();
24
25         private ExpressionBuilder startBuilder, endBuilder;
26         
27         public RangeExpression(OpenRocketDocument doc, String startTime, String endTime, String variableType) {
28                 super(doc);
29                 
30                 if (startTime.isEmpty()){
31                         startTime = "0";
32                 }
33                 if (endTime.isEmpty()){
34                         endTime = "t";
35                 }
36                 
37                 this.setName("");
38                 this.setSymbol(variableType);
39                 this.setExpressions(startTime, endTime);
40                 this.expression = variableType+startTime+endTime; // this is used just for generating the hash
41                 
42                 log.info("New range expression, "+startTime + " to "+endTime);
43                 
44         }
45         
46         /*
47          * Sets the actual expression string for this expression
48          */
49         private void setExpressions(String start, String end){
50                 
51                 startBuilder = new ExpressionBuilder(start);
52                 endBuilder = new ExpressionBuilder(end);
53                 for (String n : getAllSymbols()){
54                         startBuilder.withVariable(new Variable(n));
55                         endBuilder.withVariable(new Variable(n));
56                 }
57         }
58         
59         @Override
60         public Variable evaluate(SimulationStatus status){
61                 
62                 Calculable startCalc = buildExpression(startBuilder);
63                 Calculable endCalc = buildExpression(endBuilder);
64                 if (startCalc == null || endCalc == null){
65                         return new Variable("Unknown");
66                 }
67                 
68                 // Set the variables in the start and end calculators
69                 for (FlightDataType type : status.getFlightData().getTypes()){
70                         double value = status.getFlightData().getLast(type); 
71                         startCalc.setVariable( new Variable(type.getSymbol(), value ) );
72                         endCalc.setVariable( new Variable(type.getSymbol(), value ) );
73                 }               
74                 
75                 // From the given datatype, get the time and function values and make an interpolator
76                 FlightDataType type = getType();
77                 
78                 List<Double> data = status.getFlightData().get(type);
79                 List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
80                 LinearInterpolator interp = new LinearInterpolator(time, data); 
81                 
82                 // Evaluate the expression to get the start and end of the range
83                 double startTime, endTime;
84                 try{
85                         startTime = startCalc.calculate().getDoubleValue();
86                         startTime = MathUtil.clamp(startTime, 0, Double.MAX_VALUE);
87                         
88                         endTime = endCalc.calculate().getDoubleValue();
89                         endTime = MathUtil.clamp(endTime, 0, time.get(time.size()-1));
90                 }
91                 catch (java.util.EmptyStackException e){
92                         log.user("Unable to calculate time index for range expression "+getSymbol()+" due to empty stack exception");
93                         return new Variable("Unknown");
94                 }
95                 
96                 // generate an array representing the range
97                 double step = status.getSimulationConditions().getSimulation().getOptions().getTimeStep();
98                 double[] t = ArrayUtils.range(startTime, endTime,  step);
99                 double[] y = new double[t.length]; 
100                 int i = 0;
101                 for (double tval : t){
102                         y[i] = interp.getValue( tval );
103                         i++;
104                 }
105                                 
106                 Variable result;
107                 if (y.length == 0){
108                         result = new Variable("Unknown");
109                 }
110                 else {
111                         result = new Variable(hash(), y, startTime, step);
112                 }
113                 
114                 return result;
115         }
116 }