import java.awt.*; public class Plot3d extends java.applet.Applet { //vars passed or calculated from HTML double XMin = -Math.PI; double XMax = Math.PI; int XCut = 30; double XScale; double YMin = -Math.PI; double YMax = Math.PI; int YCut = 30; double YScale; double ZMin = -Math.PI; double ZMax = Math.PI; double Angle = Math.PI / 6; double Tilt = 5 * Math.PI / 4; double Zoom = 2; double CosA; double CosT; double SinA; double SinT; double SinAT; double CosASinT; String Function = ".5*cos(x *x + y * y)"; //misc global vars int TRUE = -1; int FALSE = 0; int Trace = 0; //eval error flag int BadEval = 0; //eval ErrorCodes int ParenthesisError = 1; int UndefinedFunction = 2; TextField Equation; Button Graph; public void init() { String s; s = getParameter("XMin"); if(s != null) XMin = Double.valueOf(s).doubleValue(); s = getParameter("XMax"); if(s != null) XMax = Double.valueOf(s).doubleValue(); s = getParameter("XCut"); if(s != null) XCut = Integer.parseInt(s); s = getParameter("YMin"); if(s != null) YMin = Double.valueOf(s).doubleValue(); s = getParameter("YMax"); if(s != null) YMax = Double.valueOf(s).doubleValue(); s = getParameter("YCut"); if(s != null) YCut = Integer.parseInt(s); s = getParameter("ZMin"); if(s != null) ZMin = Double.valueOf(s).doubleValue(); s = getParameter("ZMax"); if(s != null) ZMax = Double.valueOf(s).doubleValue(); s = getParameter("Angle"); if(s != null) Angle = Double.valueOf(s).doubleValue(); s = getParameter("Tilt"); if(s != null) Tilt = Double.valueOf(s).doubleValue(); s = getParameter("Zoom"); if(s != null) Zoom = Double.valueOf(s).doubleValue(); s = getParameter("Function"); if(s != null) Function = s; // initialize trig constants CosA = Math.cos(Angle) / Zoom; CosT = Math.cos(Tilt) / Zoom; SinA = Math.sin(Angle) / Zoom; SinT = Math.sin(Tilt) / Zoom; SinAT = Math.sin(Angle) * SinT; CosASinT = Math.cos(Angle) * SinT; XScale = size().width / (XMax - XMin); YScale = size().height / (YMax - YMin); Equation = new TextField(Function); add(Equation); Graph = new Button("Plot"); add(Graph); setBackground(new Color(0, 0, 51)); setForeground(Color.white); } double f(double x, double y) { int a; if(Math.abs(x) < .000000001) x = 0; if(Math.abs(y) < .000000001) y = 0; String fn = Function.toUpperCase(); a = fn.indexOf('X'); while(a != -1) { fn = fn.substring(0, a) + "(" + Double.toString(x) + ")" + fn.substring(a + 1, fn.length()); a = fn.indexOf('X'); } a = fn.indexOf('Y'); while(a != -1) { fn = fn.substring(0, a) + "(" + Double.toString(y) + ")" + fn.substring(a + 1, fn.length()); a = fn.indexOf('Y'); } double ret = eval(fn); if(BadEval != 0) { System.out.print("BadEval = "); System.out.println(BadEval); } if(Math.abs(ret - Math.cos(x*x+y*y)) > .1) { Trace=TRUE; ret = eval(fn); Trace=FALSE; } return ret; } String Clean(String expression) { String e = expression; e = e.toUpperCase(); e = e.trim(); int SpaceIndex = e.indexOf(' '); while(SpaceIndex != -1) { e = e.substring(0, SpaceIndex) + e.substring(SpaceIndex + 1, e.length()); SpaceIndex = e.indexOf(' '); } return e; } String ParseParenthesis(String expression) { String e = expression; int LastFound = 0; double NumberValue = 0; int OpenParenthesis = e.indexOf('('); int CloseParenthesis = 0; while(OpenParenthesis != -1) { LastFound = OpenParenthesis; while (OpenParenthesis == LastFound) { CloseParenthesis = e.indexOf(')', OpenParenthesis); if(CloseParenthesis == -1) { BadEval = ParenthesisError; return expression; } LastFound = e.indexOf('(', OpenParenthesis + 1); if((LastFound != -1) && (LastFound < CloseParenthesis)) { OpenParenthesis = LastFound; } } NumberValue = eval(e.substring(OpenParenthesis + 1, CloseParenthesis)); if(BadEval != 0) return expression; if(NumberValue < 0) { e = e.substring(0, OpenParenthesis) + '~' + Double.toString(-NumberValue) + e.substring(CloseParenthesis + 1, e.length()); } else { e = e.substring(0, OpenParenthesis) + Double.toString(NumberValue) + e.substring(CloseParenthesis + 1, e.length()); } OpenParenthesis = e.indexOf('('); } if(e.indexOf(')') != -1) { BadEval = ParenthesisError; return expression; } else { return e.toUpperCase(); } } int NumberStart(int NumEnd, String expression) { String e = expression; int NEnd = NumEnd; int NStart; for(NStart = NEnd; NStart > 0; NStart--) { if((e.substring(NStart, NStart + 1).compareTo("0") < 0) || (e.substring(NStart, NStart + 1).compareTo("9") > 0)) { if(e.substring(NStart, NStart + 1).compareTo(".") != 0) { if(e.substring(NStart, NStart + 1).compareTo("E") != 0 ) { if((e.substring(NStart, NStart + 1).compareTo("-") == 0) || (e.substring(NStart, NStart + 1).compareTo("+") == 0)) { if (e.substring(NStart - 1, NStart).compareTo("E") != 0) { return NStart + 1; } } else if(e.substring(NStart, NStart + 1).compareTo("~") != 0) { return NStart + 1; } } } } } return NStart; } int NumberEnd(int NumStart, String e) { int NStart = NumStart; int NEnd; if((e.substring(NStart, NStart + 1).compareTo("-") == 0) || (e.substring(NStart, NStart + 1).compareTo("+") == 0) || (e.substring(NStart, NStart + 1).compareTo("~") == 0)) { NStart++; } for(NEnd = NStart; NEnd < e.length(); NEnd++) { if((e.substring(NEnd, NEnd + 1).compareTo("0") < 0) || (e.substring(NEnd, NEnd + 1).compareTo("9") > 0)) { if(e.substring(NEnd, NEnd + 1).compareTo(".") != 0) { if(e.substring(NEnd, NEnd + 1).compareTo("E") != 0 ) { if((e.substring(NEnd, NEnd + 1).compareTo("-") == 0) || (e.substring(NEnd, NEnd + 1).compareTo("+") == 0)) { if(e.substring(NEnd - 1, NEnd).compareTo("E") != 0) { break; } } else { break; } } } } } return NEnd; } int sgn(double x) { if(x < 0) { return -1; } else if (x > 0) { return 1; } else { return 0; } } String ParseFunctions(String expression) { String e = expression; int Found = TRUE; int FunctionStart = 0; int FunctionEnd = 0; String FunctionName = ""; int NumEnd = 0; double Number = 0; while(Found == TRUE) { Found = FALSE; // scan for function name FunctionName = ""; for(FunctionStart = 0; FunctionStart < e.length(); FunctionStart++) { if((e.substring(FunctionStart, FunctionStart+1).compareTo("A") >= 0) && (e.substring(FunctionStart, FunctionStart + 1).compareTo("Z") <= 0)) { for(FunctionEnd = FunctionStart + 1; FunctionEnd < e.length(); FunctionEnd++) { if((e.substring(FunctionEnd, FunctionEnd + 1).compareTo("A") < 0) || (e.substring(FunctionEnd,FunctionEnd + 1).compareTo("Z") > 0)) { FunctionName = e.substring(FunctionStart, FunctionEnd); Found = TRUE; break; } } if(FunctionName.compareTo("") == 0) { FunctionName = e.substring(FunctionStart,FunctionStart+1); } if(FunctionName.compareTo("E") == 0) { Found = FALSE; } else break; } } if(Found == TRUE) { NumEnd = NumberEnd(FunctionEnd, e); Number = eval(e.substring(FunctionEnd, NumEnd)); } if(Found == TRUE) { //evaluate function if(FunctionName.compareTo("ABS") == 0) Number = Math.abs(Number); else if(FunctionName.compareTo("ACOS") == 0) Number = Math.acos(Number); else if(FunctionName.compareTo("ACOSH") == 0) Number = Math.PI / 2 - Math.atan(Number / Math.sqrt(1 - Number * Number)); else if(FunctionName.compareTo("ACOT") == 0) Number = Math.atan(Number) + Math.PI / 2; else if(FunctionName.compareTo("ACOTH") == 0) Number = Math.log((Number + 1) / (Number - 1)) / 2; else if(FunctionName.compareTo("ACSC") == 0) Number = Math.atan(Number / Math.sqrt(Number * Number - 1)) + (sgn(Number) - 1) * Math.PI / 2; else if(FunctionName.compareTo("ACSCH") == 0) Number = Math.log((sgn(Number) * Math.sqrt(1 + Number * Number) + 1) / Number); else if(FunctionName.compareTo("ASIN") == 0) Number = Math.atan(Number / Math.sqrt(1 - Number * Number)); else if(FunctionName.compareTo("ASINH") == 0) Number = Math.log(Number + Math.sqrt(Number * Number + 1)); else if(FunctionName.compareTo("ASEC") == 0) Number = Math.atan(Number / Math.sqrt(Number * Number + 1)) + (sgn(Number) - 1) * Math.PI / 2; else if(FunctionName.compareTo("ASECH") == 0) Number = Math.log((Math.sqrt(1 - Number * Number) + 1) / Number); else if(FunctionName.compareTo("ATAN") == 0) Number = Math.atan(Number); else if (FunctionName.compareTo("ATANH") == 0) Number = Math.log((1 + Number) / (1 - Number)) / 2; else if(FunctionName.compareTo("COS") == 0) Number = Math.cos(Number); else if(FunctionName.compareTo("COSH") == 0) Number = (Math.exp(Number) + Math.exp(-Number)) / 2; else if(FunctionName.compareTo("COT") == 0) Number = 1 / Math.tan(Number); else if(FunctionName.compareTo("COTH") == 0) Number = (Math.exp(Number) + Math.exp(-Number)) / (Math.exp(Number) - Math.exp(-Number)); else if(FunctionName.compareTo("CSC") == 0) Number = 1 / Math.sin(Number); else if(FunctionName.compareTo("CSCH") == 0) Number = 2 / (Math.exp(Number) - Math.exp(-Number)); else if(FunctionName.compareTo("EXP") == 0) Number = Math.exp(Number); else if(FunctionName.compareTo("LOG") == 0) Number = Math.log(Number); else if(FunctionName.compareTo("RAND") == 0) Number = Math.random() * Number; else if(FunctionName.compareTo("ROUND") == 0) Number = Math.round(Number); else if(FunctionName.compareTo("SEC") == 0) Number = 1 / Math.cos(Number); else if(FunctionName.compareTo("SECH") == 0) Number = 2 / (Math.exp(Number) + Math.exp(-Number)); else if(FunctionName.compareTo("SIGN") == 0) Number = sgn(Number); else if(FunctionName.compareTo("SIN") == 0) Number = Math.sin(Number); else if(FunctionName.compareTo("SINH") == 0) Number = (Math.exp(Number) - Math.exp(-Number)) / 2; else if(FunctionName.compareTo("SQRT") == 0) Number = Math.sqrt(Number); else if(FunctionName.compareTo("TAN") == 0) Number = Math.tan(Number); else if(FunctionName.compareTo("TANH") == 0) Number = (Math.exp(Number) - Math.exp(-Number)) / (Math.exp(Number) + Math.exp(-Number)); else { BadEval = UndefinedFunction; return expression; } if(Number < 0) { e = e.substring(0, FunctionStart) + "~" + Double.toString(-Number) + e.substring(NumEnd, e.length()); } else { e = e.substring(0, FunctionStart) + Double.toString(Number) + e.substring(NumEnd, e.length()); } } } return e.toUpperCase(); } String ParseExponent(String expression) { String e = expression; int ExponentIndex = 0; int NumStart = 0; int NumEnd = 0; double Number = 0; while(e.indexOf("^") != -1) { ExponentIndex = e.indexOf("^"); NumStart = NumberStart(ExponentIndex - 1, e); NumEnd = NumberEnd(ExponentIndex + 1, e); Number = Math.pow(eval(e.substring(NumStart, ExponentIndex)), eval(e.substring(ExponentIndex + 1, NumEnd))); if(Number < 0) { e = e.substring(0,NumStart) + "~" + Double.toString(-Number) + e.substring(NumEnd, e.length()); } else { e = e.substring(0,NumStart) + Double.toString(Number) + e.substring(NumEnd, e.length()); } } return e.toUpperCase(); } String ParseMultiplication(String expression) { String e = expression; int MultiplicationIndex = 0; int NumStart = 0; int NumEnd = 0; double Number = 0; while(e.indexOf("*") != -1) { MultiplicationIndex = e.indexOf("*"); NumStart = NumberStart(MultiplicationIndex - 1, e); NumEnd = NumberEnd(MultiplicationIndex + 1, e); Number = eval(e.substring(NumStart, MultiplicationIndex)) * eval(e.substring(MultiplicationIndex + 1, NumEnd)); if(Number < 0) { e = e.substring(0,NumStart) + "~" + Double.toString(-Number) + e.substring(NumEnd, e.length()); } else { e = e.substring(0,NumStart) + Double.toString(Number) + e.substring(NumEnd, e.length()); } } return e.toUpperCase(); } String ParseDivision(String expression) { String e = expression; int DivisionIndex = 0; int NumStart = 0; int NumEnd = 0; double Number = 0; while(e.indexOf("/") != -1) { DivisionIndex = e.indexOf("/"); NumStart = NumberStart(DivisionIndex - 1, e); NumEnd = NumberEnd(DivisionIndex + 1, e); Number = eval(e.substring(NumStart, DivisionIndex)) / eval(e.substring(DivisionIndex + 1, NumEnd)); if (Number < 0) { e = e.substring(0,NumStart) + "~" + Double.toString(-Number) + e.substring(NumEnd, e.length()); } else { e = e.substring(0,NumStart) + Double.toString(Number) + e.substring(NumEnd, e.length()); } } return e.toUpperCase(); } String ParseAddition(String expression) { String e = expression; int AdditionIndex = 0; int NumStart = 0; int NumEnd = 0; double Number = 0; while(e.indexOf("+") != -1) { AdditionIndex = e.indexOf("+"); NumStart = NumberStart(AdditionIndex - 1, e); NumEnd = NumberEnd(AdditionIndex + 1, e); Number = eval(e.substring(NumStart, AdditionIndex)) + eval(e.substring(AdditionIndex + 1, NumEnd)); if(Number < 0) { e = e.substring(0,NumStart) + "~" + Double.toString(-Number) + e.substring(NumEnd, e.length()); } else { e = e.substring(0,NumStart) + Double.toString(Number) + e.substring(NumEnd, e.length()); } } return e.toUpperCase(); } String ParseSubtraction(String expression) { String e = expression; int SubtractionIndex = 0; int NumStart = 0; int NumEnd = 0; double Number = 0; while(e.indexOf("-") != -1) { SubtractionIndex = e.indexOf("-"); NumStart = NumberStart(SubtractionIndex - 1, e); NumEnd = NumberEnd(SubtractionIndex + 1, e); Number = eval(e.substring(NumStart, SubtractionIndex)) - eval(e.substring(SubtractionIndex + 1, NumEnd)); if(Number < 0) { e = e.substring(0,NumStart) + "~" + Double.toString(-Number) + e.substring(NumEnd, e.length()); } else { e = e.substring(0,NumStart) + Double.toString(Number) + e.substring(NumEnd, e.length()); } } return e.toUpperCase(); } double eval(String expression) { BadEval = 0; String e = expression; int flag=0; e = Clean(e); // scan for simple numeric expression int ScanIndex = 0; if((e.substring(0, 1).compareTo("-") == 0) || (e.substring(0, 1).compareTo("+") == 0) || (e.substring(0, 1).compareTo("~") == 0)) { ScanIndex++; } for(ScanIndex = ScanIndex; ScanIndex < e.length(); ScanIndex++) { if((e.substring(ScanIndex, ScanIndex + 1).compareTo("0") < 0) || (e.substring(ScanIndex, ScanIndex + 1).compareTo("9") > 0)) { if(e.substring(ScanIndex, ScanIndex + 1).compareTo(".") != 0) { if((e.substring(ScanIndex, ScanIndex + 1).compareTo("-") == 0) || (e.substring(ScanIndex, ScanIndex + 1).compareTo("+") == 0)) { if(e.substring(ScanIndex - 1, ScanIndex).compareTo("E") != 0) { break; } } else if(e.substring(ScanIndex, ScanIndex + 1).compareTo("E") != 0) { break; } else flag=1; } } } if(ScanIndex == e.length()) { if(e.substring(0, 1).compareTo("~") == 0) { e = "-" + e.substring(1, e.length()); } return Double.valueOf(e).doubleValue(); } e = ParseParenthesis(e); if (BadEval != 0) return 0; e = ParseFunctions(e); if (BadEval != 0) return 0; e = ParseExponent(e); if (BadEval != 0) return 0; e = ParseMultiplication(e); if (BadEval != 0) return 0; e = ParseDivision(e); if (BadEval != 0) return 0; e = ParseAddition(e); if (BadEval != 0) return 0; e = ParseSubtraction(e); if (BadEval != 0) return 0; return eval(e); } int GetX(double x, double y, double z) { return (int) ((x * CosA - y * SinA - XMin) * XScale); } int GetY(double x, double y, double z) { return (int) ((x * SinAT + y * CosASinT + z * CosT - YMin) * YScale); } public void paint(Graphics g) { // draw border g.setColor(new Color(0, 0, 51)); g.fillRect(0, 0, size().width, size().height); // display function g.setColor(Color.white); g.drawString(Function, 5, size().height - 10); // draw axis g.setColor(Color.yellow); g.drawLine(GetX(0, 0, ZMin),GetY(0, 0, ZMin),GetX(0, 0, ZMax),GetY(0, 0, ZMax)); g.drawLine(GetX(0, YMin, 0),GetY(0, YMin, 0),GetX(0, YMax, 0),GetY(0, YMax, 0)); g.drawLine(GetX(XMin, 0, 0),GetY(XMin, 0, 0),GetX(XMax, 0, 0),GetY(XMax, 0, 0)); // Plot Function double IncX = (XMax - XMin) / XCut; double IncY = (YMax - YMin) / YCut; double x; double y; double z; double nz; g.setColor(Color.blue); for(x = XMin; x <= XMax; x += IncX) { nz = f(x, YMin); for(y = YMin + IncY; y <= YMax; y += IncY) { z = nz; nz = f(x, y); g.drawLine(GetX(x, y - IncY, z), GetY(x, y - IncY, z), GetX(x, y, nz), GetY(x, y, nz)); } } for (y = YMin; y <= YMax; y += IncY) { nz = f(XMin, y); for(x = XMin + IncX; x <= XMax; x += IncX) { z = nz; nz = f(x, y); g.drawLine(GetX(x - IncX, y, z), GetY(x - IncX, y, z), GetX(x, y, nz), GetY(x, y, nz)); } } } public boolean action(Event evt, Object o) { if(evt.target instanceof Button) { Function = Equation.getText(); Graphics g = getGraphics(); paint(g); } return true; } }