SliderMatrix was also discussed in detail in the tutorial. Its constructor:
public SliderMatrix(int capacity);
GUI was discussed in detail in the tutorial, here is its official constructor:
public GUI(SliderMatrix sm, AnimationManager am, double minx, double maxx, double miny, double maxy);
There are a number of methods available to customize your GUI. In order to gain access to the Graph object, use the getGraphObject() method in GUI. The following two Graph methods are of particular interest.
/** Set the frequency in which tick marks and labels show up * on the x-axis.. * * @param d value between tick marks */ public void setTickIncrementX(double d); /** Set the frequency in which tick marks and labels show up * on the y-axis.. * * @param d value between tick marks. */ public void setTickIncrementY(double d);Consult the JavaDoc documentation for more public methods available in the Graph object.
You may also use the second constructor
public GUI(SliderMatrix sm, AnimationManager am, double minx, double maxx, double miny, double maxy, boolean showxzoom, boolean showyzoom, boolean showdensity, boolean showparams, boolean showlimits);to set which GUI components are displayed. The only difference between this constructor and the first constructor is the five boolean parameters which determine which GUI componets are displayed.
This is the only class we have not discussed up until now. The code for the functions to be graphed will be the bulk of what a GrapherGUI user must write. It is extremely important to understand this class completely. Here is the full source code for this class:
package GrapherGUI; import java.awt.*; public abstract class Function { public static final short FCNTYPE_SINGLEVAL = 1; public static final short FCNTYPE_ARRAY = 2; public abstract short type(); public abstract double f(double in, SliderMatrix p); public abstract void farray( double minx, double maxx, int density, double [] varIndep, double [] varDep, SliderMatrix p); public Color color() { return (new Color(0, 0, 255, 153)); } public abstract String name(); }
Note that Function is an abstract class. This means that it cannot be instantiated. Instead, in order to create a function to be graphed, we must create our own class that inherits from Function. GrapherGUI draws a function by a set of coordinates (usually evenly spaced) and connecting them with lines. The density of the plot refers to the number of coordinates in the set. The Function class supports two types algorithms for calculating the values to be plotted.
public abstract double f(double in, SliderMatrix p);f() takes two arguments, the independent variable in and p the parameter information. It simply returns f(in). GrapherGUI handles all calculations about the spacing between plotted points and how many to use. This is the simpler method although for more complex functions, using f() may not be the most appropriate.
The following simple example defines x^2+h:
public double f(double x, SliderMatrix p) { double h; // get the parameters we need (just h in this case) try { h = p.val("h"); } catch (Error e) { System.out.println("FATAL ERROR: could not find parameter h."); return 0.0; } return (x*x+h); }
public abstract void farray( double minx, double maxx, int density, double [] varIndep, double [] varDep, SliderMatrix p);This function gives the user almost complete control over which points are plotted. minx and maxx determine the visible domain. density defines the number of points to use. varIndep is an array of independent variable values and varDep is an array of their associated dependent values. The function farray() is expected to allocate memory and populate these two arrays which will then be used by the drawing program to plot the function.
The following is a farray() method which defines x^2+h.
public void farray( double minx, double maxx, int density, double [] varIndep, double [] varDep, SliderMatrix p) { double h; // get the parameter h try { h = p.val("h"); } catch (Error e) { System.out.println("FATAL ERROR: could not find parameter h."); return 0.0; } // allocate memory for the two arrays varIndep = new double[density]; varDep = new double[density]; // get the idependent values double dx, x; dx = Math.abs(maxx - minx) / (double) density; // range / number of points for(int i = 0; i < density; i++) { varIndep[i] = minx + ((double) i) * dx; } // get the dependent values for(int i = 0; i < density; i++) { varDep[i] = h + varIndep[i] * varIndep[i]; // y = x * x + h } }As you can see, it is considerably more work to use farray() but it gives you more freedom. It is possible, for example, to use uneven spacing between points because there is complete control over the coordinate arrays. Using f() in this case would clearly have been the better choice.
The process of graphing involves the Graph object providing a set of parameters (your SliderMatrix object) and the value of the independent variable to your Function object. Graph does this a number of times (the density) to get a set of coordinates to draw. In order for this to work, you must have four methods in your class. Here is an example from Standalone.java:
class MyFunction extends Function { // this tells GrapherGUI that this function will use f() // instead of farray() to define the function. public short type() { return Function.FCNTYPE_SINGLEVAL; } // "Test" will show up in the key in the color that // represents this function. In this class, there is // no color() method overriding the default, so this // function will be blue. public String name() { return "Test"; } // define the function x^3*h/g public double f(double x, SliderMatrix p) { double g, h; try { g = p.val("g"); h = p.val("h"); } catch (Error e) { return 0.0; } return x*x*x*h/g; } public void farray( double minx, double maxx, int density, double [] a, double [] b, SliderMatrix p) {} // not used; empty }Note that public double f(double, SliderMatrix) calculates the dependent variable value. We want to give a single dependent value for a given independent value so we use f() and simply set farray() to be an empty function. Finally, type() tells GrapherGUI what kind of algorithm this function uses. Note also that public String name() returns the string name. This string is used when the program displays the key. Also, public Color color() overrides the default color of blue.
Note how the function gets the parameters values:
try { g = p.val("g"); h = p.val("h"); } catch (Error e) { return 0.0; } return in * in * in * h / g;The method val() in SliderMatrix class returns the current value. It takes an identifier string as input. So if you added a parameter with the name "omega", you would call p.val("omega") to get its value. The try try_codeblock catch handle_codeblock is required because val() throws an error if it cannot find the parameter requested. Upon error, the program will execute handle_codeblock. In our case, we just return 0.0. This is not recommended. In fact, an error of this type should usually be fatal. Finally, we return the value. This class defined a very simple function: x^3 * (h / g)
We are not limited to just having three predefined methods in a class inheriting from Function. We can have as many helper methods as needed, but f() and name() are required or the program will not compile. For more on abstract classes, consult the Java OOP tutorial.
You may have a function which contains a time parameter. Sometimes it is useful to be able to observe how this function changes as time progresses. This class provides a way of animating your function so that the time progresses.
Here is the constructor for AnimationManager:
/** Constructor * @param timevar name of the time parameter -- usually t * @param animSpeed the replay speed (milliseconds) * @param dt change in time interval per change * @param sm parameter data */ public AnimationManager(String timevar, int refreshRate, double dt, SliderMatrix sm);
In order to use this feature, you must declare an AnimationManager object (NOTE: you must have created a SliderMatrix object first). Here, we create an AnimationManager that treats the parameter t as the time variable. The second parameter indicates how fast the animation should progress. In this case, the graph will refresh every 250 milliseconds. The third parameter tells us that we should increment the time parameter by a value of 0.25 units on the sliderbar. Finally, sm is a SliderMatrix object that has already been created. If t is not a parameter in sm, then errors will occur. we say that we wish to have the parameter t
AnimationManager am = new AnimationManager("t", 250, 0.25, sm);And when you declare your GUI object, you would use your AnimationManager as one of the parameters:
GUI gui = new GUI(sm, am, 0.0, 5.0, -1.0, 1.0);Instead of the second parameter being null (which our very first example did), we insert our AnimationManager.