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 AnimatedGraph displays a graph
  16. // of a function that can depend on a parameter.  The value of the
  17. // parameter can be "animated" so that it ranges from one value ot
  18. // another over a sequence of frames.
  19.  
  20. import java.awt.*;
  21. import java.applet.Applet;
  22. import java.util.*;
  23. import edu.hws.jcm.draw.*;
  24. import edu.hws.jcm.data.*;
  25. import edu.hws.jcm.functions.*;
  26. import edu.hws.jcm.awt.*;
  27. import java.net.*;
  28. import java.io.*;
  29.  
  30. public class SilentAnimatedGraph 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 Animator animator; // Animates the graph
  40.    private Variable kVar;   // The parameter variable
  41.    
  42.    private VariableInput kMin, kMax, kIntervals;  // min, max, and number of intervals for the animator.  Might be null.
  43.  
  44.  
  45.    protected void setUpParser() {  // Override this to create the animator and add its variable to the parser.
  46.    
  47.       int options = Animator.START_STOP_BUTTON | Animator.PAUSE_BUTTON  | Animator.LOOP_CHOICE;
  48.       if  ( ! "no".equalsIgnoreCase(getParameter("UseNextAndPrev","yes")) )
  49.          options |=  Animator.PREV_BUTTON | Animator.NEXT_BUTTON;
  50.       animator = new Animator(options);
  51.       kVar = animator.getValueAsVariable( getParameter("Parameter","k") );  
  52.       parser.add(kVar);
  53.      
  54.       super.setUpParser();
  55.  
  56.       parameterDefaults = new Hashtable();
  57.       String defaultFunction = xVar.getName() + " / (" + kVar.getName() + " - " + xVar.getName() + "^2)";
  58.       parameterDefaults.put("Function",defaultFunction);
  59.       if (! "no".equalsIgnoreCase(getParameter("UseAnimatorInputs")))
  60.          parameterDefaults.put("TwoLimitsColumns","yes"); // change default if we need space for animator inputs
  61.      
  62.    } // end setUpParser()
  63.    
  64.  
  65.    protected void setUpBottomPanel() {  // Overridden to add the sliders at the bottom of the applet.
  66.  
  67.       super.setUpBottomPanel();  // Do the default setup.
  68.      
  69.       // If there is a functionInput box, then the SOUTH position of the mainPanel already contains
  70.       // the inputPanel that contains that box.  If so, add the animator to the SOUTH position of
  71.       // the inputPanel.  (This is a good place, in general, to put extra input objects.)
  72.       // If there is no inputPanel, then the SOUTH position of the mainPanel is empty, so put
  73.       // the animator there.
  74.      
  75.       if (inputPanel != null)
  76.          inputPanel.add(animator, BorderLayout.SOUTH);
  77.       else
  78.          mainPanel.add(animator, BorderLayout.SOUTH);
  79.  
  80.    } // end setUpBottomPanel()
  81.  
  82.  
  83.  
  84.    protected void setUpCanvas() { // Overridden to add the graph to the canvas and do other chores.
  85.  
  86.       super.setUpCanvas();  // Do the default setup.
  87.  
  88.       // When setUpCanvas() is called, the functionInput already exists, if one is
  89.       // to be used, since it is created in setUpBopttomPanel(), which is called
  90.       // before setUpCanvas.  If functionInput exists, add a graph of the function
  91.       // from functionInput to the canvas.  If not, create a graph of the function
  92.       // specified by the parameter named "Function" (or use sin(k*x) if none is specified).
  93.         if (functionInput != null){
  94.             func = functionInput.getFunction(xVar);
  95.         }
  96.         else
  97.         {//jm.evers 1/2010 load a file from url
  98.             String def;
  99.             try{
  100.                 String data = getParameter("File");
  101.                 def = load(data);
  102.                 def = def.replaceAll("\\n","");
  103.                 System.out.println("loaded "+def);
  104.             }
  105.             catch(Exception e){
  106.                 System.out.println("could not load parameter File");
  107.                 def = getParameter("Function");  // default value is set in setUpParser()
  108.             }
  109.             func = new SimpleFunction( parser.parse(def), xVar );
  110.         }
  111.  
  112.      
  113.       graph = new Graph1D(func);
  114.       graph.setColor(getColorParam("GraphColor", Color.magenta));
  115.       canvas.add(graph);
  116.      
  117.       // Set up the min, max, and intervals property of the animator
  118.      
  119.       if  (! "no".equalsIgnoreCase(getParameter("UseAnimatorInputs"))) {
  120.          kMin = new VariableInput(kVar.getName() + "Start",getParameter("ParameterMin","-2"));
  121.          kMax = new VariableInput(kVar.getName() + "End",getParameter("ParameterMax","2"));
  122.          kIntervals = new VariableInput("Intervals", getParameter("Intervals","25"));
  123.          kIntervals.setInputStyle(VariableInput.INTEGER);
  124.          kIntervals.setMin(1);
  125.          kIntervals.setMax(1000);
  126.          kMin.setOnUserAction(mainController);
  127.          kMax.setOnUserAction(mainController);
  128.          kIntervals.setOnUserAction(mainController);
  129.          animator.setMin(kMin);
  130.          animator.setMax(kMax);
  131.          animator.setIntervals(kIntervals);
  132.          if (limitsPanel != null) {
  133.                // componets will be added to limitsPanel in setUpLimitsPanel()
  134.             mainController.add(kMin);  // This is not done automatically, since they are in a limits panel  
  135.             mainController.add(kMax);
  136.             mainController.add(kIntervals);
  137.          }
  138.          else {
  139.             JCMPanel ap = new JCMPanel(9,0);
  140.             ap.setBackground(getColorParam("PanelBackground", Color.lightGray));
  141.             ap.add(new Label(kMin.getName()));
  142.             ap.add(kMin);
  143.             ap.add(new Label());
  144.             ap.add(new Label(kMax.getName()));
  145.             ap.add(kMax);
  146.             ap.add(new Label());
  147.             ap.add(new Label(kIntervals.getName()));
  148.             ap.add(kIntervals);
  149.             ap.add(new Label());
  150.             mainPanel.add(ap,BorderLayout.EAST);
  151.          }
  152.       }
  153.       else {
  154.          try {
  155.             animator.setMin( (new Double(getParameter("ParameterMin","-2"))).doubleValue() );
  156.             animator.setMax( (new Double(getParameter("ParameterMax","2"))).doubleValue() );
  157.             animator.setIntervals( (int)Math.round((new Double(getParameter("Intervals","25"))).doubleValue()) );
  158.          }
  159.          catch (NumberFormatException e) {
  160.          }
  161.       }
  162.       animator.setOnChange(mainController);
  163.  
  164.       // Add a DrawString to show the current value of the parameter
  165.  
  166.       if ( ! "no".equalsIgnoreCase(getParameter("ShowParameter","yes")) ) {
  167.          DrawString param = new DrawString(kVar.getName() + " = #", DrawString.BOTTOM_LEFT, new Value[] { kVar });
  168.          param.setBackgroundColor(canvas.getBackground());
  169.          Color c = getColorParam("ParameterColor",Color.black);
  170.          param.setColor(c);
  171.          canvas.add(param);
  172.       }
  173.  
  174.    } // end setUpCanvas
  175.  
  176.  
  177.    protected void setUpLimitsPanel() {
  178.      super.setUpLimitsPanel();
  179.      if (limitsPanel != null && kMin != null) {  // add animator inputs to limits panel
  180.          limitsPanel.addComponentPair(kMin,kMax);
  181.          limitsPanel.addComponent(kIntervals);
  182.      }
  183.    }
  184.  
  185.  
  186.    protected void doLoadExample(String example) {
  187.          // This method is called when the user loads an example from the
  188.          // example menu (if there is one).  It overrides an empty method
  189.          // in GenericGraphApplet.
  190.          //   For the SilentAnimatedGraph applet, the example string should contain
  191.          // an expression that defines the function to be graphed.  This can optionally
  192.          // be followed by a semicolon and a list of four to nine numbers.
  193.          // The first four numbers give the x- and y-limits to be used for the
  194.          // example.  If they are not present, then -5,5,-5,5 is used.  The
  195.          // next three numbers specify the minimum value for the parameter, the
  196.          // maximum number, and the number of intervals in the animation.
  197.          // The eigth number, if present, specifies the starting loop style
  198.          // for the animation with the following code:  0 for once-through,
  199.          // 1 for loop, and 2 for back-and-forth.  The ninth number, if
  200.          // present, tells whether to start the animation immediately upon
  201.          // loading.  If it is 1, the animation is started.  If it is
  202.          // not specified or is any value other than 1, the animation is not started.
  203.          
  204.       animator.stop();
  205.          
  206.       int pos = example.indexOf(";");
  207.       boolean startAnimation = false;
  208.       double[] limits = { -5,5,-5,5 }; // x- and y-limits to use
  209.  
  210.       if (pos > 0) {
  211.                // Get limits from example text.
  212.          String nums = example.substring(pos+1);
  213.          example = example.substring(0,pos);
  214.          StringTokenizer toks = new StringTokenizer(nums, " ,");
  215.          if (toks.countTokens() >= 4) {
  216.             for (int i = 0; i < 4; i++) {
  217.                try {
  218.                    Double d = new Double(toks.nextToken());
  219.                    limits[i] = d.doubleValue();
  220.                }
  221.                catch (NumberFormatException e) {
  222.                }
  223.             }
  224.          }
  225.          if (toks.hasMoreTokens()) {
  226.             try {
  227.                double d = (new Double(toks.nextToken())).doubleValue();
  228.                if (kMin == null)
  229.                   animator.setMin(d);
  230.                else
  231.                   kMin.setVal(d);
  232.             }
  233.             catch (NumberFormatException e) {
  234.             }
  235.          }
  236.          if (toks.hasMoreTokens()) {
  237.             try {
  238.                double d = (new Double(toks.nextToken())).doubleValue();
  239.                if (kMax == null)
  240.                   animator.setMax(d);
  241.                else
  242.                   kMax.setVal(d);
  243.             }
  244.             catch (NumberFormatException e) {
  245.             }
  246.          }
  247.          if (toks.hasMoreTokens()) {
  248.             try {
  249.                int d = (int)Math.round((new Double(toks.nextToken())).doubleValue());
  250.                if (kIntervals == null)
  251.                   animator.setIntervals(d);
  252.                else
  253.                   kIntervals.setVal(d);
  254.             }
  255.             catch (NumberFormatException e) {
  256.             }
  257.          }
  258.          if (toks.hasMoreTokens()) {
  259.             try {
  260.                int d = (int)Math.round((new Double(toks.nextToken())).doubleValue());
  261.                animator.setLoopStyle(d);
  262.             }
  263.             catch (NumberFormatException e) {
  264.             }
  265.          }
  266.          if (toks.hasMoreTokens()) {
  267.             try {
  268.                int d = (int)Math.round((new Double(toks.nextToken())).doubleValue());
  269.                startAnimation = (d == 1);
  270.             }
  271.             catch (NumberFormatException e) {
  272.             }
  273.          }
  274.       }
  275.      
  276.       // Set up the example data and recompute everything.
  277.  
  278.       if (functionInput != null) {
  279.             // If there is a function input box, put the example text in it.
  280.          functionInput.setText(example);
  281.       }
  282.       else {
  283.            // If there is no user input, set the function in the graph directly.
  284.          try {
  285.             func = new SimpleFunction( parser.parse(example), xVar );
  286.             graph.setFunction(func);
  287.          }
  288.          catch (ParseError e) {  
  289.              // There should't be parse error's in the Web-page
  290.              // author's examples!  If there are, the function
  291.              // just won't change.
  292.          }
  293.       }
  294.       CoordinateRect coords = canvas.getCoordinateRect(0);
  295.       coords.setLimits(limits);
  296.       coords.setRestoreBuffer();
  297.       mainController.compute();
  298.       if (startAnimation) {
  299.          try {  // insert a small delay before animation starts
  300.             synchronized(this) {
  301.                wait(250);
  302.             }
  303.          }
  304.          catch (InterruptedException e) {
  305.          }
  306.          animator.start();
  307.       }
  308.      
  309.    } // end doLoadExample()
  310.    
  311.    public void stop() {  // stop animator when applet is stopped
  312.       animator.stop();
  313.       super.stop();
  314.    }
  315.  
  316. // jm.evers; handy functions, not invented here :(
  317.     public static byte [] loadURL(URL url) throws IOException {
  318.         int bufSize = 1024 * 2;
  319.         byte [] buf = new byte[bufSize];
  320.         ByteArrayOutputStream bout = new ByteArrayOutputStream();
  321.         BufferedInputStream   in   = new BufferedInputStream(url.openStream());
  322.         int n;
  323.         while ((n = in.read(buf)) > 0){
  324.             bout.write(buf, 0, n);
  325.         }
  326.         try { in.close(); } catch (Exception ignored) { }
  327.         return bout.toByteArray();
  328.     }
  329.  
  330.     public static String loadFile(String fname) throws IOException {
  331.         byte[] bytes = loadURL(new URL("file:" + fname));
  332.         return new String(bytes);
  333.     }
  334.  
  335.     public static String load(String fileOrURL) throws IOException {
  336.         try {
  337.         URL url = new URL(fileOrURL);
  338.         return new String(loadURL(url));}
  339.         catch (Exception e) { return loadFile(fileOrURL);}
  340.     }  
  341.    
  342. } // end class FamiliesOfGraphs
  343.  
  344.