import java.util.*; import java.awt.*; import java.applet.Applet; class GraphSysGraphics { boolean is_offscreen; Panel ownerpanel; Dimension offscreensize; Graphics offgraphics; Image offscreen; int ixmin; int ixmax; int iymin; int iymax; int ixpos; int iypos; double xmin; double xmax; double ymin; double ymax; double xpos; double ypos; final Color nodeColor = new Color(250, 220, 100); final Color backColor = Color.white; final Color errColor = Color.gray; final Color functionColor = Color.blue; final Color axesColor = Color.black; final Color pathColor = Color.red; final Color lastColor = new Color(0, 128, 0); final Color llastColor = new Color(0, 0, 250); final Color llineColor = new Color(0, 250, 250); final Color lbackColor = new Color(40, 40, 40); GraphSysGraphics(Panel ownerpanel_) { this.is_offscreen = false; this.ownerpanel = ownerpanel_; } public void setScale(double xmin_,double ymin_,double xmax_,double ymax_) { xmin = xmin_; xmax = xmax_; ymin = ymin_; ymax = ymax_; } public void setColor(int paletteIndex_) { if (paletteIndex_ == -1) offgraphics.setColor(ownerpanel.getBackground()); else if (paletteIndex_ == 0) offgraphics.setColor(backColor); else if (paletteIndex_ == 1) offgraphics.setColor(functionColor); else if (paletteIndex_ == 2) offgraphics.setColor(axesColor); else if (paletteIndex_ == 3) offgraphics.setColor(pathColor); else if (paletteIndex_ == 4) offgraphics.setColor(lastColor); else if (paletteIndex_ == 11) offgraphics.setColor(lbackColor); else if (paletteIndex_ == 12) offgraphics.setColor(llastColor); else if (paletteIndex_ == 13) offgraphics.setColor(llineColor); else offgraphics.setColor(errColor); } public int X2IX(double x_) { double xx = (x_ - xmin) / ( xmax - xmin ) * ( ixmax - ixmin ) + ixmin; return (int) xx; } public int Y2IY(double y_) { double yy = (y_ - ymin) / ( ymax - ymin ) * ( iymax - iymin ) + iymin; return (int) yy; } public double IX2X(int ix_) { double xx = ((double)(ix_ - ixmin)) / ((double)( ixmax - ixmin )) * ( xmax - xmin ) + xmin; return xx; } public double IY2Y(int iy_) { double yy = ((double)(iy_ - iymin)) / ((double)( iymax - iymin )) * ( ymax - ymin ) + ymin; return yy; } public void moveTo(double x_,double y_) { xpos = x_; ypos = y_; ixpos = X2IX( x_ ); iypos = Y2IY( y_ ); } public void lineTo(double x_,double y_) { int new_ixpos = X2IX( x_ ); int new_iypos = Y2IY( y_ ); offgraphics.drawLine(ixpos,iypos,new_ixpos,new_iypos); ixpos = new_ixpos; iypos = new_iypos; xpos = x_; ypos = y_; } public void createDraw(Graphics g,int pal) { is_offscreen = true; Dimension d = ownerpanel.size(); offscreen = ownerpanel.createImage(d.width, d.height); offscreensize = d; offgraphics = offscreen.getGraphics(); ixmin = 0; iymin = d.height; ixmax = d.width; iymax = 0; ixpos = 0; iypos = 0; xpos = 0; ypos = 0; xmin = 0; xmax = 1; ymin = 0; ymax = 1; clearDraw(g,pal); } public void clearDraw(Graphics g,int pal) { xpos = 0; ypos = 0; ixpos = 0; iypos = 0; setColor(pal); Dimension d = ownerpanel.size(); offgraphics.fillRect(0, 0, d.width, d.height); } public void resetDraw(Graphics g,int pal) { clearDraw(g,pal); } public void openDraw(Graphics g,int pal) { if (!is_offscreen) { createDraw(g,pal); } } public void closeDraw(Graphics g) { g.drawImage(offscreen, 0, 0, null); } } class GraphLinePanel extends Panel { GraphSys graph; GraphSysGraphics gr; GraphSysPanel panel; int ix_last; int ix_curr; int iy_last; int iy_curr; boolean is_startpoint; boolean is_lastpoint; boolean is_reset; GraphLinePanel(GraphSys graph, GraphSysPanel panel) { this.graph = graph; this.panel = panel; this.gr = new GraphSysGraphics(this); this.is_reset = true; this.is_startpoint = false; this.is_lastpoint = false; } // public Dimension PreferredLayoutSize(Container parent) // { // return new Dimension(640,200); // }; // public Dimension MinimumLayoutSize(Container parent) // { // return new Dimension(100,200); // }; public void start() { // relaxer = new Thread(this); // relaxer.start(); } public void stop() { // relaxer.stop(); } public synchronized void resetAction() { this.is_reset = true; this.is_startpoint = false; this.is_lastpoint = false; } public synchronized void update(Graphics g) { gr.openDraw(g,11); drawLineGraph(g); gr.closeDraw(g); } public synchronized void setPoint(double x_) { if (panel.is_drawnfunction) { is_startpoint = true; ix_curr = gr.Y2IY(x_); } } public synchronized boolean mouseDown(Event evt, int ix_, int iy_) { if (panel.is_drawnfunction) { resetScaleGraph(); setPoint(gr.IY2Y(iy_)); repaint(); } return true; } public synchronized void drawLineSingleGraph(Graphics g,int ix, int pal) { double x = gr.IY2Y(ix); double y = x; gr.setColor(pal); gr.moveTo( 0., x ); for (int i = 0; i < panel.n_iters; i++ ) { y = panel.f(x,y,i); gr.lineTo((double)i,x); x = y; } } public synchronized void resetScaleGraph() { if (panel.is_use_yscale) { gr.setScale( 0., panel.y_min, (double)panel.n_iters, panel.y_max ); } else { gr.setScale( 0., panel.x_min, (double)panel.n_iters, panel.x_max ); }; } public synchronized void drawLineGraph(Graphics g) { if (is_reset) { is_reset = false; gr.resetDraw(g,11); resetScaleGraph(); } if (is_startpoint) { is_startpoint = false; if (is_lastpoint) { drawLineSingleGraph(g,ix_last,12); } drawLineSingleGraph(g,ix_curr,13); ix_last = ix_curr; is_lastpoint = true; } } synchronized void relax() { repaint(); } public void run() { // relax(); // while (true) // { // try // { // Thread.sleep(100); // } // catch (InterruptedException e) // { // break; // } // } } } class GraphSysPanel extends Panel implements Runnable { GraphSys graph; GraphSysGraphics gr; GraphLinePanel lpanel; Thread relaxer; int n_pts; int n_iters; int n_comp; int ix0_zoom; int iy0_zoom; int ix1_zoom; int iy1_zoom; int ix2_zoom; int iy2_zoom; int ix_last; int ix_curr; int iy_last; int iy_curr; int f_type; boolean is_autoscale; boolean is_use_yscale; boolean was_startpoint; boolean is_startpoint; boolean is_lastpoint; boolean is_reset; boolean is_drawnfunction; boolean is_singlemode; boolean is_zooming; boolean is_zoom_scale; boolean is_dragging; double x_min; double x_max; double y_min; double y_max; double x_corr; double y_corr; double x_add; double y_add; double y_alpha; GraphSysPanel(GraphSys graph) { this.graph = graph; this.gr = new GraphSysGraphics(this); this.n_pts = 50; this.n_iters = 20; this.n_comp = 1; this.is_reset = false; this.was_startpoint = false; this.is_startpoint = false; this.is_drawnfunction = false; this.is_use_yscale = false; this.is_autoscale = true; this.is_lastpoint = false; this.is_singlemode = true; this.is_zooming = false; this.is_zoom_scale = false; this.is_dragging = false; this.x_min = 0; this.x_max = 1; this.y_min = 0; this.y_max = 1; this.y_alpha = 1; this.x_corr = 1; this.y_corr = 1; this.x_add = 0; this.y_add = 0; this.f_type = 1; } public void run() { while (true) { relax(); try { Thread.sleep(100); } catch (InterruptedException e) { break; } } } synchronized void relax() { repaint(); } public synchronized void resetAction() { this.is_reset = true; this.was_startpoint = false; this.is_startpoint = false; this.is_lastpoint = false; this.is_drawnfunction = false; this.is_singlemode = true; this.is_zooming = false; this.is_dragging = false; lpanel.resetAction(); } public synchronized void drawFunction(Graphics g) { if (!is_drawnfunction && is_reset) { is_reset = false; is_drawnfunction = true; setFunctionRange(); gr.resetDraw(g,0); double dx = ( x_max - x_min ) / n_pts; gr.setScale( x_min, y_min, x_max, y_max ); gr.setColor(2); gr.moveTo( x_min, x_min ); gr.lineTo( x_max, x_max ); gr.setColor(1); gr.moveTo( x_min, f(x_min,x_min,0) ); double y = x_min; for (double x = x_min; x <= x_max + dx ; x = x + dx ) { y = f(x,y,0); gr.lineTo( x, y ); } } } public synchronized void setFunctionRange() { if (is_zoom_scale) { is_zoom_scale = false; } else if (is_autoscale) { double dx = ( x_max - x_min ) / n_pts; y_min = Math.min( x_min, x_max); y_max = Math.max( x_min, x_max); double y = x_min; for (double x = x_min; x <= x_max + dx; x = x + dx ) { y = f( x, y, 0); if (y < y_min) y_min = y; if (y > y_max) y_max = y; } graph.setDialogParms(); } } public synchronized void drawSinglePath(Graphics g,int ix, int pal) { double x = gr.IX2X(ix); double y = x; gr.setColor(pal); gr.moveTo( x, y_min ); for (int i = 0; i < n_iters; i++ ) { y = f(x,y,i); gr.lineTo(x,y); gr.lineTo(y,y); x = y; } } public synchronized void drawPointPath(Graphics g) { if (is_startpoint) { is_startpoint = false; if (is_lastpoint) { drawSinglePath(g,ix_last,4); } is_lastpoint = true; drawSinglePath(g,ix_curr,3); ix_last = ix_curr; } } public synchronized void update(Graphics g) { if (!is_dragging) { gr.openDraw(g,0); drawFunction(g); drawPointPath(g); if (is_singlemode) { lpanel.repaint(); } gr.closeDraw(g); } else { gr.openDraw(g,0); gr.closeDraw(g); { gr.setColor(2); int ix0 = Math.min(ix0_zoom,ix1_zoom); int iy0 = Math.min(iy0_zoom,iy1_zoom); int iw0 = Math.max(ix0_zoom,ix1_zoom) - ix0; int ih0 = Math.max(iy0_zoom,iy1_zoom) - iy0; g.drawRect(ix0,iy0,iw0,ih0); } } } public synchronized boolean mouseDown(Event evt, int ix_, int iy_) { if (is_zooming) { is_dragging = true; ix0_zoom = ix_; iy0_zoom = iy_; ix1_zoom = ix_; iy1_zoom = iy_; ix2_zoom = ix_; iy2_zoom = iy_; } else if (is_drawnfunction) { was_startpoint = true; is_startpoint = true; ix_curr = ix_; iy_curr = iy_; lpanel.setPoint(gr.IX2X(ix_)); repaint(); } return true; } public synchronized boolean mouseUp(Event evt, int ix_, int iy_) { if (is_zooming) { is_dragging = false; is_zooming = false; if (ix0_zoom > ix_) { ix1_zoom = ix0_zoom; ix0_zoom = ix_; } else { ix1_zoom = ix_; } if (iy0_zoom < iy_) { iy1_zoom = iy0_zoom; iy0_zoom = iy_; } else { iy1_zoom = iy_; } if ((ix1_zoom != ix0_zoom) && (iy1_zoom != iy0_zoom)) { x_min = gr.IX2X(ix0_zoom); x_max = gr.IX2X(ix1_zoom); y_min = gr.IY2Y(iy0_zoom); y_max = gr.IY2Y(iy1_zoom); is_zoom_scale = true; } else { is_zoom_scale = false; } graph.setDialogParms(); resetAction(); lpanel.repaint(); } return true; } public synchronized boolean mouseDrag(Event evt, int ix_, int iy_) { if (is_dragging) { ix2_zoom = ix1_zoom; iy2_zoom = iy1_zoom; ix1_zoom = ix_; iy1_zoom = iy_; repaint(); } return true; } public void start() { relaxer = new Thread(this); relaxer.start(); } public void stop() { relaxer.stop(); } public Choice getFunctionChoice() { Choice c = new Choice(); c.addItem("x(1-x)"); c.addItem("(1-x)"); c.addItem("16x^3-24x^2+9x"); c.addItem("-2x^3+3x^2-1/2x+1/4"); c.addItem("-2(x-1/2)^2+x"); c.addItem("1/(x+1)"); c.addItem("exp(-x)"); c.addItem("exp(-(5(x-1/2))^2)"); c.addItem("sin(pi x)"); c.addItem("x sin(4 pi x) + x"); return c; } public void setFunctionChoice(String s) { if ( "x(1-x)" == s) f_type = 1; else if ( "(1-x)" == s) f_type = 2; else if ( "16x^3-24x^2+9x" == s) f_type = 3; else if ( "-2x^3+3x^2-1/2x+1/4" == s) f_type = 4; else if ( "-2(x-1/2)^2+x" == s) f_type = 5; else if ( "1/(x+1)" == s) f_type = 10; else if ( "exp(-x)" == s) f_type = 11; else if ( "exp(-(5(x-1/2))^2)" == s) f_type = 12; else if ( "sin(pi x)" == s) f_type = 15; else if ( "x sin(4 pi x) + x" == s) f_type = 16; else f_type = 0; } public double g(double x_,double y_,int n_) { double x = x_corr * x_ + x_add; if (f_type == 1) return y_add + y_corr * ( x + y_alpha * ( - x + ( (1. - x) * x ))); else if (f_type == 2) return y_add + y_corr * ( x + y_alpha * ( - x + ( 1. - x ))); else if (f_type == 3) return y_add + y_corr * ( x + y_alpha * ( - x + ( 16 * x * x * x - 24 * x * x + 9 * x ))); else if (f_type == 4) return y_add + y_corr * ( x + y_alpha * ( - x + ( -2 * x * x * x + 3 * x * x - .5 * x + .25 ))); else if (f_type == 5) return y_add + y_corr * ( x + y_alpha * ( - x + ( x - (x - .5) * (x - .5) ))); else if (f_type == 10) return y_add + y_corr * ( x + y_alpha * ( - x + ( 1./(x + 1.) ))); else if (f_type == 11) return y_add + y_corr * ( x + y_alpha * ( - x + ( Math.exp(-x) ))); else if (f_type == 12) return y_add + y_corr * ( x + y_alpha * ( - x + ( Math.exp(-25*((x-.5)*(x-.5))) ))); else if (f_type == 15) return y_add + y_corr * ( x + y_alpha * ( - x + ( Math.sin(Math.PI * x) ))); else if (f_type == 16) return y_add + y_corr * ( x + y_alpha * ( - x + ( Math.sin(4 * Math.PI * x) * x + x ))); else return 0.; } public double f(double x_,double y_,int n_) { double x = x_; double y = y_; for ( int j = 0; j < n_comp; j++ ) { y = g( x, y, n_ ); x = y; } return y; } } public class GraphSys extends Applet { GraphSysPanel panel; GraphLinePanel lpanel; TextField s_x_min; TextField s_x_max; TextField s_y_min; TextField s_y_max; TextField s_y_corr; TextField s_x_corr; TextField s_y_add; TextField s_x_add; TextField s_y_alpha; TextField s_n_comp; TextField s_n_iters; TextField s_n_pts; static LayoutManager dcLayout = new FlowLayout(FlowLayout.CENTER, 10, 5); public void init() { setLayout(new BorderLayout()); panel = new GraphSysPanel(this); lpanel = new GraphLinePanel(this,panel); panel.lpanel = lpanel; Panel p3 = new Panel(); p3.add(new Checkbox("Scale")); p3.add(new Checkbox("Y Vert.")); p3.add(new Label("xmin:")); p3.add(s_x_min = new TextField(Double.toString(panel.x_min), 6)); p3.add(new Label("xmax:")); p3.add(s_x_max = new TextField(Double.toString(panel.x_max), 6)); p3.add(new Label("ymin:")); p3.add(s_y_min = new TextField(Double.toString(panel.y_min), 6)); p3.add(new Label("ymax:")); p3.add(s_y_max = new TextField(Double.toString(panel.y_max), 6)); Panel p1 = new Panel(); p1.add(new Label("x,y corr:")); p1.add(s_y_alpha = new TextField(Double.toString(panel.y_alpha), 6)); p1.add(new Label("xadd:")); p1.add(s_x_add = new TextField(Double.toString(panel.x_add), 6)); p1.add(new Label("xmult:")); p1.add(s_x_corr = new TextField(Double.toString(panel.x_corr), 6)); p1.add(new Label("yadd:")); p1.add(s_y_add = new TextField(Double.toString(panel.y_add), 6)); p1.add(new Label("ymult:")); p1.add(s_y_corr = new TextField(Double.toString(panel.y_corr), 6)); Panel p2 = new Panel(); p2.add(panel.getFunctionChoice()); p2.add(new Label("comp:")); p2.add(s_n_comp = new TextField(Integer.toString(panel.n_comp), 4)); p2.add(new Label("iters:")); p2.add(s_n_iters = new TextField(Integer.toString(panel.n_iters), 4)); p2.add(new Label("points:")); p2.add(s_n_pts = new TextField(Integer.toString(panel.n_pts), 4)); p2.add(new Button("Zoom")); p2.add(new Button("Full")); p2.add(new Button("Reset")); Panel p = new Panel(); p.setLayout(new BorderLayout()); p.add("South", p2); p.add("East", p1); p.add("North", p3); add("North", p); lpanel.setLayout(new FlowLayout(FlowLayout.CENTER, 100, 350)); add("East", lpanel); add("Center", panel); } public void setDialogParms() { s_x_min.setText(Double.toString(panel.x_min)); s_x_max.setText(Double.toString(panel.x_max)); s_y_min.setText(Double.toString(panel.y_min)); s_y_max.setText(Double.toString(panel.y_max)); s_y_alpha.setText(Double.toString(panel.y_alpha)); s_x_corr.setText(Double.toString(panel.x_corr)); s_y_corr.setText(Double.toString(panel.y_corr)); s_x_add.setText( Double.toString(panel.x_add)); s_y_add.setText( Double.toString(panel.y_add)); s_n_comp.setText( Integer.toString(panel.n_comp)); s_n_iters.setText(Integer.toString(panel.n_iters)); s_n_pts.setText( Integer.toString(panel.n_pts)); } public void getDialogParms() { panel.x_min = Double.valueOf(s_x_min.getText()).doubleValue(); panel.x_max = Double.valueOf(s_x_max.getText()).doubleValue(); panel.y_min = Double.valueOf(s_y_min.getText()).doubleValue(); panel.y_max = Double.valueOf(s_y_max.getText()).doubleValue(); panel.y_alpha = Double.valueOf(s_y_alpha.getText()).doubleValue(); panel.x_corr = Double.valueOf(s_x_corr.getText()).doubleValue(); panel.y_corr = Double.valueOf(s_y_corr.getText()).doubleValue(); panel.x_add = Double.valueOf(s_x_add.getText()).doubleValue(); panel.y_add = Double.valueOf(s_y_add.getText()).doubleValue(); panel.n_comp = Integer.parseInt(s_n_comp.getText()); panel.n_iters = Integer.parseInt(s_n_iters.getText()); panel.n_pts = Integer.parseInt(s_n_pts.getText()); } public void start() { panel.start(); lpanel.start(); } public void stop() { lpanel.stop(); panel.stop(); } public boolean action(Event evt, Object arg) { if (evt.target instanceof Choice) { panel.setFunctionChoice((String)arg); } else if (arg instanceof Boolean) { if (((Checkbox)evt.target).getLabel().equals("Scale")) { panel.is_autoscale = ! ((Boolean)arg).booleanValue(); } else if (((Checkbox)evt.target).getLabel().equals("Y Vert.")) { panel.is_use_yscale = ! ((Boolean)arg).booleanValue(); } return true; } if ("Reset".equals(arg)) { panel.is_zoom_scale = false; getDialogParms(); panel.resetAction(); lpanel.repaint(); return true; } else if ("Full".equals(arg)) { panel.is_zoom_scale = false; getDialogParms(); panel.x_min = 0; panel.x_max = 1; setDialogParms(); panel.resetAction(); lpanel.repaint(); return true; } else if ("Zoom".equals(arg)) { panel.is_zooming = true; return true; } return false; } }