Added ability for doublemodel to evaluate math expressions using exp4j, fixed typeove...
[debian/openrocket] / core / src / net / sf / openrocket / util / exp4j / PostfixExpression.java
1 /*
2    Copyright 2011 frank asseg
3
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7
8        http://www.apache.org/licenses/LICENSE-2.0
9
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15
16  */
17 package net.sf.openrocket.util.exp4j;
18
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.Stack;
23
24 /**
25  * Class for calculating values from a RPN postfix expression.<br/>
26  * The default way to create a new instance of {@link PostfixExpression} is by
27  * using the static factory method fromInfix()
28  * 
29  * @author fas@congrace.de
30  */
31 public final class PostfixExpression extends AbstractExpression implements Calculable {
32         /**
33          * Factory method for creating {@link PostfixExpression}s from human
34          * readable infix expressions
35          * 
36          * @param expression
37          *            the infix expression to be used
38          * @return an equivalent {@link PostfixExpression}
39          * @throws UnparsableExpressionException
40          *             if the expression was invalid
41          * @throws UnknownFunctionException
42          *             if an unknown function has been used
43          * @deprecated please use {@link ExpressionBuilder} API
44          */
45     @Deprecated
46         public static PostfixExpression fromInfix(String expression) throws UnparsableExpressionException, UnknownFunctionException {
47                 return fromInfix(expression, null);
48         }
49
50         /**
51          * Factory method for creating {@link PostfixExpression}s from human
52          * readable infix expressions
53          * 
54          * @param expression
55          *            the infix expression to be used
56          * @param customFunctions
57          *            the CustomFunction implementations used
58          * @return an equivalent {@link PostfixExpression}
59          * @throws UnparsableExpressionException
60          *             if the expression was invalid
61          * @throws UnknownFunctionException
62          *             if an unknown function has been used
63          * @deprecated please use {@link ExpressionBuilder}
64          */
65     @Deprecated
66         public static PostfixExpression fromInfix(String expression, Set<CustomFunction> customFunctions) throws UnparsableExpressionException,
67                         UnknownFunctionException {
68                 String[] variables = null;
69                 int posStart, posEnd;
70                 if ((posStart = expression.indexOf('=')) > 0) {
71                         String functionDef = expression.substring(0, posStart);
72                         expression = expression.substring(posStart + 1);
73                         if ((posStart = functionDef.indexOf('(')) > 0 && (posEnd = functionDef.indexOf(')')) > 0) {
74                                 variables = functionDef.substring(posStart + 1, posEnd).split(",");
75                         }
76                 }
77                 return new PostfixExpression(InfixTranslator.toPostfixExpression(expression, variables, customFunctions), variables, customFunctions);
78         }
79
80         private final Map<String, Double> variableValues = new HashMap<String, Double>();
81
82         /**
83          * Construct a new simple {@link PostfixExpression}
84          * 
85          * @param expression
86          *            the postfix expression to be calculated
87          * @param variableNames
88          *            the variable names in the expression
89          * @param customFunctions
90          *            the CustomFunction implementations used
91          * @throws UnparsableExpressionException
92          *             when expression is invalid
93          * @throws UnknownFunctionException
94          *             when an unknown function has been used
95          */
96         private PostfixExpression(String expression, String[] variableNames, Set<CustomFunction> customFunctions) throws UnparsableExpressionException,
97                         UnknownFunctionException {
98                 super(expression, new Tokenizer(variableNames, customFunctions).tokenize(expression), variableNames);
99         }
100
101         /**
102          * delegate the calculation of a simple expression without variables
103          * 
104          * @return the result
105          */
106         public double calculate() {
107                 return calculate(null);
108         }
109
110         /**
111          * calculate the result of the expression and substitute the variables by
112          * their values beforehand
113          * 
114          * @param values
115          *            the variable values to be substituted
116          * @return the result of the calculation
117          * @throws IllegalArgumentException
118          *             if the variables are invalid
119          */
120         public double calculate(double... values) throws IllegalArgumentException {
121                 if (getVariableNames() == null && values != null) {
122                         throw new IllegalArgumentException("there are no variables to set values");
123                 } else if (getVariableNames() != null && values == null && variableValues.isEmpty()) {
124                         throw new IllegalAccessError("variable values have to be set");
125                 } else if (values != null && values.length != getVariableNames().length) {
126                         throw new IllegalArgumentException("The are an unequal number of variables and arguments");
127                 }
128                 int i = 0;
129                 if (getVariableNames() != null && values != null) {
130                         for (double val : values) {
131                                 variableValues.put(getVariableNames()[i++], val);
132                         }
133                 }
134                 final Stack<Double> stack = new Stack<Double>();
135                 for (final Token t : getTokens()) {
136                         ((CalculationToken) t).mutateStackForCalculation(stack, variableValues);
137                 }
138                 return stack.pop();
139         }
140
141         public void setVariable(String name, double value) {
142                 variableValues.put(name, value);
143         }
144 }