// // Parameter_Plane is part of the MAA/USMA Lite Applet Construction Kit Project // // Written by Frank Wattenberg // // Version 0.00 // 2 May, 2002 // import java.awt.*; import java.applet.*; import java.util.*; import java.io.*; // for Expr class import java.util.Hashtable; // for Variable class import java.util.Vector; public class Parameter_Plane extends Applet { int check_out_sw = 1; int margin; int graph_width = 301; int width, height; int mark_x[] = new int[1000]; int mark_y[] = new int[1000]; int mark_index = 0; int mark_sw = 0; // 0 = ready to mark, 1 = not ready to mark int de_sw = 0; // 0 = algebraically defined functions, 1 = IVP defined functions int parameter_space_curve_sw = 0; // 1 = draw a curve in the parameter space; int mark_point_sw; // 0 = enable point marking, 1 = disable point marking int time_mark = 0; // Time to mark point for if parameter_space_curve_sw = 1 double a_low, a_high, b_low, b_high, x_low, x_high, y_low, y_high; double a_value, b_value; String a_low_label, a_high_label, b_low_label, b_high_label; String x_low_label, x_high_label, y_low_label, y_high_label; String a_axis_label, b_axis_label, x_axis_label, y_axis_label; String legend_1, legend_2, legend_3; String a_label, b_label; // Used for variable names Graphics bG; Image bI; Font textfont = new Font("Courier", Font.PLAIN, 14); Color background_color; Color parameter_graph_color; Color function_graph_color; Color grid_color; Color cursor_color; Color mark_color; Color mark_button_color, mark_button_shadow_color, clear_button_color, clear_button_shadow_color; Color legend_1_color, legend_2_color, legend_3_color; Color parameter_space_curve_color; Color time_mark_color; LeftArrow FastLeftArrow, SlowLeftArrow; RightArrow FastRightArrow, SlowRightArrow; UpArrow FastUpArrow, SlowUpArrow; DownArrow FastDownArrow, SlowDownArrow; VCRButton mark_button, clear_button; Expr y_of_x[] = new Expr[10]; Expr y_prime[] = new Expr[10]; Expr initial_value[] = new Expr[10]; Color y_of_x_color[] = new Color[10]; int y_of_x_thickness[] = new int[10]; int parameter_space_curve_thickness; int number_of_curves; String y_of_x_string; Variable x; Variable a; Variable b; Variable y[] = new Variable[10]; Variable Picon = Variable.make("Pi"); // define Pi, pi, E, and e Variable PIcon = Variable.make("PI"); Variable picon = Variable.make("pi"); Variable Econ = Variable.make("E"); Variable econ = Variable.make("e"); DataDisplayFrame message_window; // Window for parser error messages. String recovery_message_line_1; // Recovery message printed for syntax errors String recovery_message_line_2; public void init() { check_out_sw = getInteger("check_out_sw", 0, 1, 1); if (check_out_sw == 1) { System.out.println("Starting Parameter_Plane Applet."); System.out.println("Parameter messages to follow."); } else { System.out.println("Starting Parameter_Plane Applet."); System.out.println("Parameter messages omitted."); System.out.println("To turn parameter messages on add an"); System.out.println("applet parameter tag setting check_out_sw to 1."); } margin = getInteger("margin", 50, 100, 50); width = 4 * margin + 2 * graph_width; height = 4 * margin + graph_width; bI = createImage(width, height); // Screen buffer bG = bI.getGraphics(); bG.setFont(textfont); FastLeftArrow = new LeftArrow(margin + graph_width/2 - 40, margin/2, 10); SlowLeftArrow = new LeftArrow(margin + graph_width/2 - 20, margin/2, 5); FastRightArrow = new RightArrow(margin + graph_width/2 + 40, margin/2, 10); SlowRightArrow = new RightArrow(margin + graph_width/2 + 20, margin/2, 5); FastUpArrow = new UpArrow(margin + graph_width + margin/2, margin + graph_width/2 - 40, 10); SlowUpArrow = new UpArrow(margin + graph_width + margin/2, margin + graph_width/2 - 20, 5); FastDownArrow = new DownArrow(margin + graph_width + margin/2, margin + graph_width/2 + 40, 10); SlowDownArrow = new DownArrow(margin + graph_width + margin/2, margin + graph_width/2 + 20, 5); de_sw = getInteger("de_sw", 0, 1, 0); parameter_space_curve_sw = getInteger("parameter_space_curve_sw", 0, 1, 0); mark_point_sw = getInteger("mark_point_sw", 0, 1, 0); background_color = getColor("background_color", "255255255"); parameter_graph_color = getColor("parameter_graph_color", "192192255"); function_graph_color = getColor("function_graph_color", "192255192"); grid_color = getColor("grid_color", "000000000"); cursor_color = getColor("cursor_color", "255000000"); mark_color = getColor("mark_color", "000000255"); mark_button_color = getColor("mark_button_color", "128128255"); mark_button_shadow_color = getColor("mark_button_shadow_color", "000000000"); clear_button_color = getColor("clear_button_color", "128128255"); clear_button_shadow_color = getColor("clear_button_shadow_color", "000000000"); parameter_space_curve_color = getColor("parameter_space_curve_color", "000000000"); time_mark_color = getColor("time_mark_color", "000000000"); mark_button = new VCRButton(margin, 3 * margin + graph_width, 80, 20, mark_button_color, background_color, mark_button_shadow_color, "Mark point"); clear_button = new VCRButton(margin + graph_width/2, 3 * margin + graph_width, 80, 20, clear_button_color, background_color, clear_button_shadow_color, "Clear marked points"); a_low = getDouble("a_low", -9999, 9999, -1); a_low_label = getString("a_low_label", "-1"); a_high = getDouble("a_high", -9999, 9999, 1); a_high_label = getString("a_high_label", "1"); a_value = getDouble("a_initial", a_low, a_high, (a_low + a_high)/2); a_axis_label = getString("a_axis_label", "a"); a_label = getString("a_label", a_axis_label); b_low = getDouble("b_low", -9999, 9999, -1); b_low_label = getString("b_low_label", "-1"); b_high = getDouble("b_high", -9999, 9999, 1); b_high_label = getString("b_high_label", "1"); b_value = getDouble("b_initial", b_low, b_high, (b_low + b_high)/2); b_axis_label = getString("b_axis_label", "b"); b_label = getString("b_label", b_axis_label); x_low = getDouble("x_low", -9999, 9999, -1); x_low_label = getString("x_low_label", "-1"); x_high = getDouble("x_high", -9999, 9999, 1); x_high_label = getString("x_high_label", "1"); x_axis_label = getString("x_axis_label", "x"); y_low = getDouble("y_low", -9999, 9999, -1); y_low_label = getString("y_low_label", "-1"); y_high = getDouble("y_high", -9999, 9999, 1); y_high_label = getString("y_high_label", "1"); y_axis_label = getString("y_axis_label", "y"); legend_1 = getString("legend_1", ""); legend_2 = getString("legend_2", ""); legend_3 = getString("legend_3", ""); legend_1_color = getColor("legend_1_color", "000000000"); legend_2_color = getColor("legend_2_color", "000000000"); legend_3_color = getColor("legend_3_color", "000000000"); time_mark = getInteger("time_mark_initial", 0, 150, 0); picon.set_value(Math.PI); Picon.set_value(Math.PI); PIcon.set_value(Math.PI); econ.set_value(Math.E); Econ.set_value(Math.E); recovery_message_line_1 = getString("recovery_message_line_1", "Algebraic Expression Syntax Error."); recovery_message_line_2 = getString("recovery_message_line_2", ""); number_of_curves = getInteger("number_of_curves", 1, 10, 10); for (int i = 0; i < number_of_curves; i = i + 1) { y_of_x_string = getString("y_of_x_"+ java.lang.Integer.toString(i + 1), "x^4/4 + b * x^2/2 + a * x"); try { y_of_x[i] = Parser.parse(y_of_x_string); } catch (SyntaxException e) { tell_error("Syntax error: " + e + "\n" + e.explain()); return; } y_of_x_string = getString("y_"+ java.lang.Integer.toString(i + 1) + "_prime", "x^4/4 + b * x^2/2 + a * x"); try { y_prime[i] = Parser.parse(y_of_x_string); } catch (SyntaxException e) { tell_error("Syntax error: " + e + "\n" + e.explain()); return; } y_of_x_color[i] = getColor("y_of_x_color_" + java.lang.Integer.toString(i + 1), "000000000"); y_of_x_thickness[i] = getInteger("y_of_x_thickness_" + java.lang.Integer.toString(i + 1), 0, 2, 1); if (de_sw == 1) { y_of_x_string = getString("initial_value_" + java.lang.Integer.toString(i + 1), "t"); try { initial_value[i] = Parser.parse(y_of_x_string); } catch (SyntaxException e) { tell_error("Syntax error: " + e + "\n" + e.explain()); return; } } } x = Variable.make(x_axis_label); a = Variable.make(a_label); b = Variable.make(b_label); parameter_space_curve_thickness = getInteger("parameter_space_curve_thickness", 0, 2, 1); for (int i = 0; i < number_of_curves; i = i + 1) y[i] = Variable.make(getString("y_" + java.lang.Integer.toString(i + 1) + "_label", "y" + java.lang.Integer.toString(i + 1))); } public int x_coord(double x) { double work; work = 3 * margin + graph_width - 1 + (x - x_low) * graph_width / (x_high - x_low); return (int) java.lang.Math.round(work); } public int y_coord(double y) { double work; work = margin - 1 + graph_width - (y - y_low) * graph_width / (y_high - y_low); return (int) java.lang.Math.round(work); } public int a_coord(double a) { double work; work = margin - 1 + (a - a_low) * graph_width / (a_high - a_low); return (int) java.lang.Math.round(work); } public int b_coord(double b) { double work; work = margin - 1 + graph_width - (b - b_low) * graph_width / (b_high - b_low); return (int) java.lang.Math.round(work); } public int getInteger(String param_name, int low, int high, int no_param) { int value; if (check_out_sw == 1) { System.out.println("Parameter: " + param_name); System.out.println(" Default value: " + java.lang.Integer.toString(no_param)); } if (getParameter(param_name) != null) { value = Integer.parseInt(getParameter(param_name)); value = java.lang.Math.min(high, java.lang.Math.max(low, value)); } else { value = no_param; } if (check_out_sw == 1) { System.out.println(" Actual value: " + java.lang.Integer.toString(value)); } return value; } public void paint(Graphics g) { super.paint(g); draw_screen(); g.drawImage(bI, 0, 0, this); } public void update(Graphics g) { paint(g); } public void draw_screen() { // // Draw before background for clipping // int x_start, x_end; int y_int_start[] = new int[10]; int y_int_end[] = new int[10]; double y_start[] = new double[10]; double y_end[] = new double[10]; double v1[] = new double[10]; double v2[] = new double[10]; double v3[] = new double[10]; double v4[] = new double[10]; double curve_a_start, curve_a_end, curve_b_start, curve_b_end; int n = 150; int save_a[] = new int[151]; int save_b[] = new int[151]; int thickness; int work; double dx = (x_high - x_low)/n; bG.setColor(parameter_graph_color); bG.fillRect(margin, margin, graph_width, graph_width); bG.setColor(function_graph_color); bG.fillRect(3 * margin + graph_width, margin, graph_width, graph_width); bG.setColor(grid_color); for (int i = 0; i <= graph_width; i = i + graph_width/20) { bG.drawLine(margin, margin + i, margin + graph_width - 1, margin + i); bG.drawLine(3 * margin + graph_width, margin + i, 3 * margin + 2 * graph_width - 1, margin + i); bG.drawLine(margin + i, margin, margin + i, margin + graph_width - 1); bG.drawLine(3 * margin + graph_width + i, margin, 3 * margin + graph_width + i, margin + graph_width - 1); } if ((a_low < 0) & (0 < a_high)) { work = a_coord(0.0); bG.drawLine(work - 1, margin, work - 1, margin + graph_width); bG.drawLine(work + 1, margin, work + 1, margin + graph_width); } if ((x_low < 0) & (0 < x_high)) { work = x_coord(0.0); bG.drawLine(work - 1, margin, work - 1, margin + graph_width); bG.drawLine(work + 1, margin, work + 1, margin + graph_width); } if ((b_low < 0) & (0 < b_high)) { work = b_coord(0.0); bG.drawLine(margin, work - 1, margin + graph_width, work - 1); bG.drawLine(margin, work + 1, margin + graph_width, work + 1); } if ((y_low < 0) & (0 < y_high)) { work = y_coord(0.0); bG.drawLine(3 * margin + graph_width, work - 1, 3 * margin + 2 * graph_width, work - 1); bG.drawLine(3 * margin + graph_width, work + 1, 3 * margin + 2 * graph_width, work + 1); } a.set_value(a_value); b.set_value(b_value); if (de_sw == 0) { // // The curves are described by functions // for (int p = 0; p < number_of_curves; p = p + 1) { thickness = y_of_x_thickness[p]; bG.setColor(y_of_x_color[p]); x_start = x_coord(x_low); x.set_value(x_low); y_int_start[p] = y_coord(y_of_x[p].value()); for (int i = 1; i <= n; i = i + 1) { x_end = x_coord(x_low + i * dx); x.set_value(x_low + i * dx); y_int_end[p] = y_coord(y_of_x[p].value()); for (int j = -thickness; j <= thickness; j = j + 1) { for (int k = -thickness; k <= thickness; k = k + 1) bG.drawLine(x_start + j, y_int_start[p] + k, x_end + j, y_int_end[p] + k); } x_start = x_end; y_int_start[p] = y_int_end[p]; } } } else { // // The curves are described by differential equations // // The method used is the standard fourth order Runge-Kutta Method // x_start = x_coord(x_low); // starting coordinate for (int p = 0; p < number_of_curves; p = p + 1) { y_start[p] = initial_value[p].value(); // double value at start y_int_start[p] = y_coord(y_start[p]); // starting coordinate } if (parameter_space_curve_sw == 1) { save_a[0] = a_coord(initial_value[0].value()); save_b[0] = b_coord(initial_value[1].value()); } for (int i = 1; i <= n; i = i + 1) { x_end = x_coord(x_low + i * dx); // ending coordinate x.set_value(x_low + (i - 1) * dx); // set values of x, y1, ... yn for computation of v1 for (int p = 0; p < number_of_curves; p = p + 1) y[p].set_value(y_start[p]); for (int p = 0; p < number_of_curves; p = p + 1) v1[p] = y_prime[p].value(); x.set_value(x_low + (i - 0.5) * dx); // set values of x, y1, ... yn for computation of v2 for (int p = 0; p < number_of_curves; p = p + 1) y[p].set_value(y_start[p] + dx * v1[p]/2); for (int p = 0; p < number_of_curves; p = p + 1) v2[p] = y_prime[p].value(); for (int p = 0; p < number_of_curves; p = p + 1) // set values of y1, ... yn for computation of v3 y[p].set_value(y_start[p] + dx * v2[p]/2); for (int p = 0; p < number_of_curves; p = p + 1) v3[p] = y_prime[p].value(); x.set_value(x_low + i * dx); // set values of x, y1, ... yn for computation of v4 for (int p = 0; p < number_of_curves; p = p + 1) y[p].set_value(y_start[p] + dx * v3[p]); for (int p = 0; p < number_of_curves; p = p + 1) v4[p] = y_prime[p].value(); for (int p = 0; p < number_of_curves; p = p + 1) { y_end[p] = y_start[p] + dx * (v1[p] + 2 * v2[p] + 2 * v3[p] + v4[p])/6; y_int_end[p] = y_coord(y_end[p]); } for (int p = 0; p < number_of_curves; p = p + 1) // graph this segment of the solution { thickness = y_of_x_thickness[p]; bG.setColor(y_of_x_color[p]); for (int j = -thickness; j <= thickness; j = j + 1) { for (int k = -thickness; k <= thickness; k = k + 1) bG.drawLine(x_start + j, y_int_start[p] + k, x_end + j, y_int_end[p] + k); } } if (parameter_space_curve_sw == 1) { save_a[i] = a_coord(y_end[0]); save_b[i] = b_coord(y_end[1]); bG.setColor(parameter_space_curve_color); for (int j = -parameter_space_curve_thickness; j <= parameter_space_curve_thickness; j = j + 1) { for (int k = -parameter_space_curve_thickness; k <= parameter_space_curve_thickness; k = k + 1) { if ((a_coord(y_start[0]) < graph_width + 2 * margin) && (a_coord(y_end[0]) < graph_width + 2 * margin)) bG.drawLine(a_coord(y_start[0]) + j, b_coord(y_start[1]) + k, a_coord(y_end[0]) + j, b_coord(y_end[1]) + k); } } } x_start = x_end; for (int p = 0; p < number_of_curves; p = p + 1) { y_start[p] = y_end[p]; y_int_start[p] = y_int_end[p]; } } } // // Draw background to clip // bG.setColor(background_color); bG.fillRect(0, 0, width, margin); bG.fillRect(0, margin + graph_width, width, 3 * margin); bG.fillRect(0, 0, margin, height); bG.fillRect(margin + graph_width, 0, 2 * margin, height); bG.fillRect(3 * margin + 2 * graph_width, 0, margin, height); // // Draw after background // bG.setColor(grid_color); FastLeftArrow.draw(bG); SlowLeftArrow.draw(bG); FastRightArrow.draw(bG); SlowRightArrow.draw(bG); FastUpArrow.draw(bG); SlowUpArrow.draw(bG); FastDownArrow.draw(bG); SlowDownArrow.draw(bG); if (mark_point_sw == 0) { if (mark_sw == 0) mark_button.draw_off(bG); else mark_button.draw_on(bG); if (mark_index > 0) clear_button.draw_off(bG); else clear_button.draw_on(bG); } bG.drawString(a_low_label, margin - bG.getFontMetrics().stringWidth(a_low_label)/2, (5 * margin)/4 + graph_width + 2); bG.drawString(a_high_label, margin + graph_width - bG.getFontMetrics().stringWidth(a_high_label)/2, (5 * margin)/4 + graph_width + 2); bG.drawString(x_low_label, 3 * margin + graph_width - bG.getFontMetrics().stringWidth(x_low_label)/2, (5 * margin)/4 + graph_width + 2); bG.drawString(x_high_label, 3 * margin + 2 * graph_width - bG.getFontMetrics().stringWidth(x_high_label)/2, (5 * margin)/4 + graph_width + 2); bG.drawString(b_low_label, margin - bG.getFontMetrics().stringWidth(b_low_label) - 4, margin + graph_width + 4); bG.drawString(b_high_label, margin - bG.getFontMetrics().stringWidth(b_high_label) - 4, margin + 4); bG.drawString(y_low_label, 3 * margin + graph_width - bG.getFontMetrics().stringWidth(y_low_label) - 4, margin + graph_width + 4); bG.drawString(y_high_label, 3 * margin + graph_width - bG.getFontMetrics().stringWidth(y_high_label) - 4, margin + 4); bG.drawString(a_axis_label, margin + graph_width/2 - bG.getFontMetrics().stringWidth(a_axis_label)/2, (3 * margin)/2 + graph_width); bG.drawString(x_axis_label, 3 * margin + (3 * graph_width)/2 - bG.getFontMetrics().stringWidth(x_axis_label)/2, (3 * margin)/2 + graph_width); bG.drawString(b_axis_label, margin - 12 - bG.getFontMetrics().stringWidth(b_axis_label), margin + graph_width/2 + 4); bG.drawString(y_axis_label, 3 * margin + graph_width - 12 - bG.getFontMetrics().stringWidth(y_axis_label), margin + graph_width/2 + 4); bG.setColor(legend_1_color); bG.drawString(legend_1, width/2 - bG.getFontMetrics().stringWidth(legend_1)/2, 2 * margin + graph_width); bG.setColor(legend_2_color); bG.drawString(legend_2, width/2 - bG.getFontMetrics().stringWidth(legend_2)/2, 2 * margin + graph_width + 18); bG.setColor(legend_3_color); bG.drawString(legend_3, width/2 - bG.getFontMetrics().stringWidth(legend_3)/2, 2 * margin + graph_width + 36); bG.setColor(cursor_color); bG.fillRect(a_coord(a_value) - 4, b_coord(b_value) - 4, 9, 9); bG.setColor(mark_color); for (int i = 0; i < mark_index; i = i + 1) bG.fillRect(mark_x[i] - 2, mark_y[i] - 2, 5, 5); if ((parameter_space_curve_sw == 1) && (time_mark > 0)) { bG.setColor(time_mark_color); bG.fillOval(save_a[time_mark] - 5, save_b[time_mark] - 5, 11, 11); bG.drawLine(3 * margin + graph_width + 2 * time_mark, margin, 3 * margin + graph_width + 2 * time_mark, margin + graph_width - 2); bG.drawLine(3 * margin + graph_width + 2 * time_mark - 1, margin, 3 * margin + graph_width + 2 * time_mark - 1, margin + graph_width - 2); bG.drawLine(3 * margin + graph_width + 2 * time_mark + 1, margin, 3 * margin + graph_width + 2 * time_mark + 1, margin + graph_width - 2); for (int i = 0; i <= 6; i = i + 1) { bG.drawLine(3 * margin + graph_width + 2 * time_mark - i, margin - 2 - i, 3 * margin + graph_width + 2 * time_mark + i, margin - 2 - i); bG.drawLine(3 * margin + graph_width + 2 * time_mark - i, margin + graph_width + 2 + i, 3 * margin + graph_width + 2 * time_mark + i, margin + graph_width + 2 + i); } } } public boolean mouseDown(Event evt, int mx, int my) { if ((margin <= mx) & (mx <= margin + graph_width) & (margin <= my) & (my <= margin + graph_width)) { a_value = a_low + (a_high - a_low) * (mx - margin)/graph_width; b_value = b_low + (b_high - b_low) * (graph_width + margin - my)/graph_width; mark_sw = 0; time_mark = 0; repaint(); return true; } if (SlowLeftArrow.test(mx, my)) { a_value = a_value - (a_high - a_low)/graph_width; a_value = java.lang.Math.max(a_value, a_low); mark_sw = 0; time_mark = 0; repaint(); return true; } if (FastLeftArrow.test(mx, my)) { a_value = a_value - 15 * (a_high - a_low)/graph_width; a_value = java.lang.Math.max(a_value, a_low); mark_sw = 0; time_mark = 0; repaint(); return true; } if (SlowRightArrow.test(mx, my)) { a_value = a_value + (a_high - a_low)/graph_width; a_value = java.lang.Math.min(a_value, a_high); mark_sw = 0; time_mark = 0; repaint(); return true; } if (FastRightArrow.test(mx, my)) { a_value = a_value + 15 * (a_high - a_low)/graph_width; a_value = java.lang.Math.min(a_value, a_high); mark_sw = 0; time_mark = 0; repaint(); return true; } if (SlowDownArrow.test(mx, my)) { b_value = b_value - (b_high - b_low)/graph_width; b_value = java.lang.Math.max(b_value, b_low); mark_sw = 0; time_mark = 0; repaint(); return true; } if (FastDownArrow.test(mx, my)) { b_value = b_value - 15 * (b_high - b_low)/graph_width; b_value = java.lang.Math.max(b_value, b_low); mark_sw = 0; time_mark = 0; repaint(); return true; } if (SlowUpArrow.test(mx, my)) { b_value = b_value + (b_high - b_low)/graph_width; b_value = java.lang.Math.min(b_value, b_high); mark_sw = 0; time_mark = 0; repaint(); return true; } if (FastUpArrow.test(mx, my)) { b_value = b_value + 15 * (b_high - b_low)/graph_width; b_value = java.lang.Math.min(b_value, b_high); mark_sw = 0; time_mark = 0; repaint(); return true; } if ((mark_point_sw == 0) && (mark_button.test(mx, my))) { mark_x[mark_index] = a_coord(a_value); mark_y[mark_index] = b_coord(b_value); mark_index = java.lang.Math.min(999, mark_index + 1); mark_sw = 1; repaint(); return true; } if ((mark_point_sw == 0) && (clear_button.test(mx, my))) { mark_index = 0; mark_sw = 0; repaint(); return true; } if ((3 * margin + graph_width < mx) && (mx <= 3 * margin + 2 * graph_width) && (margin - 10 < my) && (my < margin + graph_width + 10)) { time_mark = (mx - (3 * margin + graph_width))/2; repaint(); return true; } return true; } public Color getColor(String color_parameter, String default_color_parameter) { int red, green, blue; Color color_variable; String work; work = getString(color_parameter, default_color_parameter); red = Integer.parseInt(work.substring(0, 3)); green = Integer.parseInt(work.substring(3, 6)); blue = Integer.parseInt(work.substring(6, 9)); red = java.lang.Math.max(0, java.lang.Math.min(255, red)); green = java.lang.Math.max(0, java.lang.Math.min(255, green)); blue = java.lang.Math.max(0, java.lang.Math.min(255, blue)); color_variable = new Color(red, green, blue); return color_variable; } public String getString(String param_name, String no_param) { String value; if (check_out_sw == 1) { System.out.println("Parameter: " + param_name); System.out.println(" Default value: " + no_param); } if (getParameter(param_name) != null) { value = getParameter(param_name); } else { value = no_param; } if (check_out_sw == 1) { System.out.println(" Actual value: " + value); } return value; } public double getDouble(String param_name, double low, double high, double no_param) { double value; if (check_out_sw == 1) { System.out.println("Parameter: " + param_name); System.out.println(" Default value: " + java.lang.Double.toString(no_param)); } if (getParameter(param_name) != null) { value = java.lang.Double.valueOf(getParameter(param_name)).doubleValue(); value = java.lang.Math.min(high, java.lang.Math.max(low, value)); } else { value = no_param; } if (check_out_sw == 1) { System.out.println(" Actual value: " + java.lang.Double.toString(value)); } return value; } public void tell_error(String message) { message_window = new DataDisplayFrame("Expression Error"); message_window.hide(); message_window.clearText(); message_window.addText("An error has been detected in an algebraic expression.\n\n"); message_window.addText(message); message_window.addText("\n\n"); message_window.addText(recovery_message_line_1); message_window.addText("\n"); message_window.addText(recovery_message_line_2); message_window.addText("\n"); message_window.pack(); message_window.show(); return; } } class VCRButton { // // On-off button // Click to turn on // public int left; public int top; public int width; public int height; public String label; public Color button_color, back_color, shadow_color; public VCRButton(int left, int top, int width, int height, Color button_color, Color back_color, Color shadow_color, String label) { this.left = left; this.top = top; this.width = width; this.height = height; this.button_color = button_color; this.back_color = back_color; this.shadow_color = shadow_color; this.label = label; } public void draw_on(Graphics g) { g.setColor(back_color); g.fillRect(left, top, width, height); g.setColor(button_color); g.fillRect(left + 3, top + 3, width - 3, height - 3); g.setColor(shadow_color); g.drawString(label, left + width/2 - g.getFontMetrics().stringWidth(label)/2, top + height + height/2 + 4); } public void draw_off(Graphics g) { g.setColor(back_color); g.fillRect(left, top, width, height); g.setColor(shadow_color); g.fillRect(left + 3, top + 3, width - 3, height - 3); g.setColor(button_color); g.fillRect(left, top, width - 3, height - 3); g.setColor(shadow_color); g.drawString(label, left + width/2 - g.getFontMetrics().stringWidth(label)/2, top + height + height/2 + 4); } public boolean test(int mx, int my) { if ((mx >= left) & (mx <= left + width) & (my >= top) & (my <= top + height)) return true; else return false; } } class LeftArrow { public int point_x; public int point_y; public int width; public LeftArrow(int point_x, int point_y, int width) { this.point_x = point_x; this.point_y = point_y; this.width = width; } public void draw(Graphics g) { for (int i = 0; i <= width; i = i + 1) g.drawLine(point_x + i, point_y + i, point_x + i, point_y - i); } public boolean test(int mx, int my) { if ((point_x <= mx) & (mx <= point_x + width) & (point_y - width <= my) & (my <= point_y + width)) return true; else return false; } } class RightArrow { public int point_x; public int point_y; public int width; public RightArrow(int point_x, int point_y, int width) { this.point_x = point_x; this.point_y = point_y; this.width = width; } public void draw(Graphics g) { for (int i = 0; i <= width; i = i + 1) g.drawLine(point_x - i, point_y + i, point_x - i, point_y - i); } public boolean test(int mx, int my) { if ((point_x - width <= mx) & (mx <= point_x) & (point_y - width <= my) & (my <= point_y + width)) return true; else return false; } } class UpArrow { public int point_x; public int point_y; public int width; public UpArrow(int point_x, int point_y, int width) { this.point_x = point_x; this.point_y = point_y; this.width = width; } public void draw(Graphics g) { for (int i = 0; i <= width; i = i + 1) g.drawLine(point_x + i, point_y + i, point_x - i, point_y + i); } public boolean test(int mx, int my) { if ((point_x - width <= mx) & (mx <= point_x + width) & (point_y <= my) & (my <= point_y + width)) return true; else return false; } } class DownArrow { public int point_x; public int point_y; public int width; public DownArrow(int point_x, int point_y, int width) { this.point_x = point_x; this.point_y = point_y; this.width = width; } public void draw(Graphics g) { for (int i = 0; i <= width; i = i + 1) g.drawLine(point_x + i, point_y - i, point_x - i, point_y - i); } public boolean test(int mx, int my) { if ((point_x - width <= mx) & (mx <= point_x + width) & (point_y - width <= my) & (my <= point_y)) return true; else return false; } } // // The following is used to display information in a form that // can be imported into another program by cut-and-paste // class DataDisplayFrame extends Frame { final static Font textfont = new Font("Courier", Font.PLAIN, 12); TextArea txt = new TextArea(); public DataDisplayFrame (String title) { super(title); txt.setEditable(true); txt.setFont(textfont); add(txt); } public void addText(String text) { txt.setText(txt.getText() + text); } public void clearText() { txt.setText(""); } public boolean handleEvent(Event evt) { if (evt.id == Event.WINDOW_DESTROY) dispose(); return super.handleEvent(evt); } } // // The following was written by Darius Bacon // abstract class Expr { /** @return the value given the current variable values */ public abstract double value(); /** Binary operator: addition */ public static final int ADD = 0; /** Binary operator: subtraction */ public static final int SUB = 1; /** Binary operator: multiplication */ public static final int MUL = 2; /** Binary operator: division */ public static final int DIV = 3; /** Binary operator: exponentiation */ public static final int POW = 4; /** Binary operator: arctangent */ public static final int ATAN2 = 5; /** Binary operator: maximum */ public static final int MAX = 6; /** Binary operator: minimum */ public static final int MIN = 7; /** Binary operator: less than */ public static final int LT = 8; /** Binary operator: less or equal */ public static final int LE = 9; /** Binary operator: equality */ public static final int EQ = 10; /** Binary operator: inequality */ public static final int NE = 11; /** Binary operator: greater or equal*/ public static final int GE = 12; /** Binary operator: greater than */ public static final int GT = 13; /** Binary operator: logical and */ public static final int AND = 14; /** Binary operator: logical or */ public static final int OR = 15; /** Unary operator: absolute value*/ public static final int ABS = 100; /** Unary operator: arccosine */ public static final int ACOS = 101; /** Unary operator: arcsine */ public static final int ASIN = 102; /** Unary operator: arctangent*/ public static final int ATAN = 103; /** Unary operator: ceiling */ public static final int CEIL = 104; /** Unary operator: cosine */ public static final int COS = 105; /** Unary operator: e to the x*/ public static final int EXP = 106; /** Unary operator: floor */ public static final int FLOOR = 107; /** Unary operator: natural log*/ public static final int LOG = 108; /** Unary operator: negation */ public static final int NEG = 109; /** Unary operator: rounding */ public static final int ROUND = 110; /** Unary operator: sine */ public static final int SIN = 111; /** Unary operator: square root */ public static final int SQRT = 112; /** Unary operator: tangent */ public static final int TAN = 113; /** Make a literal expression. * @param v the constant value of the expression * @return an expression whose value is always v */ public static Expr makeLiteral(double v) { return new LiteralExpr(v); } /** Make an expression that applies a unary operator to an operand. * @param rator a code for a unary operator * @param rand operand * @return an expression meaning rator(rand) */ public static Expr makeApp1(int rator, Expr rand) { Expr app = new UnaryExpr(rator, rand); return rand instanceof LiteralExpr ? new LiteralExpr(app.value()) : app; } /** Make an expression that applies a binary operator to two operands. * @param rator a code for a binary operator * @param rand0 left operand * @param rand1 right operand * @return an expression meaning rator(rand0, rand1) */ public static Expr makeApp2(int rator, Expr rand0, Expr rand1) { Expr app = new BinaryExpr(rator, rand0, rand1); return rand0 instanceof LiteralExpr && rand1 instanceof LiteralExpr ? new LiteralExpr(app.value()) : app; } /** Make a conditional expression. * @param test `if' part * @param consequent `then' part * @param alternative `else' part * @return an expression meaning `if test, then consequent, else * alternative' */ public static Expr makeIfThenElse(Expr test, Expr consequent, Expr alternative) { Expr cond = new ConditionalExpr(test, consequent, alternative); if (test instanceof LiteralExpr && consequent instanceof LiteralExpr && alternative instanceof LiteralExpr) return new LiteralExpr(cond.value()); else return cond; } } // These classes are all private to this module so that I can get rid // of them later. For applets you want to use as few classes as // possible to avoid http connections at load time; it'd be profitable // to replace all these subtypes with bytecodes for a stack machine, // or perhaps a type that's the union of all of them (see class Node // in java/demo/SpreadSheet/SpreadSheet.java). class LiteralExpr extends Expr { double v; LiteralExpr(double v) { this.v = v; } public double value() { return v; } } class UnaryExpr extends Expr { int rator; Expr rand; UnaryExpr(int rator, Expr rand) { this.rator = rator; this.rand = rand; } public double value() { double arg = rand.value(); switch (rator) { case ABS: return Math.abs(arg); case ACOS: return Math.acos(arg); case ASIN: return Math.asin(arg); case ATAN: return Math.atan(arg); case CEIL: return Math.ceil(arg); case COS: return Math.cos(arg); case EXP: return Math.exp(arg); case FLOOR: return Math.floor(arg); case LOG: return Math.log(arg); case NEG: return -arg; case ROUND: return Math.round(arg); case SIN: return Math.sin(arg); case SQRT: return Math.sqrt(arg); case TAN: return Math.tan(arg); default: throw new RuntimeException("BUG: bad rator"); } } } class BinaryExpr extends Expr { int rator; Expr rand0, rand1; BinaryExpr(int rator, Expr rand0, Expr rand1) { this.rator = rator; this.rand0 = rand0; this.rand1 = rand1; } public double value() { double arg0 = rand0.value(); double arg1 = rand1.value(); switch (rator) { case ADD: return arg0 + arg1; case SUB: return arg0 - arg1; case MUL: return arg0 * arg1; case DIV: return arg0 / arg1; // division by 0 has IEEE 754 behavior case POW: return Math.pow(arg0, arg1); case ATAN2: return Math.atan2(arg0, arg1); case MAX: return arg0 < arg1 ? arg1 : arg0; case MIN: return arg0 < arg1 ? arg0 : arg1; case LT: return arg0 < arg1 ? 1.0 : 0.0; case LE: return arg0 <= arg1 ? 1.0 : 0.0; case EQ: return arg0 == arg1 ? 1.0 : 0.0; case NE: return arg0 != arg1 ? 1.0 : 0.0; case GE: return arg0 >= arg1 ? 1.0 : 0.0; case GT: return arg0 > arg1 ? 1.0 : 0.0; case AND: return arg0 != 0 && arg1 != 0 ? 1.0 : 0.0; case OR: return arg0 != 0 || arg1 != 0 ? 1.0 : 0.0; default: throw new RuntimeException("BUG: bad rator"); } } } class ConditionalExpr extends Expr { Expr test, consequent, alternative; ConditionalExpr(Expr test, Expr consequent, Expr alternative) { this.test = test; this.consequent = consequent; this.alternative = alternative; } public double value() { return test.value() != 0 ? consequent.value() : alternative.value(); } } // Operator-precedence parser. // Copyright 1996 by Darius Bacon; see the file COPYING. /** Parses strings representing mathematical formulas with variables. The following operators, in descending order of precedence, are defined:
These functions are defined: abs, acos, asin, atan, ceil, cos, exp, floor, log, round, sin, sqrt, tan. Each requires one argument enclosed in parentheses.
There are also binary functions: atan2, min, max; and a ternary conditional function: if(test, then, else).
Whitespace outside identifiers is ignored.
Examples: