Advanced Graphics Java

/*************************************************************************
*                                                                        *
*  This source code file, and compiled classes derived from it, can      *
*  be used and distributed without restriction, including for commercial *
*  use.  (Attribution is not required but is appreciated.)               * 
*                                                                        *
*   David J. Eck                                                         *
*   Department of Mathematics and Computer Science                       *
*   Hobart and William Smith Colleges                                    *
*   Geneva, New York 14456,   USA                                        *
*   Email: eck@hws.edu          WWW: http://math.hws.edu/eck/            *
*                                                                        *
*************************************************************************/
// An applet belonging to the class FamiliesOfGraphs displays a graph
// of a function that can depend on one or more parameters.  The values of
// the parameters are controlled by the user using sliders at the bottom of
// the applet.
import java.awt.*;
import java.applet.Applet;
import java.util.*;
import edu.hws.jcm.draw.*;
import edu.hws.jcm.data.*;
import edu.hws.jcm.functions.*;
import edu.hws.jcm.awt.*;
public class FamiliesOfGraphs extends GenericGraphApplet {
   // Declare some private variables that are created in one method in
   // this class and used in a second method.
   private Function func;   // The function that is graphed.
   private Graph1D graph;   // The graph of the function.
   
   private Vector sliders;  // Elements of this vector are the VariableSlider
                            //   objects that represent the parameter values.
                            //   The sliders are created in the setUpParser() method.
   protected void setUpParser() {  // Override this to add VariableSliders to parser.
   
      // Get the data for the sliders from applet params named "Parameter", "Parameter1", ...
      // The sliders are created and the variables are added to the parser by the
      // addParameter() method, which is defined below.
      
      sliders = new Vector();
      int ct = 0;
      String param = getParameter("Parameter");
      if (param == null) {
         ct++;
         param = getParameter("Parameter" + ct);
      }
      while (true) {
         if (param == null)
            break;
         addParameter(param);
         ct++;
         param = getParameter("Parameter" + ct);
      }
      
      // If no parameters were specified in applet params, create one with name "k".
      
      if (sliders.size() == 0)
         addParameter("k");
         
      super.setUpParser();  // Call this last so function definitions 
                            // in applet params can use the parameter names 
                            // that have just been added to the parser
                            // (even though it's probably not a good idea).
                            // Note that this also defines the independent variable,
                            // whose name is given by the applet param "Variable"
                            // and which is referred to as xVar in this program.
                            
      VariableSlider slide = (VariableSlider)sliders.elementAt(0);
      String def = getParameter("Function", "sin(" + slide.getName() + " * " + xVar.getName() + ")");
      parameterDefaults = new Hashtable();  // I want to set a different default value for
                                            // the "Function" applet param.
      parameterDefaults.put("Function",def);
         
                            
   } // end setUpParser()
   
   private void addParameter(String data) {
         // Create a VariableSlider from the information in name and add it to the
         // Vector of sliders.  The data must contain the name of the variable 
         // associated with the slider.  The name can be followed by a ";" and up to
         // three numbers.  (If there is no ";", a space after the name will do.)
         // The numbers can be separated by commas, spaces, or tabs.  The first
         // number gives the minimum value on the slider, the second gives the maximum,
         // and the third gives the initial value of the slider variable.
      double min = -5, max = 5, val = 0;  // min, max, and value for slider
      data = data.trim();
      int pos = data.indexOf(';');
      if (pos < 0)
         pos = data.indexOf(' ');
         
      String name; //  The name of the parameter
      if (pos < 0) {
            // If there is no space or ";", the data is just the name of the variable.
         name = data;
      }
      else {
            // Get the name from the front of the data, then look for min, max, and val.
          String nums = data.substring(pos+1);
          name = data.substring(0,pos).trim();
          StringTokenizer toks = new StringTokenizer(nums," ,\t");
          try {
             if (toks.hasMoreElements())
                 min = (new Double(toks.nextToken())).doubleValue();
             if (toks.hasMoreElements())
                 max = (new Double(toks.nextToken())).doubleValue();
             if (toks.hasMoreElements())
                 val = (new Double(toks.nextToken())).doubleValue();
          }
          catch (NumberFormatException e) {
             min = -5;
             max = 5;
             val = 0;
          }
      }
      
      // Create the slider, adding the associated variable to the parser, and set its value.
      
      VariableSlider slide = new VariableSlider(name, new Constant(min), new Constant(max), parser);
      slide.setVal(val);
      
      sliders.addElement(slide);  // Save the slider in the array of sliders for later use.
      
   } // end setUpParser();
   
