Subversion Repositories wimsdev

Rev

Blame | Last modification | View Log | RSS feed

  1. /*************************************************************************
  2. *                                                                        *
  3. *  This source code file, and compiled classes derived from it, can      *
  4. *  be used and distributed without restriction, including for commercial *
  5. *  use.  (Attribution is not required but is appreciated.)               *
  6. *                                                                        *
  7. *   David J. Eck                                                         *
  8. *   Department of Mathematics and Computer Science                       *
  9. *   Hobart and William Smith Colleges                                    *
  10. *   Geneva, New York 14456,   USA                                        *
  11. *   Email: eck@hws.edu          WWW: http://math.hws.edu/eck/            *
  12. *                                                                        *
  13. *************************************************************************/
  14. //12/1/2010
  15. // jm.evers added param "file" //
  16. // jm.evers multigraphs: x^2,sqrt(x),sin(1/x)
  17. // the moving point is on first graph.
  18.  
  19. import java.awt.*;
  20. import java.applet.Applet;
  21. import java.net.*;                                                                                                                        
  22. import java.io.*;
  23. import java.util.*;                                                                                                                        
  24. import edu.hws.jcm.draw.*;
  25. import edu.hws.jcm.data.*;
  26. import edu.hws.jcm.functions.*;
  27. import edu.hws.jcm.awt.*;
  28.  
  29. public class SilentSimpleGraph extends GenericGraphApplet {
  30.  
  31.    // Declare some private variables that are created in one method in
  32.    // this class and used in a second method.
  33.  
  34.    private VariableInput xInput; // Contains the x-coordinate of the marked point.
  35.    private Vector functies;
  36.    private Color[] graphColors = { Color.magenta, new Color(0,180,0),Color.red, new Color(0,200,200),Color.orange, Color.gray, Color.blue, Color.pink };
  37.    
  38.    private Function func;   // The function that is graphed.
  39.    private Graph1D[] graphs;
  40.    private Graph1D graph;
  41.    private DrawGeometric point;  // An oval that marks the selected point on the graph.
  42.    private DrawGeometric vLine;  // A line from the point to the x-axis.
  43.    private DrawGeometric hLine;  // A line from the point to the y-axis.
  44.  
  45.  
  46.  
  47.    protected void setUpCanvas() {  // Override this to add more stuff to the canvas.
  48.    
  49.       super.setUpCanvas();  // Do the common setup: Add the axes and
  50.  
  51.       // When setUpCanvas is called, the functionInput already exists, if one is
  52.       // to be used, since it is created in setUpBopttomPanel(), which is called
  53.       // before setUpCanvas.  If functionInput exists, add a graph of the function
  54.       // from functionInput to the canvas.  If not, create a graph of the function
  55.       // specified by the parameter named "Function".
  56.         functies = new Vector();
  57.         if (functionInput != null){
  58.             func = functionInput.getFunction(xVar);
  59.             functies.add(func);
  60.         } else {
  61.         //jm.evers 1/2010 load a file from url
  62.             String def;
  63.             try{
  64.                 String data = getParameter("File");
  65.                 def = load(data);
  66.                 def = def.replaceAll("\\n","");
  67.                 StringTokenizer toks = new StringTokenizer(def, ",");
  68.                 int cnt = toks.countTokens();
  69.                 for(int i=0; i<cnt;i++){
  70.                     String tmp = toks.nextToken();
  71.                     func = new SimpleFunction( parser.parse(tmp), xVar );
  72.                     //func = new WrapperFunction(f);
  73.                     functies.add(func);
  74.                 }
  75.             } catch(Exception e){System.out.println("could not load parameter File");
  76.                 def = getParameter("Function", " abs(" + xVar.getName() + ") ^ " + xVar.getName());
  77.                 func = new SimpleFunction( parser.parse(def), xVar );
  78.                 //func = new WrapperFunction(f);
  79.                 //functies.add(func);
  80.                 functies.add(func);
  81.             }
  82.         }
  83.         graphs = new Graph1D[functies.size()];
  84.         for (int i = 0; i < functies.size(); i++) {                                                                                      
  85.             graphs[i] = new Graph1D();                                                                                                    
  86.             graphs[i].setColor(graphColors[ i % graphColors.length ]);
  87.             graphs[i].setFunction((Function)functies.elementAt(i));                                                                                                                                                                                                                            
  88.             if(i==0){
  89.                 if (! "no".equalsIgnoreCase( getParameter("ShowPoint","yes"))){
  90.                     vLine = new DrawGeometric();
  91.                     hLine = new DrawGeometric();
  92.                     point = new DrawGeometric();
  93.                     canvas.add(vLine);
  94.                     canvas.add(hLine);
  95.                     canvas.add(point);
  96.                 }          
  97.             }
  98.             canvas.add(graphs[i]);
  99.         }
  100.  
  101.    } // end setUpCanvas()
  102.    
  103.    
  104.  
  105.    protected void setUpMainPanel() { // Override to handle the point marked on the graph
  106.    
  107.       super.setUpMainPanel(); // Do the common setup
  108.  
  109.       if ( "no".equalsIgnoreCase( getParameter("ShowPoint","yes") ) ) {
  110.          return;  // If the applet is not configured to show a point, there is nothing to do.
  111.       }
  112.      
  113.       // Create two input objects, a VariableInput and a VariableSlider.  The values of
  114.       // the two inputs will be synchronized with each other using a "Tie".  The
  115.       // minimum and maximum values represented on the slider are given by the
  116.       // the minimum and maximum x-coordinates on the CoordinateRect.  This will restrict
  117.       // the x-coodinate of the point that is marked on the graph to the range of
  118.       // x-values actually shown on the screen.
  119.       xInput = new VariableInput();   // An input box for the x-coord of the marked point
  120.       xInput.setInputStyle(VariableInput.REAL);   // Allow only real numbers (not constant expressions)
  121.       CoordinateRect coords = canvas.getCoordinateRect();
  122.       VariableSlider xSlider = new VariableSlider( coords.getValueObject(CoordinateRect.XMIN),
  123.       coords.getValueObject(CoordinateRect.XMAX) );
  124.      
  125.       Value yValue = new ValueMath(func,xSlider); // Represents the y-value of the marked point.
  126.       DisplayLabel yDisplay = new DisplayLabel(" y = #", yValue);  // Shows the y-value of the point
  127.       // Create a panel to contain the input objects.
  128.      
  129.       JCMPanel panel = new JCMPanel(1,3);
  130.       panel.setBackground(getColorParam("PanelBackground",Color.lightGray));
  131.       JCMPanel subpanel = new JCMPanel();
  132.       String varName = getParameter("Variable","x");
  133.       subpanel.add(new Label(" " + varName + " = ", Label.CENTER), BorderLayout.WEST);
  134.       subpanel.add(xInput, BorderLayout.CENTER);
  135.       panel.add(xSlider);
  136.       panel.add(subpanel);
  137.       panel.add(yDisplay);
  138.      
  139.       // If there is a functionInput box, then the SOUTH position of the mainPanel already contains
  140.       // the inputPanel that contains that box.  If so, add the new panel to the SOUTH position of
  141.       // the inputPanel.  (This is a good place, in general, to put extra input objects.)
  142.       // If there is no inputPanel, then the SOUTH position of the mainPanel is empty, so put
  143.       // the newly created panel there.  Also, set the background color for the input panel from
  144.       // from the PanelBackground applet param.  (This is already done for inputPanel, if it exists.)
  145.      
  146.       if (inputPanel == null)
  147.          mainPanel.add(panel, BorderLayout.SOUTH);
  148.       else {
  149.          inputPanel.setBackground(getColorParam("PanelBackground",Color.lightGray));
  150.          inputPanel.add(panel, BorderLayout.SOUTH);
  151.       }
  152.  
  153.       // Set up all the data for the point and the lines from the point to the axes.
  154.       // The objects where created in setUpCanvas() and added to the canvas.
  155.  
  156.       hLine.setPoints(new Constant(0),yValue,xSlider,yValue);
  157.       hLine.setPoints(new Constant(0),yValue,xSlider,yValue);
  158.       point.setShape(DrawGeometric.CROSS);
  159.       point.setPoints(xSlider,yValue,5,5);
  160.       point.setLineWidth(3);
  161.       vLine.setPoints(xSlider,new Constant(0),xSlider,yValue);
  162.       Color c = getColorParam("LineColor", Color.lightGray);
  163.       vLine.setColor(c);
  164.       hLine.setColor(c);
  165.       c = getColorParam("DotColor", Color.gray);
  166.       point.setColor(c);
  167.  
  168.       // Now, I have to set a Controller to respond to changes in the input objects.
  169.       // I could just use the mainController, but then the data for the graph would
  170.       // be recomputed whenever the user changes the x-coordinate of the marked point.
  171.       // For effieciency, I will use a separate Controller that only recomputes the
  172.       // data for the point (not the graph) when the inputs change.
  173.      
  174.       Controller cc = new Controller();
  175.  
  176.       xInput.setOnTextChange(cc);   // cc responds when user types in the input box
  177.       xSlider.setOnUserAction(cc);  // cc responds when the user drags the slider
  178.       coords.setOnChange(cc);       // cc responds when the coordinate limits change;
  179.                                     //    this is necessary because the minimum and
  180.                                     //    maximum values on the slider have to be checked.
  181.  
  182.       cc.add( xInput );  // Check whether the values have changed.
  183.       cc.add( xSlider );
  184.  
  185.       cc.add( new Tie(xSlider,xInput) );  // synchronize values of input box and slider
  186.  
  187.       cc.add( hLine );  // Recompute the values for the point and lines.
  188.       cc.add( vLine );
  189.       cc.add( point );
  190.  
  191.       cc.add( yDisplay ); // Recompute the value displayed on the yDisplay label.
  192.  
  193.       mainController.add(cc);  // When the mainController recomputes (because function has
  194.                                //   been changed, all the stuff controlled by cc also has
  195.                                //   to be checked.
  196.      
  197.       mainController.remove(canvas);  // The mainController should not recompute the contents
  198.                                       //   of the canvas (which it would do by default).
  199.       mainController.add(graph);      // But the mainController should recompute the graph.
  200.  
  201.    } // end setUpMainPanel()
  202.    
  203.  
  204.  
  205.    protected void doLoadExample(String example) {
  206.          // This method is called when the user loads an example from the
  207.          // example menu (if there is one).  It overrides an empty method
  208.          // in GenericGraphApplet.
  209.          //   For the SilentSimpleGraph applet, the example string should contain
  210.          // an expression that defines the function to be graphed.  This can optionally
  211.          // be followed by a semicoloon and a list of four or five numbers.
  212.          // The first four numbers give the x- and y-limits to be used for the
  213.          // example.  If they are not present, then -5,5,-5,5 is used.  The
  214.          // fifth number, if present, gives the x-coord of the marked point
  215.          // on the graph.
  216.    
  217.       int pos = example.indexOf(";");
  218.  
  219.       double[] limits = { -5,5,-5,5 };  // x- and y-limits to use
  220.      
  221.       if (pos > 0) { // get limits from example text
  222.          String limitsText = example.substring(pos+1);
  223.          example = example.substring(0,pos);
  224.          StringTokenizer toks = new StringTokenizer(limitsText, " ,");
  225.          if (toks.countTokens() >= 4) {
  226.             for (int i = 0; i < 4; i++) {
  227.                try {
  228.                    Double d = new Double(toks.nextToken());
  229.                    limits[i] = d.doubleValue();
  230.                }
  231.                catch (NumberFormatException e) {
  232.                }
  233.             }
  234.             if (toks.countTokens() > 0 && xInput != null) {
  235.                   // get x-coord of marked point from example text
  236.                try {
  237.                    Double d = new Double(toks.nextToken());
  238.                    xInput.setVal( d.doubleValue() );
  239.                }
  240.                catch (NumberFormatException e) {
  241.                }
  242.             }
  243.          }
  244.       }
  245.      
  246.       // Set up the example data and recompute everything.
  247.  
  248.       if (functionInput != null) {
  249.             // If there is a function input box, put the example text in it.
  250.          functionInput.setText(example);
  251.       }
  252.       else {
  253.            // If there is no user input, set the function in the graph directly.
  254.            // Also, in this case, func is a "WrapperFunction".  Set the
  255.            // definition of that WrapperFunction to be the same as f
  256.          try {
  257.             Function f = new SimpleFunction( parser.parse(example), xVar );
  258.             ((WrapperFunction)func).setFunction(f);
  259.          }
  260.          catch (ParseError e) {  
  261.              // There should't be parse error's in the Web-page
  262.              // author's examples!  If there are, the function
  263.              // just won't change.
  264.          }
  265.       }
  266.       CoordinateRect coords = canvas.getCoordinateRect(0);
  267.       coords.setLimits(limits);
  268.       coords.setRestoreBuffer();
  269.       mainController.compute();
  270.      
  271.    } // end doLoadExample()
  272.    
  273. // jm.evers; handy functions, not invented here :(
  274.     public static byte [] loadURL(URL url) throws IOException {
  275.         int bufSize = 1024 * 2;
  276.         byte [] buf = new byte[bufSize];
  277.         ByteArrayOutputStream bout = new ByteArrayOutputStream();
  278.         BufferedInputStream   in   = new BufferedInputStream(url.openStream());
  279.         int n;
  280.         while ((n = in.read(buf)) > 0){
  281.             bout.write(buf, 0, n);
  282.         }
  283.         try { in.close(); } catch (Exception ignored) { }
  284.         return bout.toByteArray();
  285.     }
  286.  
  287.     public static String loadFile(String fname) throws IOException {
  288.         byte[] bytes = loadURL(new URL("file:" + fname));
  289.         return new String(bytes);
  290.     }
  291.  
  292.     public static String load(String fileOrURL) throws IOException {
  293.         try {
  294.         URL url = new URL(fileOrURL);
  295.         return new String(loadURL(url));}
  296.         catch (Exception e) { return loadFile(fileOrURL);}
  297.     }
  298. } // end class SilentSimpleGraph
  299.  
  300.  
  301. //////////////////////////////////////////////////
  302.