In the source code for the function classes in the ` SlingFunction ` hierarchy, the design principles show through. They are as follows : -
Represent each known function with a class that implements the method ` f() ` . -
Write ` f() ` for each function class so that it wraps its function around other function objects. Require that these objects be supplied to the class constructor. -
Define the signature of ` f() ` to be ` Point f(double t). ` -
For any base function that would naturally return a single number ` y ` , return new ` Point(t, y) ` , where ` t ` is the input parameter to ` f() ` . The classes in this hierarchy also provide the ability to create unvariable functions from variable functions by evaluating their sources. The ` Variable ` class and the hierarchy superclass ` SlingFunction ` are the only classes that actually implement methods that support evaluation. #### 16.8.1 SlingFunction This class is at the top of the hierarchy of functions (see Figure 16.26). ##### Figure 16.26. The ` SlingFunction ` class. This class defines, for a large number of subclasses, the methods for evaluating and copying a function. Class ` SlingFunction ` defines ` f() ` as an abstract method and defines ` eval() ` for evaluating a function into an unvariable form. #### 16.8.2 Abs, Ceil, Cos, Floor, Sin, and Tan Each of these Sling functions wraps a routine from class ` Math ` in ` java.lang ` . Each of these functions normally takes a single number and returns a single number. To follow the Sling environment design principles, each function must find its input number by evaluating its source at a given time and then extracting the ` y ` component. The Sling functions pass this number to the appropriate ` Math ` method and get back a single number. The Sling functions augment this number, using time as the ` x ` component, to create a two-dimensional point. For example, ` Abs.f(t) ` contains the statement return new Point(t, Math.abs(source[0].f(t).y)); The other functions in the title of this section operate in the same way, each using a different function from ` Math ` . #### 16.8.3 Arithmetic This class wraps an arithmetic function around two source functions. The ` Arithmetic ` class's constructor requires a ` char ` (to indicate an operator), and two source functions. The operator must be " ` + ` ", " ` - ` ", " ` / ` ", " ` * ` ", or " ` % ` "; otherwise , ` f(t) ` of this object will always be the point ` (0, 0) ` . The value of an arithmetic function at time ` t ` is the value of the operator applied to the source functions at time ` t ` . For example, evaluating the arithmetic sum f1 + f2 at time ` t ` creates the point (f1(t).x + f2(t).x, f1(t).y + f2(t).y) #### 16.8.4 Cartesian This class combines the ` y ` component of each of two source functions to form a new two-dimensional function. This allows functions that are normally one-dimensional to combine into a two-dimensional function. For example, both ` sin ` and ` cos ` are normally one-dimensional functions, returning a single number for any given value. The classes ` Sin ` and ` Cos ` store their results in the ` y ` dimension of a function, augmenting any particular point with ` t ` as the ` x ` value. Objects of the ` Cartesian ` class ignore the ` x ` component of each source function. The ` y ` component of the first source function becomes the ` x ` component of the ` Cartesian ` function, and the ` y ` component of the second function becomes the ` y ` component of the ` Cartesian ` function. Consider the following program, which plots a circle: theta = 2*pi*t; x = cos(theta); y = sin(theta); plot cartesian(x, y); The design principles at play in ` sjm.examples.sling ` augment the ` x ` and ` y ` functions so that they are effectively ` cartesian(t, cos(theta)) ` and ` cartesian(t, sin(theta)) ` . The program recombines the ` y ` components of these functions into a new ` cartesian ` with an ` x ` value of ` cos(theta) ` and a ` y ` value of ` sin(theta). ` #### 16.8.5 Point Objects of this class store two numbers that effectively determine a point in two-dimensional space. #### 16.8.6 Polar This class represents the location of a sling stone in terms of the length of a sling's strap and the angle (in radians) around the slinger's head. The constructor accepts two source functions. The ` y ` component of the first function represents the length of the strap, and the ` y ` component of the second function represents the strap's angle. When you whirl a sling, the stone's path covers 2*pi radians of arc as the stone makes one revolution. The arc varies from 0 to 2*pi, starting in the positive ` x ` direction and rotating counterclockwise. You can use the variable ` r ` to represent the strap's length, and the variable ` theta ` to represent the strap's angle. At any point in time, then, the stone's position is polar(r, theta) This is equivalent to cartesian(r * cos(theta), r * sin(theta)) because the ` cos ` and ` sin ` functions represent the ` x ` and ` y ` components of a stone's path. Thus, the implementation of ` Polar.f() ` is public Point f(double t) { double r = source[0].f(t).y; double theta = source[1].f(t).y; return new Point( r * Math.cos(theta), r * Math.sin(theta)); } #### 16.8.7 Random Objects of this class return a random number between 0 and 1 when asked for their value. Here is the implementation of ` Random.f ` (): public Point f(double t) { return new Point(t, Math.random()); } #### 16.8.8 Scale A ` Scale ` function varies between two limits. As a plot unfolds, time varies from 0 to 1. When time is 0, the value of a ` Scale ` object is the value of its first limit. When time is 1, the value of a ` Scale ` object is the value of its second limit. For example, the Sling program plot scale(cartesian(-1, -1), cartesian(1, 1)); plots a 45-degree line from the lower-left corner to the upper-right corner. #### 16.8.9 Sling This class represents the location of a sling stone in terms of the length of a sling's strap and the speed of the stone's rotation around the slinger's head. The constructor accepts two source functions. The ` y ` component of the first function represents the length of the strap, and the ` y ` component of the second function represents the stone's angular speed. A speed of 1 represents one full rotation that occurs during the course of a plot. Here is the implementation of ` Sling.f() ` : public Point f(double t) { double r = source[0].f(t).y; double speed = source[1].f(t).y; double theta = Math.PI * 2 * speed * t; return new Point( r * Math.cos(theta), r * Math.sin(theta)); } #### 16.8.10 Slider This class holds a Swing ` JSlider ` component, returning the slider's value in its ` f(t) ` call. The slider, which this class's constructor requires, should vary from 0 to 100. This class divides that value by 100 so that the slider effectively varies from 0 to 1. The ` y ` component of the return value of ` f(t) ` ignores time and depends only on the slider value. Like all one-dimensional functions, however, this function uses time as the ` x ` component of the value it returns. #### 16.8.11 T This class represents time, which the Sling environment defines to vary from 0 to 1 as a plot unfolds. Here is the implementation of ` T.f ` (): public Point f(double t) { return new Point(t, t); } #### 16.8.12 Variable A variable is a named place that can store another function. The ` Variable ` class is a subclass of ` SlingFunction ` , which allows functions to compose themselves from other functions. During the execution phase, term objects evaluate themselves into function objects that do not contain variables . It is an error to ask a variable for ` f(t) ` because this function applies only in the drawing phase. Here is the implementation of ` Variable.f(t) ` : public Point f(double t) { throw new InternalError(); } |