   protected void setUpBottomPanel() {  // Overridden to add the sliders at the bottom of the applet.
      super.setUpBottomPanel();  // Do the default setup.
      // Create a panel holding all the sliders, with a display label for each slider to show its value.
      JCMPanel sliderPanel = new JCMPanel();
      sliderPanel.setLayout(new GridLayout(0,1,3,3));
      sliderPanel.setBackground(getColorParam("PanelBackground", Color.lightGray));
      for (int i = 0; i < sliders.size(); i++) {
         JCMPanel p = new JCMPanel();
         VariableSlider slide = (VariableSlider)sliders.elementAt(i);
         p.add(slide, BorderLayout.CENTER);
         p.add(new DisplayLabel("  " + slide.getName() + " = # ", new Value[] { slide.getVariable() } ), 
                      BorderLayout.EAST);
         sliderPanel.add(p);
         slide.setOnUserAction(mainController);
      }
      
      
      // If there is a functionInput box, then the SOUTH position of the mainPanel already contains
      // the inputPanel that contains that box.  If so, add the new panel to the SOUTH position of
      // the inputPanel.  (This is a good place, in general, to put extra input objects.)
      // If there is no inputPanel, then the SOUTH position of the mainPanel is empty, so put
      // the newly created panel there.
      
      if (inputPanel != null)
         inputPanel.add(sliderPanel, BorderLayout.SOUTH);
      else
         mainPanel.add(sliderPanel, BorderLayout.SOUTH);
   } // end setUpBottomPanel()
   protected void setUpCanvas() { // Overridden to add the graph to the canvas.
      super.setUpCanvas();  // Do the default setup.
      // When setUpCanvas() is called, the functionInput already exists, if one is
      // to be used, since it is created in setUpBopttomPanel(), which is called
      // before setUpCanvas.  If functionInput exists, add a graph of the function
      // from functionInput to the canvas.  If not, create a graph of the function
      // specified by the parameter named "Function" (or use sin(k*x) if none is specified).
      if (functionInput != null)
         func = functionInput.getFunction(xVar);
      else {
         String def = getParameter("Function");  // default value is set in setUpParser()
         func = new SimpleFunction( parser.parse(def), xVar );
      }
      // Create a graph of the function and add it to the canvas.
      
      graph = new Graph1D(func);
      graph.setColor(getColorParam("GraphColor", Color.magenta));
      canvas.add(graph);
   } // end setUpCanvas
   protected void doLoadExample(String example) {
         // This method is called when the user loads an example from the 
         // example menu (if there is one).  It overrides an empty method
         // in GenericGraphApplet.
         //   For the FamiliesOfGraphs applet, the example string should contain
         // an expression that defines the function to be graphed.  This can optionally
         // be followed by a semicolon and a list of four or more numbers.
         // The first four numbers give the x- and y-limits to be used for the
         // example.  If they are not present, then -5,5,-5,5 is used.  The
         // remaining numbers occur in groups of three and specify the minimumn, 
         // maximum and values of the parameters, in the
         // same order that they were encountered in the setUpParser() method.
         
      int pos = example.indexOf(";");
      
      double[] limits = { -5,5,-5,5 }; // x- and y-limits to use
      if (pos > 0) { 
               // Get limits from example text.
         String nums = example.substring(pos+1);
         example = example.substring(0,pos);
         StringTokenizer toks = new StringTokenizer(nums, " ,");
         if (toks.countTokens() >= 4) {
            for (int i = 0; i < 4; i++) {
               try {
                   Double d = new Double(toks.nextToken());
                   limits[i] = d.doubleValue();
               }
               catch (NumberFormatException e) {
               }
            }
         }
         int i = 0;
         while (i < sliders.size() && toks.hasMoreElements()) {
               // Look for a value for the i-th slider.
            try {
                double min = (new Double(toks.nextToken())).doubleValue();
                double max = (new Double(toks.nextToken())).doubleValue();
                double d = (new Double(toks.nextToken())).doubleValue();
                VariableSlider slider = ((VariableSlider)sliders.elementAt(i));
                slider.setMin(new Constant(min));
                slider.setMax(new Constant(max));
                slider.setVal(d);
            }
            catch (Exception e) {
            }
            i++;
         }
      }
      
      // Set up the example data and recompute everything.
      if (functionInput != null) {
            // If there is a function input box, put the example text in it.
         functionInput.setText(example);
      }
      else { 
           // If there is no user input, set the function in the graph directly.
         try {
            func = new SimpleFunction( parser.parse(example), xVar );
            graph.setFunction(func);
         }
         catch (ParseError e) {  
             // There should't be parse error's in the Web-page
             // author's examples!  If there are, the function
             // just won't change.
         }
      }
      CoordinateRect coords = canvas.getCoordinateRect(0);
      coords.setLimits(limits);
      coords.setRestoreBuffer();
      mainController.compute();
      
   } // end doLoadExample()
      public static void main(String[] a){
         javax.swing.JFrame f = new javax.swing.JFrame();
         Applet app = new FamiliesOfGraphs();
         app.init();
         
         f.getContentPane().add (app);
         f.pack();
         f.setSize (new Dimension (500, 500));
         f.setVisible(true);
      }   
} // end class FamiliesOfGraphs
           
       
jcm1-source.zip( 532 k)