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.  
  15. // An applet belonging to the class FamiliesOfGraphs displays a graph
  16. // of a function that can depend on one or more parameters.  The values of
  17. // the parameters are controlled by the user using sliders at the bottom of
  18. // the applet.
  19.  
  20.  
  21. import java.awt.*;
  22. import java.applet.Applet;
  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.  
  30. public class FamiliesOfGraphs extends GenericGraphApplet {
  31.  
  32.  
  33.    // Declare some private variables that are created in one method in
  34.    // this class and used in a second method.
  35.  
  36.    private Function func;   // The function that is graphed.
  37.    private Graph1D graph;   // The graph of the function.
  38.    
  39.    private Vector sliders;  // Elements of this vector are the VariableSlider
  40.                             //   objects that represent the parameter values.
  41.                             //   The sliders are created in the setUpParser() method.
  42.  
  43.  
  44.  
  45.    protected void setUpParser() {  // Override this to add VariableSliders to parser.
  46.    
  47.       // Get the data for the sliders from applet params named "Parameter", "Parameter1", ...
  48.       // The sliders are created and the variables are added to the parser by the
  49.       // addParameter() method, which is defined below.
  50.      
  51.       sliders = new Vector();
  52.       int ct = 0;
  53.       String param = getParameter("Parameter");
  54.       if (param == null) {
  55.          ct++;
  56.          param = getParameter("Parameter" + ct);
  57.       }
  58.       while (true) {
  59.          if (param == null)
  60.             break;
  61.          addParameter(param);
  62.          ct++;
  63.          param = getParameter("Parameter" + ct);
  64.       }
  65.      
  66.       // If no parameters were specified in applet params, create one with name "k".
  67.      
  68.       if (sliders.size() == 0)
  69.          addParameter("k");
  70.          
  71.       super.setUpParser();  // Call this last so function definitions
  72.                             // in applet params can use the parameter names
  73.                             // that have just been added to the parser
  74.                             // (even though it's probably not a good idea).
  75.                             // Note that this also defines the independent variable,
  76.                             // whose name is given by the applet param "Variable"
  77.                             // and which is referred to as xVar in this program.
  78.                            
  79.       VariableSlider slide = (VariableSlider)sliders.elementAt(0);
  80.       String def = getParameter("Function", "sin(" + slide.getName() + " * " + xVar.getName() + ")");
  81.       parameterDefaults = new Hashtable();  // I want to set a different default value for
  82.                                             // the "Function" applet param.
  83.       parameterDefaults.put("Function",def);
  84.          
  85.                            
  86.    } // end setUpParser()
  87.    
  88.  
  89.  
  90.    private void addParameter(String data) {
  91.          // Create a VariableSlider from the information in name and add it to the
  92.          // Vector of sliders.  The data must contain the name of the variable
  93.          // associated with the slider.  The name can be followed by a ";" and up to
  94.          // three numbers.  (If there is no ";", a space after the name will do.)
  95.          // The numbers can be separated by commas, spaces, or tabs.  The first
  96.          // number gives the minimum value on the slider, the second gives the maximum,
  97.          // and the third gives the initial value of the slider variable.
  98.  
  99.       double min = -5, max = 5, val = 0;  // min, max, and value for slider
  100.  
  101.       data = data.trim();
  102.       int pos = data.indexOf(';');
  103.       if (pos < 0)
  104.          pos = data.indexOf(' ');
  105.          
  106.       String name; //  The name of the parameter
  107.  
  108.       if (pos < 0) {
  109.             // If there is no space or ";", the data is just the name of the variable.
  110.          name = data;
  111.       }
  112.       else {
  113.             // Get the name from the front of the data, then look for min, max, and val.
  114.           String nums = data.substring(pos+1);
  115.           name = data.substring(0,pos).trim();
  116.           StringTokenizer toks = new StringTokenizer(nums," ,\t");
  117.           try {
  118.              if (toks.hasMoreElements())
  119.                  min = (new Double(toks.nextToken())).doubleValue();
  120.              if (toks.hasMoreElements())
  121.                  max = (new Double(toks.nextToken())).doubleValue();
  122.              if (toks.hasMoreElements())
  123.                  val = (new Double(toks.nextToken())).doubleValue();
  124.           }
  125.           catch (NumberFormatException e) {
  126.              min = -5;
  127.              max = 5;
  128.              val = 0;
  129.           }
  130.       }
  131.      
  132.       // Create the slider, adding the associated variable to the parser, and set its value.
  133.      
  134.       VariableSlider slide = new VariableSlider(name, new Constant(min), new Constant(max), parser);
  135.       slide.setVal(val);
  136.      
  137.       sliders.addElement(slide);  // Save the slider in the array of sliders for later use.
  138.      
  139.    } // end setUpParser();
  140.    
  141.  
  142.  
  143.    protected void setUpBottomPanel() {  // Overridden to add the sliders at the bottom of the applet.
  144.  
  145.       super.setUpBottomPanel();  // Do the default setup.
  146.  
  147.       // Create a panel holding all the sliders, with a display label for each slider to show its value.
  148.  
  149.       JCMPanel sliderPanel = new JCMPanel();
  150.       sliderPanel.setLayout(new GridLayout(0,1,3,3));
  151.       sliderPanel.setBackground(getColorParam("PanelBackground", Color.lightGray));
  152.       for (int i = 0; i < sliders.size(); i++) {
  153.          JCMPanel p = new JCMPanel();
  154.          VariableSlider slide = (VariableSlider)sliders.elementAt(i);
  155.          p.add(slide, BorderLayout.CENTER);
  156.          p.add(new DisplayLabel("  " + slide.getName() + " = # ", new Value[] { slide.getVariable() } ),
  157.                       BorderLayout.EAST);
  158.          sliderPanel.add(p);
  159.          slide.setOnUserAction(mainController);
  160.       }
  161.      
  162.      
  163.       // If there is a functionInput box, then the SOUTH position of the mainPanel already contains
  164.       // the inputPanel that contains that box.  If so, add the new panel to the SOUTH position of
  165.       // the inputPanel.  (This is a good place, in general, to put extra input objects.)
  166.       // If there is no inputPanel, then the SOUTH position of the mainPanel is empty, so put
  167.       // the newly created panel there.
  168.      
  169.       if (inputPanel != null)
  170.          inputPanel.add(sliderPanel, BorderLayout.SOUTH);
  171.       else
  172.          mainPanel.add(sliderPanel, BorderLayout.SOUTH);
  173.  
  174.    } // end setUpBottomPanel()
  175.  
  176.  
  177.  
  178.    protected void setUpCanvas() { // Overridden to add the graph to the canvas.
  179.  
  180.       super.setUpCanvas();  // Do the default setup.
  181.  
  182.       // When setUpCanvas() is called, the functionInput already exists, if one is
  183.       // to be used, since it is created in setUpBopttomPanel(), which is called
  184.       // before setUpCanvas.  If functionInput exists, add a graph of the function
  185.       // from functionInput to the canvas.  If not, create a graph of the function
  186.       // specified by the parameter named "Function" (or use sin(k*x) if none is specified).
  187.  
  188.       if (functionInput != null)
  189.          func = functionInput.getFunction(xVar);
  190.       else {
  191.          String def = getParameter("Function");  // default value is set in setUpParser()
  192.          func = new SimpleFunction( parser.parse(def), xVar );
  193.       }
  194.  
  195.       // Create a graph of the function and add it to the canvas.
  196.      
  197.       graph = new Graph1D(func);
  198.       graph.setColor(getColorParam("GraphColor", Color.magenta));
  199.       canvas.add(graph);
  200.  
  201.    } // end setUpCanvas
  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 FamiliesOfGraphs applet, the example string should contain
  210.          // an expression that defines the function to be graphed.  This can optionally
  211.          // be followed by a semicolon and a list of four or more 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.          // remaining numbers occur in groups of three and specify the minimumn,
  215.          // maximum and values of the parameters, in the
  216.          // same order that they were encountered in the setUpParser() method.
  217.          
  218.       int pos = example.indexOf(";");
  219.      
  220.       double[] limits = { -5,5,-5,5 }; // x- and y-limits to use
  221.  
  222.       if (pos > 0) {
  223.                // Get limits from example text.
  224.          String nums = example.substring(pos+1);
  225.          example = example.substring(0,pos);
  226.          StringTokenizer toks = new StringTokenizer(nums, " ,");
  227.          if (toks.countTokens() >= 4) {
  228.             for (int i = 0; i < 4; i++) {
  229.                try {
  230.                    Double d = new Double(toks.nextToken());
  231.                    limits[i] = d.doubleValue();
  232.                }
  233.                catch (NumberFormatException e) {
  234.                }
  235.             }
  236.          }
  237.          int i = 0;
  238.          while (i < sliders.size() && toks.hasMoreElements()) {
  239.                // Look for a value for the i-th slider.
  240.             try {
  241.                 double min = (new Double(toks.nextToken())).doubleValue();
  242.                 double max = (new Double(toks.nextToken())).doubleValue();
  243.                 double d = (new Double(toks.nextToken())).doubleValue();
  244.                 VariableSlider slider = ((VariableSlider)sliders.elementAt(i));
  245.                 slider.setMin(new Constant(min));
  246.                 slider.setMax(new Constant(max));
  247.                 slider.setVal(d);
  248.             }
  249.             catch (Exception e) {
  250.             }
  251.             i++;
  252.          }
  253.       }
  254.      
  255.       // Set up the example data and recompute everything.
  256.  
  257.       if (functionInput != null) {
  258.             // If there is a function input box, put the example text in it.
  259.          functionInput.setText(example);
  260.       }
  261.       else {
  262.            // If there is no user input, set the function in the graph directly.
  263.          try {
  264.             func = new SimpleFunction( parser.parse(example), xVar );
  265.             graph.setFunction(func);
  266.          }
  267.          catch (ParseError e) {  
  268.              // There should't be parse error's in the Web-page
  269.              // author's examples!  If there are, the function
  270.              // just won't change.
  271.          }
  272.       }
  273.       CoordinateRect coords = canvas.getCoordinateRect(0);
  274.       coords.setLimits(limits);
  275.       coords.setRestoreBuffer();
  276.       mainController.compute();
  277.      
  278.    } // end doLoadExample()
  279.  
  280.    
  281. } // end class FamiliesOfGraphs
  282.  
  283.