package freegraph; import java.util.*; import java.awt.Graphics; import java.awt.Color; /****** * ExpressionEvaluator takes an expression as a String and evaluates the * expression. Values of single character variables may be set. The * ExpressionEvaluator uses and ExpressionStack to convert the expression * to postfix for evaluation.

* ExpressionEvaluator implements GraphPlaneItem to draw the graph of * function on GraphPlane. * @see GraphPlane * @see ExpressionStack */ public class ExpressionEvaluator implements GraphPlaneItem { private ExpressionStack expressionStack = new ExpressionStack(); private VariableValues variables = new VariableValues(); private String expressionStr; private Color color = Color.red; /**** * constructs a new ExpressionEvaluator with an empty expression */ public ExpressionEvaluator() { } /**** * constructs a new ExpressionEvaluator with expression * @param expression the expression to evaluate */ public ExpressionEvaluator(String expression) throws ExpressionException { setExpression(expression); } /*** * sets the expression for the evaluator. The expression is in the form * of an infix expression with single character variables. The expression * is parsed and converted to postfix using ExpressionStack. */ public void setExpression(String expression) throws ExpressionException { expressionStr = expression; expressionStack.setInfixExpression(expression); } /**** * returns the expression as the String it was set with. */ public String getExpression() { return expressionStr; } /**** * returns the color of the expression. This color is used when the * expression is drawn as a GraphPlaneItem */ public Color getColor() { return color; } /**** * sets the color of the expression. This color is used when the * expression is drawn as a GraphPlaneItem */ public void setColor(Color newColor) { color = newColor; } /**** * returns the VariableValues object representing the variables for this * expression evaluator. These values will be used when the expression * is evaluated. Use the VariableValues object returned by this method to * set the values of variables for this ExpressionEvaluator * @return the variable values used by the ExpressionEvaluator */ public VariableValues getVariables() { return variables; } /**** * evaluates the expression using the current variable values and returns * the result * (ExpressionEvaluator does some down casting on the ExpressionItems when * evaluating expressions. Perhaps there is a design which would avoid * this; however, it works fine in this case.) * @return the value of the expression */ public double evaluate() { if (expressionStr.length() < 1) return 0; Stack evalStack = new Stack(); int i = 0; for (i = expressionStack.size() - 1; i>=0; i--) { ExpressionItem exprItem = (ExpressionItem)expressionStack.elementAt(i); if (exprItem instanceof ExpressionItem.Number) evalStack.push( new Double(((ExpressionItem.Number)exprItem).getNumber())); else if (exprItem instanceof ExpressionItem.Variable) evalStack.push( new Double(variables.getValue( ((ExpressionItem.Variable)exprItem).getVariable()))); else if (exprItem instanceof ExpressionItem.UnOperator) { double x = ((Double)evalStack.pop()).doubleValue(); evalStack.push( new Double( ((ExpressionItem.UnOperator)exprItem).doOperation(x))); } else if (exprItem instanceof ExpressionItem.BiOperator) { double x = ((Double)evalStack.pop()).doubleValue(); double y = ((Double)evalStack.pop()).doubleValue(); evalStack.push( new Double( ((ExpressionItem.BiOperator)exprItem).doOperation(x, y))); } } return ((Double)evalStack.pop()).doubleValue(); } /**** * called by GraphPlane to draw this GraphPlaneItem. Draws the * graph of the expression on the graph plane. * @param graphPlane the GraphPlane on which to draw the expression * @param g the Graphics object for graphPlane * @param variableChar the varible in the expression for the X axis * (typically "x") */ public void drawItem(GraphPlane graphPlane, Graphics g, char variableChar) { if (expressionStr == null || expressionStr.length() < 1) return; g.setColor(color); double incr = (graphPlane.getXMax() - graphPlane.getXMin()) / 800; if (incr < 0) incr = -incr; double x = graphPlane.getXMin(); double y = 0; double x1 = 0, y1 = 0; boolean moveTo = true; while (x < graphPlane.getXMax()) { variables.setValue(variableChar, x); try { y = evaluate(); if (moveTo) moveTo = false; else if (y == Double.NaN) moveTo = true; else moveTo = !graphPlane.drawLine(g, x1, y1, x, y); } catch (Exception e) { moveTo = true; System.out.println(e.getMessage()); //continue; let x move on. } x1 = x; y1 = y; x += incr; } } public String toString() { return super.toString() + ": " + expressionStr; } }