// // Image_and_Cursor.java // // Written by Frank Wattenberg // // Version 0.40 // 15 May 2002 // // Added getColor // // Uses a parser written by Darius Bacon and obtained from Joe Yanik and Chuck Pheatt // // Known problems // // Lines drawn with a slope of -1 seem to be off by one pixel. // 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 Image_and_Cursor extends Applet { int check_out_sw = 1; // 0 = omit console messages; 1 = write console messages int margin_x, margin_y; // Left and right margins (pixels) int mid_x, mid_y; // Location of cursor control points int cursor_size; // Size of cursor int cursor_pad_sw; // 0 = cursors at edges, 1 = cursor pad int cursor_pad_x, cursor_pad_y; // Center of cursor pad if pad Color controls_color; // Color for cursor controls Color cursor_color; Color back_color; // Background color Color button_color; Color shadow_color; // Button shadow color Color list_color; // List button color Color list_shadow_color; // List button shadow color Color mark_color; // Color for mark symbols int mark_sw; // 0 = no marks, 1 = squares, 2 = filled squares, // 3 = diamonds, 4 = filled diamonds int mark_radius; // Controls size (radius) of mark symbols int mark_connect; // 0 = do not connect marks by lines; 1 = do connect marks by lines Color clear_color; // Clear button color Color clear_shadow_color; // Clear button shadow color VCRButton record_button; // Press this button to record one point VCRButton list_button; // Press this button to list recorded data VCRButton clear_button; // Press this button to clear recorded data int font_size; // Size of display font Font text_font; int display_placement; // 0 = underneath, 1 = at right int coordinates_left; // left edge of coordinate display int coordinates_top; // top of coordinate display int button_left; // left edge for buttons int button_top; // top for buttons int button_width; // width of buttons int button_height; // height of buttons int display_sw; // 0 = coordinates only, 1 = coordinates and three buttons, 2 = omit list button int record_sw = 0; // 0 = this point not yet recorded; 1 = this point recorded Graphics bG; // Screen buffer Image bI; int applet_width, applet_height; // Applet dimensions int image_width, image_height; // Image dimensions int cursor_x, cursor_y; // Cursor coordinates (pixels) Image backdrop; // backdrop image String backdrop_filename; int save_x[] = new int[1000]; // Save the x-ant y-coordinates of marked points int save_y[] = new int[1000]; String save_distance[] = new String[1000]; // Save the polar coordinates of marked points as String save_angle[] = new String[1000]; // formatted strings double angle, distance; int save_index = 0; DataDisplayFrame list_window; // Window for list of marked points DataDisplayFrame message_window; // Window for parser error messages. Expr x_of_t; // The expression for x(t) Expr y_of_t; // The expression for y(t) Expr y_of_x; // The expression for y(x) Expr r_of_theta; // The expression for r(theta) Expr curve_a_expression; // Expression for curve_a Expr curve_b_expression; // Expression for curve_b String recovery_message_line_1; // Recovery message printed for syntax errors String recovery_message_line_2; Variable t = Variable.make("t"); // independent variable for parametric curve Variable x = Variable.make("x"); // independent variable for y = f(x) curve Variable theta = Variable.make("theta"); // Independent variable for curve in polar coordinates 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"); int curve_n; // number of steps for parametric curve String curve_a_string; // expression for curve_a String curve_b_string; // expression for curve_b double curve_a; // left (t) end point for parametric curve double curve_b; // right (t) end point for parametric curve double curve_dt; // step size for parametric curve double curve_t; String curve_x_of_t; String curve_y_of_t; String curve_y_of_x; String curve_r_of_theta; int curve_sw; // 0 = no curve; 1 = y = f(x) curve; 2 = parametric curve; 3 = curve in polar coordinates int curve_thickness; // thickness is 2 * curve_thickness + 1 Color curve_color; int x_start, y_start, x_end, y_end; // used to draw curve int cas_sw; // 0 = Maple; 1 = Mathematica; 2 = MathCAD/Spreadsheet int polar_sw; // 0 = Cartesian; 1 = polar in radians; 2 = polar in degrees Color polar_color; int polar_origin_x, polar_origin_y; public String formatdouble(double arg, int width, int digits) { double work; int iwork; String swork; String blanks = " "; String zeros = "000000000000000000000000000000000000000000000"; work = arg; for(int i = 0; i < digits; i = i + 1) work = 10 * work; iwork = (int) java.lang.Math.round(work); swork = java.lang.Integer.toString(iwork); iwork = swork.length(); if (iwork < digits) { swork = zeros.substring(0, digits - iwork + 1) + swork; iwork = swork.length(); } swork = swork.substring(0, iwork - digits) + "." + swork.substring(iwork - digits, iwork); iwork = swork.length(); swork = blanks.substring(0, width - iwork) + swork; return swork; } 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 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 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); if (work.length() != 9) work = 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 void init() { check_out_sw = getInteger("check_out_sw", 0, 1, 0); if (check_out_sw == 1) { System.out.println("Starting Image_and_Cursor Applet."); System.out.println("Parameter messages to follow."); } else { System.out.println("Starting Color_Play 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."); } applet_width = getInteger("applet_width", 100, 2000, 100); // Get applet dimensions applet_height = getInteger("applet_height", 100, 2000, 100); bI = createImage(applet_width, applet_height); // Screen buffer bG = bI.getGraphics(); image_width = getInteger("image_width", 10, 2000, 10); // Get (backdrop) image dimensions image_height = getInteger("image_height", 10, 2000, 10); margin_x = getInteger("margin_x", 0, applet_width - image_width, (applet_width - image_width)/2); margin_y = getInteger("margin_y", 0, applet_height - image_height, (applet_height - image_height)/2); backdrop_filename = getString("backdrop_filename", "No file name parameter"); backdrop = getImage(getCodeBase(), backdrop_filename); // Backdrop image back_color = getColor("back_color", "255255255"); cursor_color = getColor("cursor_color", "000000000"); cursor_x = getInteger("cursor_x", 0, image_width - 1, image_width/2); cursor_y = image_height - 1 - getInteger("cursor_y", 0, image_height - 1, image_height/2); cursor_pad_sw = getInteger("cursor_pad_sw", 0, 1, 0); cursor_pad_x = getInteger("cursor_pad_x", 0, applet_width, margin_x + image_width + 150); cursor_pad_y = getInteger("cursor_pad_y", 0, applet_height, margin_y + image_height/2); controls_color = getColor("controls_color", "000000000"); mid_x = margin_x + image_width/2; mid_y = margin_y + image_height/2; cursor_size = getInteger("cursor_size", 5, 40, 10); font_size = getInteger("font_size", 8, 48, 12); // Set font for display text_font = new Font("Courier", Font.BOLD, font_size); bG.setFont(text_font); display_placement = getInteger("display_placement", 0, 1, 0); // Display placement if (display_placement == 0) { // Set up for display underneath image // coordinates_left = getInteger("coordinates_left", 0, applet_width, margin_x); button_left = getInteger("button_left", 0, applet_width, margin_x + image_width/2); coordinates_top = getInteger("coordinates_top", margin_y + image_height + 5, applet_height, margin_y + image_height + cursor_size + 15); button_top = getInteger("button_top", margin_y + image_height + 5, applet_height, margin_y + image_height + cursor_size + 15); } else { // Set up for display to the right of the image // coordinates_left = getInteger("coordinates_left", 0, applet_width, margin_x + image_width + cursor_size + 15); button_left = getInteger("button_left", 0, applet_width, margin_x + image_width + cursor_size + 15); coordinates_top = getInteger("coordinates_top", 0, applet_height, margin_y); button_top = getInteger("button_top", 0, applet_height, margin_y + image_height/2); } display_sw = getInteger("display_sw", 0, 2, 1); button_color = getColor("button_color", "064064255"); button_width = getInteger("button_width", 10, 200, 80); button_height = getInteger("button_height", 10, 50, 20); shadow_color = getColor("shadow_color", "000000128"); record_button = new VCRButton(button_left, button_top, button_width, button_height, button_color, back_color, shadow_color, "Mark point"); list_color = getColor("list_color", "255064064"); list_shadow_color = getColor("list_shadow_color", "128000000"); list_button = new VCRButton(button_left, button_top + 2 * button_height, button_width, button_height, list_color, back_color, list_shadow_color, "List points"); clear_color = getColor("clear_color", "064064064"); clear_shadow_color = getColor("clear_shadow_color", "000000000"); clear_button = new VCRButton(button_left, button_top + 4 * button_height, button_width, button_height, clear_color, back_color, clear_shadow_color, "Clear points"); mark_color = getColor("mark_color", "000000000"); mark_sw = getInteger("mark_sw", 0, 4, 4); mark_radius = getInteger("mark_radius", 0, 10, 3); mark_connect = getInteger("mark_connect", 0, 1, 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", "Close this window and the previous window."); recovery_message_line_2 = getString("recovery_message_line_2", ""); curve_n = getInteger("curve_n", 10, 1000, 100); curve_x_of_t = getString("curve_x_of_t", "t"); curve_y_of_t = getString("curve_y_of_t", "t"); curve_y_of_x = getString("curve_y_of_x", "x"); curve_a_string = getString("curve_a", "0"); curve_b_string = getString("curve_b", "1"); curve_r_of_theta = getString("r_of_theta", "theta"); try { curve_a_expression = Parser.parse(curve_a_string); } catch (SyntaxException e) { tell_error("Syntax error: " + e + "\n" + e.explain()); return; } try { curve_b_expression = Parser.parse(curve_b_string); } catch (SyntaxException e) { tell_error("Syntax error: " + e + "\n" + e.explain()); return; } curve_a = curve_a_expression.value(); curve_b = curve_b_expression.value(); curve_dt = (curve_b - curve_a)/curve_n; curve_sw = getInteger("curve_sw", 0, 3, 0); curve_thickness = getInteger("curve_thickness", 0, 10, 1); try { x_of_t = Parser.parse(curve_x_of_t); } catch (SyntaxException e) { tell_error("Syntax error: " + e + "\n" + e.explain()); return; } try { y_of_t = Parser.parse(curve_y_of_t); } catch (SyntaxException e) { tell_error("Syntax error: " + e + "\n" + e.explain()); return; } try { y_of_x = Parser.parse(curve_y_of_x); } catch (SyntaxException e) { tell_error("Syntax error: " + e + "\n" + e.explain()); return; } try { r_of_theta = Parser.parse(curve_r_of_theta); } catch (SyntaxException e) { tell_error("Syntax error: " + e + "\n" + e.explain()); return; } curve_color = getColor("curve_color", "000000000"); cas_sw = getInteger("cas_sw", 0, 2, 2); polar_sw = getInteger("polar_sw", 0, 2, 0); if (polar_sw > 0) { polar_color = getColor("polar_color", "255255255"); polar_origin_x = getInteger("polar_origin_x", 0, image_width - 1, image_width/2); polar_origin_y = getInteger("polar_origin_y", 0, image_height - 1, image_height/2); } } public void paint(Graphics g) { super.paint(g); drawcursors(); g.drawImage(bI, 0, 0, this); } public void update(Graphics g) { paint(g); } public void drawcursors() { int work, work_x, work_y; int center_x, center_y; int real_y; String angle_string; bG.setColor(back_color); bG.fillRect(0, 0, applet_width, applet_height); bG.drawImage(backdrop, margin_x, margin_y, this); if (polar_sw > 0) { // Draw polar grid bG.setColor(polar_color); // Compute center for diagonal polar grid lines center_x = margin_x + polar_origin_x; center_y = margin_y + image_height - 1 - polar_origin_y; // Draw horizontal and vertical polar grid lines bG.drawLine(margin_x, center_y, margin_x + image_width - 1, center_y); bG.drawLine(center_x, margin_y, center_x, margin_y + image_height - 1); // Draw 45 degree polar grid line work = java.lang.Math.min(image_width - 1 - polar_origin_x, polar_origin_y) + 1; bG.drawLine(center_x, center_y, center_x + work, center_y + work); // Draw -45 degree polar grid line work = java.lang.Math.min(image_width - polar_origin_x, image_height - polar_origin_y) + 1; bG.drawLine(center_x, center_y, center_x + work, center_y - work); // Draw 135 degree polar grid line work = java.lang.Math.min(polar_origin_x, polar_origin_y) + 1; bG.drawLine(center_x, center_y, center_x - work, center_y + work); // Draw -135 degree polar grid line work = java.lang.Math.min(polar_origin_x, image_height - 1 - polar_origin_y); bG.drawLine(center_x, center_y, center_x - work, center_y - work); } // Draw control buttons if (record_sw == 0) { if (display_sw > 0) { record_button.draw_off(bG); if (save_index > 0) { clear_button.draw_off(bG); if (display_sw == 1) list_button.draw_off(bG); } else { clear_button.draw_on(bG); if (display_sw == 1) list_button.draw_on(bG); } } } else { if (display_sw > 0) { record_button.draw_on(bG); if (display_sw == 1) list_button.draw_off(bG); if (save_index > 0) { clear_button.draw_off(bG); } else { clear_button.draw_on(bG); } } } // Draw marks at recorded points if (mark_sw > 0) { bG.setColor(mark_color); for (int i = 0; i < save_index; i = i + 1) { work_x = margin_x + save_x[i]; // x- and y-coordinates of marked point work_y = margin_y + image_height - save_y[i] - 1; if (mark_sw == 1) // Mark by open box { bG.drawLine(work_x - mark_radius, work_y + mark_radius, work_x + mark_radius, work_y + mark_radius); bG.drawLine(work_x - mark_radius, work_y - mark_radius, work_x + mark_radius, work_y - mark_radius); bG.drawLine(work_x - mark_radius, work_y - mark_radius, work_x - mark_radius, work_y + mark_radius); bG.drawLine(work_x + mark_radius, work_y - mark_radius, work_x + mark_radius, work_y + mark_radius); } if (mark_sw == 2) // Mark by solid box { for (int j = -mark_radius; j <= mark_radius; j = j + 1) bG.drawLine(work_x - mark_radius, work_y + j, work_x + mark_radius, work_y + j); } if (mark_sw == 3) // Mark by open diamond { bG.drawLine(work_x - mark_radius, work_y, work_x, work_y + mark_radius); bG.drawLine(work_x, work_y + mark_radius, work_x + mark_radius, work_y); bG.drawLine(work_x + mark_radius, work_y, work_x, work_y - mark_radius); bG.drawLine(work_x, work_y - mark_radius, work_x - mark_radius, work_y); } if (mark_sw == 4) // Mark by solid diamond (default) { for (int j = 0; j <= mark_radius; j = j + 1) { bG.drawLine(work_x - mark_radius + j, work_y + j, work_x + mark_radius - j, work_y + j); bG.drawLine(work_x - mark_radius + j, work_y - j, work_x + mark_radius - j, work_y - j); } } } } // Draw lines connecting marked points if ((mark_sw > 0) & (mark_connect == 1)) { bG.setColor(mark_color); x_start = margin_x + save_x[0]; y_start = margin_y + image_height - save_y[0] - 1; for (int i = 1; i < save_index; i = i + 1) { work_x = margin_x + save_x[i]; work_y = margin_y + image_height - save_y[i] - 1; bG.drawLine(x_start, y_start, work_x, work_y); x_start = work_x; y_start = work_y; } } if (curve_sw == 1) // Draw curve specified as y(x) { curve_t = curve_a; x.set_value(curve_a); bG.setColor(curve_color); x_start = (int) java.lang.Math.round(curve_a); y_start = (int) java.lang.Math.round(y_of_x.value()); for (int i = 1; i <= curve_n; i = i + 1) { curve_t = curve_t + curve_dt; x.set_value(curve_t); x_end = (int) java.lang.Math.round(curve_t); y_end = (int) java.lang.Math.round(y_of_x.value()); for (int j = -curve_thickness; j <= curve_thickness; j = j + 1) { for (int k = -curve_thickness; k <= curve_thickness; k = k + 1) { bG.drawLine(margin_x + x_start + j, margin_y + image_height - 1 - y_start + k, margin_x + x_end + j, margin_y + image_height - 1 - y_end + k); } } x_start = x_end; y_start = y_end; } } if (curve_sw == 2) // Draw curve specified as x(t), y(t) { curve_t = curve_a; t.set_value(curve_a); bG.setColor(curve_color); x_start = (int) java.lang.Math.round(x_of_t.value()); y_start = (int) java.lang.Math.round(y_of_t.value()); for (int i = 1; i <= curve_n; i = i + 1) { curve_t = curve_t + curve_dt; t.set_value(curve_t); x_end = (int) java.lang.Math.round(x_of_t.value()); y_end = (int) java.lang.Math.round(y_of_t.value()); for (int j = -curve_thickness; j <= curve_thickness; j = j + 1) { for (int k = -curve_thickness; k <= curve_thickness; k = k + 1) { bG.drawLine(margin_x + x_start + j, margin_y + image_height - 1 - y_start + k, margin_x + x_end + j, margin_y + image_height - 1 - y_end + k); } } x_start = x_end; y_start = y_end; } } if ((curve_sw == 3) & (polar_sw > 0)) { center_x = margin_x + polar_origin_x; center_y = margin_y + image_height - 1 - polar_origin_y; curve_t = curve_a; t.set_value(curve_t); theta.set_value(curve_t); bG.setColor(curve_color); x_start = (int) java.lang.Math.round( center_x + java.lang.Math.cos(curve_t) * r_of_theta.value()); y_start = (int) java.lang.Math.round( center_y - java.lang.Math.sin(curve_t) * r_of_theta.value()); for (int i = 1; i <= curve_n; i = i + 1) { curve_t = curve_t + curve_dt; t.set_value(curve_t); theta.set_value(curve_t); x_end = (int) java.lang.Math.round( center_x + java.lang.Math.cos(curve_t) * r_of_theta.value()); y_end = (int) java.lang.Math.round( center_y - java.lang.Math.sin(curve_t) * r_of_theta.value()); for (int j = -curve_thickness; j <= curve_thickness; j = j + 1) { for (int k = -curve_thickness; k <= curve_thickness; k = k + 1) bG.drawLine(x_start + j, y_start + k, x_end + j, y_end + k); } x_start = x_end; y_start = y_end; } } // Draw cursors bG.setColor(cursor_color); bG.drawLine(margin_x + cursor_x, margin_y, margin_x + cursor_x, margin_y + image_height - 1); bG.drawLine(margin_x, margin_y + cursor_y, margin_x + image_width - 1, margin_y + cursor_y); // Draw controls to move cursor one pixel at a time bG.setColor(controls_color); for (int i = 0; i <= cursor_size; i = i + 1) { if (cursor_pad_sw == 0) { bG.drawLine(mid_x - i, margin_y - 10 - cursor_size + i, mid_x + i, margin_y - 10 - cursor_size + i); bG.drawLine(mid_x - i, margin_y + 10 + image_height + cursor_size - i, mid_x + i, margin_y + 10 + image_height + cursor_size - i); bG.drawLine(margin_x - 10 - cursor_size + i, mid_y - i, margin_x - 10 - cursor_size + i, mid_y + i); bG.drawLine(margin_x + image_width + 10 + cursor_size - i, mid_y - i, margin_x + image_width + 10 + cursor_size - i, mid_y + i); } else { bG.drawLine(cursor_pad_x - i, 5 + cursor_pad_y + 10 + cursor_size - i, cursor_pad_x + i, 5 + cursor_pad_y + 10 + cursor_size - i); bG.drawLine(cursor_pad_x - i, cursor_pad_y - 10 - cursor_size + i - 5, cursor_pad_x + i, cursor_pad_y - 10 - cursor_size + i - 5); bG.drawLine(5 + cursor_pad_x + 10 + cursor_size - i, cursor_pad_y - i, 5 + cursor_pad_x + 10 + cursor_size - i, cursor_pad_y + i); bG.drawLine(cursor_pad_x - 10 - cursor_size + i - 5, cursor_pad_y - i, cursor_pad_x - 10 - cursor_size + i - 5, cursor_pad_y + i); } } // Print cursor coordinates bG.drawString("x: " + String.valueOf(cursor_x), coordinates_left, coordinates_top + font_size); bG.drawString("y: " + String.valueOf(image_height - cursor_y - 1), coordinates_left, coordinates_top + 2 * font_size + 5); if (polar_sw > 0) { real_y = image_height - cursor_y - 1; distance = java.lang.Math.sqrt((cursor_x - polar_origin_x) * (cursor_x - polar_origin_x) + (real_y - polar_origin_y) * (real_y - polar_origin_y)); bG.drawString("r: " + formatdouble(distance, 7, 2), coordinates_left, coordinates_top + 3 * font_size + 10); if (cursor_x == polar_origin_x) { if (polar_sw == 1) { if (real_y >= polar_origin_y) angle_string = " 1.5708"; else angle_string = " 4.7124"; if (real_y == polar_origin_y) angle_string = " undefined"; } else { if (real_y >= polar_origin_y) angle_string = " 90.00"; else angle_string = " 270.00"; if (real_y == polar_origin_y) angle_string = " undefined"; } } else { angle = java.lang.Math.atan(1.0 * (real_y - polar_origin_y)/(cursor_x - polar_origin_x)); if (cursor_x < polar_origin_x) angle = Math.PI + angle; if (angle < 0) angle = angle + 2 * Math.PI; if (polar_sw == 2) { angle = angle * 360 / (2 * Math.PI); angle_string = formatdouble(angle, 10, 2); } else angle_string = formatdouble(angle, 7, 4); } bG.drawString("theta: " + angle_string, coordinates_left, coordinates_top + 4 * font_size + 15); } } public boolean mouseDown(Event evt, int mx, int my) { int x_start, y_start, x_end, y_end; int real_y; double work; if ((mx >= margin_x) & (mx <= margin_x + image_width - 1) & (my >= margin_y) & (my <= margin_y + image_height - 1)) { cursor_x = mx - margin_x; cursor_y = my - margin_y; record_sw = 0; repaint(); return true; } if (cursor_pad_sw == 0) { if ((mx >= margin_x - 10 - cursor_size) & (mx <= margin_x - 10) & (my >= mid_y - cursor_size) & (my <= mid_y + cursor_size)) { cursor_x = java.lang.Math.max(0, cursor_x - 1); record_sw = 0; repaint(); return true; } if ((mx >= margin_x + image_width + 10) & (mx <= margin_x + image_width + 10 + cursor_size) & (my >= mid_y - cursor_size) & (my <= mid_y + cursor_size)) { cursor_x= java.lang.Math.min(image_width - 1, cursor_x + 1); record_sw = 0; repaint(); return true; } if ((mx >= mid_x - cursor_size) & (mx <= mid_x + cursor_size) & (my >= margin_y - 10 - cursor_size) & (my <= margin_y - 10)) { cursor_y = java.lang.Math.max(0, cursor_y - 1); record_sw = 0; repaint(); return true; } if ((mx >= mid_x - cursor_size) & (mx <= mid_x + cursor_size) & (my >= margin_y + image_height + 10) & (my <= margin_y + image_height + 10 + cursor_size)) { cursor_y = java.lang.Math.min(image_height - 1, cursor_y + 1); record_sw = 0; repaint(); return true; } } else { if ((mx >= cursor_pad_x - 5 - 2 * cursor_size) & (mx <= cursor_pad_x - 5 - cursor_size) & (my >= cursor_pad_y - cursor_size - 5) & (my <= cursor_pad_y + cursor_size + 5)) { cursor_x = java.lang.Math.max(0, cursor_x - 1); record_sw = 0; repaint(); return true; } if ((mx >= cursor_pad_x + 5 + cursor_size) & (mx <= cursor_pad_x + 5 + 2 * cursor_size) & (my >= cursor_pad_y - cursor_size - 5) & (my <= cursor_pad_y + cursor_size + 5)) { cursor_x= java.lang.Math.min(image_width - 1, cursor_x + 1); record_sw = 0; repaint(); return true; } if ((mx >= cursor_pad_x - 5 - cursor_size) & (mx <= cursor_pad_x + 5 + cursor_size) & (my >= cursor_pad_y - 5 - 2 * cursor_size) & (my <= cursor_pad_y - 5 - cursor_size)) { cursor_y = java.lang.Math.max(0, cursor_y - 1); record_sw = 0; repaint(); return true; } if ((mx >= cursor_pad_x - 5 - cursor_size) & (mx <= cursor_pad_x + 5 + cursor_size) & (my >= cursor_pad_y + 5 + cursor_size) & (my <= cursor_pad_y + 5 + 2 * cursor_size)) { cursor_y = java.lang.Math.min(image_height - 1, cursor_y + 1); record_sw = 0; repaint(); return true; } } if (record_button.test(mx, my)) { if (record_sw == 0) { if (save_index == 1000) save_index = 0; real_y = image_height - cursor_y - 1; save_x[save_index] = cursor_x; save_y[save_index] = real_y; distance = java.lang.Math.sqrt((cursor_x - polar_origin_x) * (cursor_x - polar_origin_x) + (real_y - polar_origin_y) * (real_y - polar_origin_y)); save_distance[save_index] = formatdouble(distance, 10, 2); if (cursor_x == polar_origin_x) { if (polar_sw == 1) { if (real_y >= polar_origin_y) save_angle[save_index] = " 1.5708"; else save_angle[save_index] = " 4.7124"; if (real_y == polar_origin_y) save_angle[save_index] = " undefined"; } else { if (real_y >= polar_origin_y) save_angle[save_index] = " 90.00"; else save_angle[save_index] = " 270.00"; if (real_y == polar_origin_y) save_angle[save_index] = " undefined"; } } else { angle = java.lang.Math.atan(1.0 * (real_y - polar_origin_y)/(cursor_x - polar_origin_x)); if (cursor_x < polar_origin_x) angle = Math.PI + angle; if (angle < 0) angle = angle + 2 * Math.PI; if (polar_sw == 2) { angle = angle * 360 / (2 * Math.PI); save_angle[save_index] = formatdouble(angle, 10, 2); } else save_angle[save_index] = formatdouble(angle, 10, 4); } save_index = save_index + 1; record_sw = 1; repaint(); return true; } } if (clear_button.test(mx, my)) { save_index = 0; record_sw = 0; repaint(); return true; } if (list_button.test(mx, my) & (display_sw == 1)) { list_window = new DataDisplayFrame("List of marked points"); list_window.hide(); list_window.clearText(); list_window.addText("MacOS: Highlight the information to be copied in this window.\n"); list_window.addText("Then copy it by pressing command-c. Next click in the area\n"); list_window.addText("into which it is to be pasted and press command-v.\n\n"); list_window.addText("Windows: Highlight the information to be copied in this window.\n"); list_window.addText("Then copy it by pressing control-c. Next click in the area\n"); list_window.addText("into which it is to be pasted and press control-v.\n\n"); if (cas_sw == 0) // Format for Maple { list_window.addText("n := "); list_window.addText(String.valueOf(save_index)); list_window.addText(";\n\n"); list_window.addText("x := ["); for (int i = 0; i < save_index; i = i + 1) { list_window.addText(String.valueOf(save_x[i])); if (i < save_index - 1) { list_window.addText(", "); if (i == 10 * (i/ 10) + 9) list_window.addText("\n "); } } list_window.addText("];\n\n"); list_window.addText("y := ["); for (int i = 0; i < save_index; i = i + 1) { list_window.addText(String.valueOf(save_y[i])); if (i < save_index - 1) { list_window.addText(", "); if (i == 10 * (i/ 10) + 9) list_window.addText("\n "); } } list_window.addText("];\n\n"); if (polar_sw > 0) { list_window.addText("r := ["); for (int i = 0; i < save_index; i = i + 1) { list_window.addText(save_distance[i]); if (i < save_index - 1) { list_window.addText(", "); if (i == 10 * (i/10) + 9) list_window.addText("\n "); } } list_window.addText("];\n\n"); list_window.addText("t := ["); for (int i = 0; i < save_index; i = i + 1) { list_window.addText(save_angle[i]); if (i < save_index - 1) { list_window.addText(", "); if (i == 10 * (i/10) + 9) list_window.addText("\n "); } } list_window.addText("];\n\n"); } } else if (cas_sw == 1) // Format for Mathematica { list_window.addText("n := "); list_window.addText(String.valueOf(save_index)); list_window.addText("\n\n"); list_window.addText("x := {"); for (int i = 0; i < save_index; i = i + 1) { list_window.addText(String.valueOf(save_x[i])); if (i < save_index - 1) { list_window.addText(", "); if (i == 10 * (i/ 10) + 9) list_window.addText("\n "); } } list_window.addText("}\n\n"); list_window.addText("y := {"); for (int i = 0; i < save_index; i = i + 1) { list_window.addText(String.valueOf(save_y[i])); if (i < save_index - 1) { list_window.addText(", "); if (i == 10 * (i/ 10) + 9) list_window.addText("\n "); } } list_window.addText("}\n\n"); if (polar_sw > 0) { list_window.addText("r := {"); for (int i = 0; i < save_index; i = i + 1) { list_window.addText(save_distance[i]); if (i < save_index - 1) { list_window.addText(", "); if (i == 10 * (i/10) + 9) list_window.addText("\n "); } } list_window.addText("}\n\n"); list_window.addText("t := {"); for (int i = 0; i < save_index; i = i + 1) { list_window.addText(save_angle[i]); if (i < save_index - 1) { list_window.addText(", "); if (i == 10 * (i/10) + 9) list_window.addText("\n "); } } list_window.addText("}\n\n"); } } if (cas_sw == 2) // Format for Excel { if (polar_sw == 0) list_window.addText("x-coordinate \t y-coordinate\n\n"); if (polar_sw == 1) list_window.addText("x-coordinate \t y-coordinate \t distance \t angle (radians)\n\n"); if (polar_sw == 2) list_window.addText("x-coordinate \t y-coordinate \t distance \t angle (degrees)\n\n"); for (int i = 0; i < save_index; i = i + 1) { list_window.addText(leftfill(6, String.valueOf(save_x[i]))); list_window.addText("\t "); list_window.addText(leftfill(6, String.valueOf(save_y[i]))); if (polar_sw > 0) list_window.addText("\t" + save_distance[i] + "\t" + save_angle[i]); list_window.addText("\n"); } } list_window.pack(); list_window.show(); } return true; } 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; } // // Used to right justify output // public String leftfill(int n, String str) { int k; String body; body = str; k = body.length(); body = " "; body = body.substring(0, n - k) + str; return body; } } // // 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 were written by Frank Wattenberg // 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); } 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); } public boolean test(int mx, int my) { if ((mx >= left) & (mx <= left + width) & (my >= top) & (my <= top + height)) return true; else return false; } } // // 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: