// IntApprox.java - Optimally approximates quadratic interval functions // with linear interval functions. // Created by Misha Koshelev. // Copyright (C) 1996 by Misha Koshelev import java.applet.Applet; import java.awt.*; import java.net.*; // Event IDs class EV_Closing extends Object { } class EV_NewInfo extends Object { private String info; EV_NewInfo(String sInfo) { info = sInfo; } public String toString() { return info; } } class EV_NewInfoDontShow extends Object { private String info; EV_NewInfoDontShow(String sInfo) { info = sInfo; } public String toString() { return info; } } class EV_CloseInfo extends Object { } // Other classes class IntApproxInfo { Color cUpr, cLwr, cUprApprox, cLwrApprox, cOther; } class MessageWindow extends Frame { TextArea taMsg; Button bOk; Panel spacer; // The container Component parent; public MessageWindow(Component cont, String sTitle, String sMsg, String sButton) { super(sTitle); parent = cont; taMsg = new TextArea(sMsg); taMsg.setEditable(false); bOk = new Button(sButton); spacer = new Panel(); add("North", taMsg); add("Center", spacer); add("South", bOk); pack(); show(); } public void setMessage(String sMsg) { taMsg.setText(sMsg); } public boolean handleEvent(Event event) { switch (event.id) { case Event.WINDOW_DESTROY: hide(); dispose(); parent.handleEvent(new Event(this, Event.ACTION_EVENT, new EV_Closing())); return true; } return super.handleEvent(event); } public boolean action(Event event, Object arg) { if (event.target == bOk) { hide(); dispose(); parent.handleEvent(new Event(this, Event.ACTION_EVENT, new EV_Closing())); } return true; } } class IntApproxCanvas extends Canvas { // Parent Component parent; // Global information IntApproxInfo info; // The error window MessageWindow errwnd; // The coefficients and bounding x values double lower_c[] = {1.0,0.0,0.0}, lowera_c[] = {0.0, 0.0}, upper_c[] = {1.0,0.0,0.0}, uppera_c[] = {0.0, 0.0}, fX[] = {-1.0, 1.0}; // The X step (how many units each pixel signifies) double fXStep; // The maximal and minimal Y values (the max of the upper approximator // and the min of the lower approximator) double fYMax, fYMin, fYStep; // The amount of empty space at the top and the left of the canvas // both as a double and in pixels double fXSpace, fYSpace; int iXSpace = 2, iYSpace = 2; // Which functions we should show boolean bShowQuad = false, bShowApprox = false; // Whether any of the coefficient data has changed boolean bChanged = true; // The largest and smallest differences between the quadratic // functions and the approximators double largeDiff, smallDiff, largeADiff, smallADiff; public IntApproxCanvas(Component cont) { super(); parent = cont; info = null; } public boolean action(Event e, Object o) { if (e.target == errwnd && e.arg instanceof EV_Closing) { errwnd = null; } return true; } // Makes a string containing information in this object public String toString() { StringBuffer s = new StringBuffer(); s.append("Lower Approximator: " + lowera_c[0] + "x + " + lowera_c[1] + "\n"); s.append("Upper Approximator: " + uppera_c[0] + "x + " + uppera_c[1] + "\n\n"); s.append("Differences y+(x)-y-(x): Largest = " + largeDiff + ", Smallest = " + smallDiff + "\n\n"); s.append("Differences z+(x)-z-(x): Largest = " + largeADiff + ", Smallest = " + smallADiff); return s.toString(); } public String toString(int x) { StringBuffer s = new StringBuffer(); double realX; realX = ((x-iXSpace)*fXStep)+fX[0]; if (Math.abs(realX) < 0.000000000001) realX = 0.0; s.append("Lower Approximator: " + lowera_c[0] + "x + " + lowera_c[1] + "\n"); s.append("Upper Approximator: " + uppera_c[0] + "x + " + uppera_c[1] + "\n\n"); s.append("Differences y+(x)-y-(x): Largest = " + largeDiff + ", Smallest = " + smallDiff + "\n\n"); s.append("Differences z+(x)-z-(x): Largest = " + largeADiff + ", Smallest = " + smallADiff + "\n\n"); s.append("x = " + realX + " y+(x) = " + evalUpr(realX) + ", y-(x) = " + evalLwr(realX) + " y+(x)-y-(x) = " + evalDiff(realX) + "\n"); s.append("x = " + realX + " z+(x) = " + evalUprApprox(realX) + ", z-(x) = " + evalLwrApprox(realX) + " z+(x)-z-(x) = " + evalDiffApprox(realX)); return s.toString(); } public boolean handleEvent(Event event) { switch (event.id) { case Event.MOUSE_DOWN: case Event.MOUSE_DRAG: parent.handleEvent(new Event(this, Event.ACTION_EVENT, new EV_NewInfo(toString(event.x)))); return true; } return super.handleEvent(event); } public void paint(Graphics g) { int i, prev_y, y; double fidx; // If we have no info yet, return if (info == null) return; // If any of the data has changed, calculate the approximators if (bChanged) calcApprox(); // Make sure to leave the appropriate space at the top and left // corners g.translate(iXSpace, iYSpace); // Draw the axes g.setColor(info.cOther); g.drawLine(0, (int)(fYMax/fYStep), (this.size()).width, (int)(fYMax/fYStep)); if (fX[0] <= 0.0) { g.drawLine((int)(-fX[0]/fXStep), 0, (int)(-fX[0]/fXStep), (this.size()).height); } // If we should show the quadratic functions if (bShowQuad) { // Draw the upper function g.setColor(info.cUpr); prev_y = (int)((fYMax-fYStep-evalUpr(fX[0]))/fYStep); for (i=0, fidx = fX[0]; i<(this.size()).width; i++, fidx += fXStep) { y = (int)((fYMax-fYStep-evalUpr(fidx))/fYStep); g.drawLine(i-1, prev_y, i, y); prev_y = y; } // Draw the lower function g.setColor(info.cLwr); prev_y = (int)((fYMax-fYStep-evalLwr(fX[0]))/fYStep); for (i=0, fidx = fX[0]; i<(this.size()).width; i++, fidx += fXStep) { y = (int)((fYMax-fYStep-evalLwr(fidx))/fYStep); g.drawLine(i-1, prev_y, i, y); prev_y = y; } } // If we should show the approximations if (bShowApprox) { // Draw the upper approximation g.setColor(info.cUprApprox); prev_y = (int)((fYMax-fYStep-evalUprApprox(fX[0]))/fYStep); y = (int)((fYMax-fYStep-evalUprApprox(fX[1]))/fYStep); g.drawLine(0, prev_y, (this.size()).width-1, y); // Draw the lower approximation g.setColor(info.cLwrApprox); prev_y = (int)((fYMax-fYStep-evalLwrApprox(fX[0]))/fYStep); y = (int)((fYMax-fYStep-evalLwrApprox(fX[1]))/fYStep); g.drawLine(0, prev_y, (this.size()).width-1, y); } } public void showQuad(boolean bValue) { bShowQuad = bValue; } public void showApprox(boolean bValue) { bShowApprox = bValue; } public void setLCoeff(int cnum, double value) { lower_c[cnum] = value; bChanged = true; } public void setInfo(IntApproxInfo newinfo) { info = newinfo; fXSpace = (fX[1]-fX[0])/((this.size()).width-iXSpace); fXStep = (fX[1]-fX[0]+fXSpace+fXSpace)/(this.size()).width; } public void setUCoeff(int cnum, double value) { upper_c[cnum] = value; bChanged = true; } public void setLCoeffStr(TextComponent comp, int cnum, String sValue) { lower_c[cnum] = Double.valueOf(sValue).doubleValue(); comp.setText((new Double(lower_c[cnum])).toString()); bChanged = true; } public void setUCoeffStr(TextComponent comp, int cnum, String sValue) { upper_c[cnum] = Double.valueOf(sValue).doubleValue(); comp.setText((new Double(upper_c[cnum])).toString()); bChanged = true; } public void setXStr(TextComponent comp, int cnum, String sValue) { fX[cnum] = Double.valueOf(sValue).doubleValue(); comp.setText((new Double(fX[cnum])).toString()); fXSpace = (fX[1]-fX[0])/((this.size()).width-iXSpace); fXStep = (fX[1]-fX[0]+fXSpace+fXSpace)/(this.size()).width; } // Evaluation functions (returns value of function at x) public double evalUpr(double x) { return (upper_c[0]*x*x + upper_c[1]*x + upper_c[2]); } public double evalUprApprox(double x) { return (uppera_c[0]*x + uppera_c[1]); } public double evalLwr(double x) { return (lower_c[0]*x*x + lower_c[1]*x + lower_c[2]); } public double evalLwrApprox(double x) { return (lowera_c[0]*x + lowera_c[1]); } public double evalDiff(double x) { return (evalUpr(x)-evalLwr(x)); } public double evalDiffApprox(double x) { return (evalUprApprox(x)-evalLwrApprox(x)); } // Calculation functions private void approxLwrSecant() { lowera_c[0] = (evalLwr(fX[1])-evalLwr(fX[0]))/(fX[1]-fX[0]); lowera_c[1] = evalLwr(fX[0])-lowera_c[0]*fX[0]; } private void approxUprSecant() { uppera_c[0] = (evalUpr(fX[1])-evalUpr(fX[0]))/(fX[1]-fX[0]); uppera_c[1] = evalUpr(fX[0])-uppera_c[0]*fX[0]; } private void approxUprTan(double x) { uppera_c[0] = upper_c[1]+2*upper_c[0]*x; uppera_c[1] = evalUpr(x)-uppera_c[0]*x; } private void approxLwrTan(double x) { lowera_c[0] = lower_c[1]+2*lower_c[0]*x; lowera_c[1] = evalLwr(x)-lowera_c[0]*x; } private boolean IsQuadraticZeroWithin(double a, double b, double c, double x1, double x2) { double x, sq; // If this is a linear function, solve it as one if (a == 0) { x = -c/b; if (x >= x1 && x <= x2) return true; else return false; } // If all coefficients are zero, then we have bad functions if (a == 0 && b == 0 & c == 0) return true; // Find the value which we must take the square // root of sq = b*b-4*a*c; // If there are no roots, all OK if (sq < 0) return false; // If there is one root and it is at one of the endpoints, // all OK if (sq == 0 && (-b/(2*a) == fX[0] || -b/(2*a) == fX[1])) return false; // If there is one root, make sure that the values to // the left of it and to the right of it keep the // same sign if (sq == 0) { if ((evalDiff(fX[0]) < 0) != (evalDiff(fX[1]) < 0)) return true; else return false; } // Now, check the actual values x = (-b + Math.sqrt(sq))/(2*a); if (x >= x1 && x <= x2) return true; x = (-b - Math.sqrt(sq))/(2*a); if (x >= x1 && x <= x2) return true; return false; } public void calcApprox() { boolean bNegative; double fidx, y =0.0; // See if the quadratics intersect if (evalUpr(fX[0]) < evalLwr(fX[0]) || IsQuadraticZeroWithin(upper_c[0]-lower_c[0], upper_c[1]-lower_c[1], upper_c[2]-lower_c[2], fX[0], fX[1])) { if (errwnd != null) { errwnd.hide(); errwnd.dispose(); } errwnd = new MessageWindow(this, "Interval Approximator Error", "The upper and lower functions intersect. Please change\n the coefficients and try again.", "OK"); // Make the coefficients neutral lower_c[0] = -1.0; lower_c[1] = 0.0; lower_c[2] = 0.0; upper_c[0] = 1.0; upper_c[1] = 0.0; upper_c[2] = 0.0; } // Depending on the case, call the correct function if (lower_c[0] <= 0 && upper_c[0] >= 0) calcCase1(); else if (lower_c[0] <= 0 && upper_c[0] < 0) calcCase2(); else if (lower_c[0] > 0 && upper_c[0] >= 0) calcCase3(); else calcCase4(); // Find the maximal and minimal Xs if (uppera_c[0] >= 0) fYMax = evalUprApprox(fX[1]); else fYMax = evalUprApprox(fX[0]); if (lowera_c[0] < 0) fYMin = evalLwrApprox(fX[1]); else fYMin = evalLwrApprox(fX[0]); // Find the Y step fYSpace = (fYMax - fYMin)/((this.size()).height-iYSpace); fYStep = (fYMax - fYMin + fYSpace + fYSpace)/(this.size()).height; // Compute the smallest difference between the quadratics fidx = -(upper_c[1]-lower_c[1])/(2*(upper_c[0]-lower_c[0])); if (fidx < fX[0]) { fidx = fX[0]; } else if (fidx > fX[1]) { fidx = fX[1]; } smallDiff = evalDiff(fidx); // Compute the largest difference between the quadratics // (which would always have to be at one of the endpoints // of their difference) largeDiff = evalDiff(fX[0]) > evalDiff(fX[1]) ? evalDiff(fX[0]) : evalDiff(fX[1]); // Compute the largest and smallest differences between the // approximators if (uppera_c[0] - lowera_c[0] >= 0) { largeADiff = evalUprApprox(fX[1])-evalLwrApprox(fX[1]); smallADiff = evalUprApprox(fX[0])-evalLwrApprox(fX[0]); } else { smallADiff = evalUprApprox(fX[1])-evalLwrApprox(fX[1]); largeADiff = evalUprApprox(fX[0])-evalLwrApprox(fX[0]); } // Inform the parent that the information has changed parent.handleEvent(new Event(this, Event.ACTION_EVENT, new EV_NewInfoDontShow(toString()))); } // Case 1: Both are secants private void calcCase1() { approxLwrSecant(); approxUprSecant(); } // Case 2: Lower is secant, see "About the Algorithm" for information // on upper private void calcCase2() { double xMax; // The x value at which the Y maximum is attained approxLwrSecant(); // Upper approximators xMax = -(upper_c[1]-lowera_c[0])/(2*upper_c[0]); if (xMax > fX[1]) { approxUprTan(fX[1]); } else if (xMax < fX[0]) { approxUprTan(fX[0]); } else { uppera_c[0] = lowera_c[0]; uppera_c[1] = evalUpr(xMax)-lowera_c[0]*xMax; } } // Case 3: Upper is secant, see "About the Algorithm" for information // on lower private void calcCase3() { double xMax; // The x value at which the Y maximum is attained approxUprSecant(); // Lower approximators xMax = -(lower_c[1]-uppera_c[0])/(2*lower_c[0]); if (xMax > fX[1]) { approxLwrTan(fX[1]); } else if (xMax < fX[0]) { approxLwrTan(fX[0]); } else { lowera_c[0] = uppera_c[0]; lowera_c[1] = evalLwr(xMax)-uppera_c[0]*xMax; } } // Case 4: See "About the Algorithm" private void calcCase4() { double xMax; // The x value at which the Y maximum is attained xMax = -(upper_c[1]-lower_c[1])/(2*(upper_c[0]-lower_c[0])); if (xMax > fX[1]) { approxLwrTan(fX[1]); approxUprTan(fX[1]); } else if (xMax < fX[0]) { approxLwrTan(fX[0]); approxUprTan(fX[0]); } else { approxLwrTan(xMax); approxUprTan(xMax); } } } public class IntApprox extends Applet { IntApproxInfo info; boolean bHideShow = false; TextField tf_lower_c1, tf_lower_c2, tf_lower_c3, tf_upper_c1, tf_upper_c2, tf_upper_c3, tf_x1, tf_x2; Label l_lower_c1, l_lower_c2, l_lower_c3, l_upper_c1, l_upper_c2, l_upper_c3, l_x1, l_x2, l_x3; IntApproxCanvas iac; Button bGraph, bInfo, bAboutAlg; MessageWindow wInfo; Panel panel, empty1, empty2, empty3; public void init() { Dimension dim_tf = new Dimension(4,1), dim_smalll = new Dimension(1,1), dim_largel = new Dimension(6,1), dim_empty = new Dimension(1,1), dim_smallb = new Dimension(4,1), dim_mediumb = new Dimension(6,1), dim_largeb = new Dimension(10,1); int iacWidth, iacHeight; // Get the color parameters info = new IntApproxInfo(); info.cUpr = getColorParameter("color_upr", Color.green); info.cLwr = getColorParameter("color_lwr", Color.blue); info.cUprApprox = getColorParameter("color_uprapprox", Color.red); info.cLwrApprox = getColorParameter("color_lwrapprox", Color.cyan); info.cOther = getColorParameter("color_other", Color.white); // Create the text fields tf_lower_c1 = new TextField(getDefParameter("lower_c1", "-1.0"), 5); tf_lower_c1.setEditable(true); tf_lower_c2 = new TextField(getDefParameter("lower_c2", "0.0"), 5); tf_lower_c2.setEditable(true); tf_lower_c3 = new TextField(getDefParameter("lower_c3", "0.0"), 5); tf_lower_c3.setEditable(true); tf_upper_c1 = new TextField(getDefParameter("upper_c1", "1.0"), 5); tf_upper_c1.setEditable(true); tf_upper_c2 = new TextField(getDefParameter("upper_c2", "0.0"), 5); tf_upper_c2.setEditable(true); tf_upper_c3 = new TextField(getDefParameter("upper_c3", "0.0"), 5); tf_upper_c3.setEditable(true); tf_x1 = new TextField(getDefParameter("left_x", "-1.0"), 5); tf_x1.setEditable(true); tf_x2 = new TextField(getDefParameter("right_x", "1.0"), 5); tf_x2.setEditable(true); // Create the labels l_lower_c1 = new Label("Lower Function: y-(x) = "); l_lower_c2 = new Label(" x*x + "); l_lower_c3 = new Label(" x + "); l_upper_c1 = new Label("Upper Function: y+(x) = "); l_upper_c2 = new Label(" x*x + "); l_upper_c3 = new Label(" x + "); l_x1 = new Label("Domain: ["); l_x2 = new Label(","); l_x3 = new Label("]"); // Create the buttons bGraph = new Button("Graph"); bInfo = new Button("Show Info"); bAboutAlg = new Button("About the Approximation Algorithm"); // Set the layout manager setLayout(new BorderLayout()); // Create spacer panels empty1 = new Panel(); empty2 = new Panel(); empty3 = new Panel(); // Create a "user-interface" panel panel = new Panel(); panel.setLayout(new GridBagLayout()); // Add the fields to the panel add_curpos(panel,empty1, dim_empty); nl_curpos(); add_curpos(panel,l_lower_c1, dim_largel); add_curpos(panel,tf_lower_c1, dim_tf); add_curpos(panel,l_lower_c2, dim_smalll); add_curpos(panel,tf_lower_c2, dim_tf); add_curpos(panel,l_lower_c3, dim_smalll); add_curpos(panel,tf_lower_c3, dim_tf); nl_curpos(); add_curpos(panel,l_upper_c1, dim_largel); add_curpos(panel,tf_upper_c1, dim_tf); add_curpos(panel,l_upper_c2, dim_smalll); add_curpos(panel,tf_upper_c2, dim_tf); add_curpos(panel,l_upper_c3, dim_smalll); add_curpos(panel,tf_upper_c3, dim_tf); nl_curpos(); add_curpos(panel,l_x1, dim_largel); add_curpos(panel,tf_x1, dim_tf); add_curpos(panel,l_x2, dim_smalll); add_curpos(panel,tf_x2, dim_tf); add_curpos(panel,l_x3, dim_smalll); nl_curpos(); // Add the buttons add_curpos(panel,empty2,dim_empty); nl_curpos(); skipx_curpos(1); add_curpos(panel,bGraph,dim_smallb); add_curpos(panel,bInfo,dim_mediumb); add_curpos(panel,bAboutAlg,dim_largeb); nl_curpos(); add_curpos(panel,empty3,dim_empty); // Create the canvas iac = new IntApproxCanvas(this); // Add the panel and the canvas add("North", panel); add("South", iac); validate(); // Set its width and height if (getParameter("CANVAS_WIDTH") != null) iacWidth = Integer.parseInt(getParameter("CANVAS_WIDTH"), 10); else iacWidth = (this.size()).width; if (getParameter("CANVAS_HEIGHT") != null) iacHeight = Integer.parseInt(getParameter("CANVAS_HEIGHT"), 10); else iacHeight = (this.size()).height - (panel.size()).height; if (iacHeight+(panel.size()).height > (this.size()).height) iacHeight = (this.size()).height - (panel.size()).height; iac.resize(iacWidth, iacHeight); // Now that we have the correct size, let the layout // manager do its work again validate(); // Set misc. information iac.setInfo(info); iac.setBackground(getColorParameter("BGCOLOR", info.cUpr.black)); // If we should draw something, do it if (getParameter("SHOW_QUAD") != null) iac.showQuad(true); if (getParameter("SHOW_APPROX") != null) iac.showApprox(true); doGraph(false); } // Handle events public boolean handleEvent(Event event) { switch (event.id) { case Event.GOT_FOCUS: // If there is an info window if (wInfo != null) { // Make sure it is displayed on top of the // applet viewer's window if this was done // because of an info request bHideShow = true; } return true; } return super.handleEvent(event); } public boolean action(Event e, Object o) { String sInfo; if (e.target instanceof Button) { if (e.target == bGraph) doGraph(true); else if (e.target == bAboutAlg) { try { getAppletContext().showDocument(new URL(getDefParameter("about_url", "http://intcomp.home.ml.org/intapprox/aboutalg.html"))); } catch (MalformedURLException exception) { } } else if (e.target == bInfo) { if (wInfo != null) { wInfo.hide(); wInfo.dispose(); wInfo = null; bInfo.setLabel("Show Info"); } else { // Get the info sInfo = iac.toString(); // And set it wInfo = new MessageWindow(this, "Interval Approximator Info", sInfo, "Hide"); bInfo.setLabel("Hide Info"); } } } else if (e.target == wInfo) { if (e.arg instanceof EV_Closing) { wInfo = null; bInfo.setLabel("Show Info"); } } else if (e.target == iac) { if (e.arg instanceof EV_Closing) { wInfo = null; bInfo.setLabel("Show Info"); } else if (e.arg instanceof EV_NewInfo) { sInfo = ((EV_NewInfo)e.arg).toString(); if (wInfo == null) { wInfo = new MessageWindow(this, "Interval Approximator Info", sInfo, "Hide"); bInfo.setLabel("Hide Info"); } else { wInfo.setMessage(sInfo); wInfo.repaint(); if (bHideShow) { wInfo.hide(); wInfo.show(); bHideShow = false; } } } else if (e.arg instanceof EV_NewInfoDontShow && wInfo != null) { sInfo = ((EV_NewInfoDontShow)e.arg).toString(); wInfo.setMessage(sInfo); } else if (e.arg instanceof EV_CloseInfo) { wInfo.hide(); wInfo.dispose(); wInfo = null; bInfo.setLabel("Show Info"); } } return true; } // Utility functions public void doGraph(boolean bShowBoth) { // Get all the coefficient values iac.setLCoeffStr(tf_lower_c1, 0, tf_lower_c1.getText()); iac.setLCoeffStr(tf_lower_c2, 1, tf_lower_c2.getText()); iac.setLCoeffStr(tf_lower_c3, 2, tf_lower_c3.getText()); iac.setUCoeffStr(tf_upper_c1, 0, tf_upper_c1.getText()); iac.setUCoeffStr(tf_upper_c2, 1, tf_upper_c2.getText()); iac.setUCoeffStr(tf_upper_c3, 2, tf_upper_c3.getText()); // Get the Xs iac.setXStr(tf_x1, 0, tf_x1.getText()); iac.setXStr(tf_x2, 1, tf_x2.getText()); // Graph the functions if (bShowBoth) { iac.showQuad(true); iac.showApprox(true); } iac.repaint(); } int gridCurX = 0, gridCurY = 0; public void add_curpos(Container container, Component component, Dimension dim) { constrain(container, component, gridCurX, gridCurY, dim.width, dim.height); gridCurX += dim.width; } public void nl_curpos() { gridCurY++; gridCurX = 0; } public void skipx_curpos(int x) { gridCurX += x; } public void constrain(Container container, Component component, int x, int y, int width, int height) { GridBagConstraints c = new GridBagConstraints(); c.gridx = x; c.gridy = y; c.gridwidth = width; c.gridheight = height; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; c.weightx = 0; c.weighty = 0; ((GridBagLayout)container.getLayout()).setConstraints(component, c); container.add(component); } public String getDefParameter(String sParName, String sDefault) { String sValue; sValue = getParameter(sParName); if (sValue == null) return sDefault; else return sValue; } public Color getColorParameter(String sName, Color cDefault) { String sParam; int idx = 0, r = 0, g = 0, b = 0; // If the parameter is empty, return the default color sParam = getParameter(sName); if (sParam == null) return cDefault; sParam = sParam.toUpperCase(); // Process the string if (sParam.charAt(idx) == '#') idx++; r = Integer.parseInt(sParam.substring(idx, idx+2), 16); idx += 2; g = Integer.parseInt(sParam.substring(idx, idx+2), 16); idx += 2; b = Integer.parseInt(sParam.substring(idx, idx+2), 16); idx += 2; // Return the color return (new Color(r,g,b)); } // Information functions public String[][] getParameterInfo() { String[][] info = { {"lower_c1", "floating-point value", "The coefficient of the lower function y-(x) at x*x"}, {"lower_c2", "floating-point value", "The coefficient of the lower function y-(x) at x"}, {"lower_c3", "floating-point value", "The coefficient of the lower function y-(x) at 1"}, {"upper_c1", "floating-point value", "The coefficient of the upper function y+(x) at x*x"}, {"upper_c2", "floating-point value", "The coefficient of the upper function y+(x) at x"}, {"upper_c3", "floating-point value", "The coefficient of the upper function y+(x) at 1"}, {"left_x", "floating-point value", "The left-most X coordinate to be displayed"}, {"right_x", "floating-point value", "The right-most X coordinate to be displayed"}, {"color_upr", "RGB color value", "The color of the upper quadratic function"}, {"color_lwr", "RGB color value", "The color of the lower quadratic function"}, {"color_uprapprox", "RGB color value", "The color of the upper approximator function"}, {"color_lwrapprox", "RGB color value", "The color of the lower approximator function"}, {"color_other", "RGB color value", "The color of parts of the graph not representing a function, such as the axes"}, {"bgcolor", "RGB color value", "The background color of the drawing area"}, {"canvas_width", "string", "The width of the drawing canvas on which the functions will be drawn"}, {"canvas_height", "string", "The height of the drawing canvas on which the functions will be drawn"}, {"show_quad", "flag", "If set, specifies that the quadratic functions should be shown on startup"}, {"show_approx", "flag", "If set, specifies that the approximator functions should be shown on startup"}}; return info; } public String getAppletInfo() { return "IntApprox v. 1.0. Written by Misha Koshelev."; } }