/*************************************************************************
* *
* 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/ *
* *
*************************************************************************/
import java.awt.*;
import java.applet.Applet;
import java.util.StringTokenizer;
import edu.hws.jcm.draw.*;
import edu.hws.jcm.data.*;
import edu.hws.jcm.functions.*;
import edu.hws.jcm.awt.*;
/**
* An applet for exploring the epsilon-delta definition of a limit.
*/
public class EpsilonDelta extends GenericGraphApplet {
// Declare some private variables that are created in one method in
// this class and used in a second method.
private VariableInput xInput;
private VariableInput epsilonInput;
private VariableInput deltaInput;
private VariableInput limitInput;
private VariableSlider xSlider;
private VariableSlider epsilonSlider;
private VariableSlider deltaSlider;
private VariableSlider limitSlider;
private Controller subController;
private Variable xValue, limitValue;
private Function func; // The function that is graphed.
private Graph1D graph; // The graph of the function.
protected void setUpBottomPanel() {
super.setUpBottomPanel();
subController = new Controller();
mainController.add(subController);
JCMPanel inputs = new JCMPanel(3);
subController.add(inputs);
inputs.setBackground(getColorParam("PanelBackground", Color.lightGray));
if (inputPanel == null)
mainPanel.add(inputs,BorderLayout.SOUTH);
else
inputPanel.add(inputs,BorderLayout.SOUTH);
JCMPanel left = new JCMPanel(0,1,2);
JCMPanel right = new JCMPanel(0,1,2);
JCMPanel middle = new JCMPanel(0,1,2);
inputs.add(middle, BorderLayout.CENTER);
inputs.add(left, BorderLayout.WEST);
inputs.add(right, BorderLayout.EAST);
double[] a = getNumericParam("AValue");
double avalue = (a == null || a.length < 1)? 0 : a[0];
if ("yes".equalsIgnoreCase(getParameter("UseAInput","yes"))) {
xSlider = new VariableSlider();
xInput = new VariableInput();
xInput.setVal(avalue);
xSlider.setVal(avalue);
xInput.setThrowErrors(false);
subController.add(new Tie(xSlider, xInput));
xValue = xInput.getVariable();
left.add(new Label("limit at a = ",Label.RIGHT));
middle.add(xSlider);
right.add(xInput);
}
else {
xValue = new Variable();
xValue.setVal(avalue);
}
a = getNumericParam("LimitValue");
double Lvalue = (a == null || a.length < 1)? 1 : a[0];
if ("yes".equalsIgnoreCase(getParameter("UseLimitInput","yes"))) {
limitSlider = new VariableSlider();
limitInput = new VariableInput();
limitInput.setVal(Lvalue);
limitSlider.setVal(Lvalue);
limitInput.setThrowErrors(false);
subController.add(new Tie(limitSlider, limitInput));
limitValue = limitInput.getVariable();
left.add(new Label(" test limit L = ",Label.RIGHT));
middle.add(limitSlider);
right.add(limitInput);
}
else {
limitValue = new Variable();
limitValue.setVal(Lvalue);
}
a = getNumericParam("EpsilonValue");
double epsilonValue = (a == null || a.length < 1)? 0.25 : a[0];
epsilonSlider = new VariableSlider(new Constant(0), new Constant(2));
epsilonInput = new VariableInput();
epsilonInput.setVal(epsilonValue);
epsilonSlider.setVal(epsilonValue);
epsilonInput.setThrowErrors(false);
subController.add(new Tie(epsilonSlider, epsilonInput));
left.add(new Label("epsilon = ", Label.RIGHT));
middle.add(epsilonSlider);
right.add(epsilonInput);
a = getNumericParam("DeltaValue");
double deltaValue = (a == null || a.length < 1)? 1 : a[0];
deltaSlider = new VariableSlider(new Constant(0), new Constant(2));
deltaInput = new VariableInput();
deltaInput.setVal(deltaValue);
deltaSlider.setVal(deltaValue);
deltaInput.setThrowErrors(false);
subController.add(new Tie(deltaSlider, deltaInput));
left.add(new Label("delta = ", Label.RIGHT));
middle.add(deltaSlider);
right.add(deltaInput);
}
protected void setUpCanvas() { // Override this to add more stuff to the canvas.
// 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".
if (functionInput != null)
func = functionInput.getFunction(xVar);
else {
String def = getParameter("Function", "abs(" + xVar.getName() + ") ^ " + xVar.getName());
Function f = new SimpleFunction( parser.parse(def), xVar );
func = new WrapperFunction(f);
}
graph = new Graph1D(func);
graph.setColor(getColorParam("GraphColor", Color.black));
Value xMinusDelta = new ValueMath(xValue, deltaInput, '-');
Value xPlusDelta = new ValueMath(xValue, deltaInput, '+');
Value limitMinusEpsilon = new ValueMath(limitValue, epsilonInput, '-');
Value limitPlusEpsilon = new ValueMath(limitValue, epsilonInput, '+');
Value xmin = canvas.getCoordinateRect().getValueObject(CoordinateRect.XMIN);
Value xmax = canvas.getCoordinateRect().getValueObject(CoordinateRect.XMAX);
Value ymin = canvas.getCoordinateRect().getValueObject(CoordinateRect.YMIN);
Value ymax = canvas.getCoordinateRect().getValueObject(CoordinateRect.YMAX);
if (xSlider != null) {
xSlider.setMin(xmin);
xSlider.setMax(xmax);
}
if (limitSlider != null) {
limitSlider.setMin(ymin);
limitSlider.setMax(ymax);
}
DrawGeometric deltaBox = new DrawGeometric(DrawGeometric.RECT_ABSOLUTE, xMinusDelta, ymin, xPlusDelta, ymax);
deltaBox.setFillColor(new Color(225,255,225));
deltaBox.setLineWidth(0);
DrawGeometric epsilonBox = new DrawGeometric(DrawGeometric.RECT_ABSOLUTE, xmin, limitMinusEpsilon, xmax, limitPlusEpsilon);
epsilonBox.setFillColor(new Color(255,230,230));
epsilonBox.setLineWidth(0);
DrawGeometric overlap = new DrawGeometric(DrawGeometric.RECT_ABSOLUTE, xMinusDelta, limitMinusEpsilon, xPlusDelta,limitPlusEpsilon);
overlap.setFillColor(new Color(255,255,225));
overlap.setColor(Color.yellow);
DrawGeometric xLine = new DrawGeometric(DrawGeometric.LINE_ABSOLUTE, xValue, ymin, xValue, ymax);
xLine.setColor(new Color(130,255,130));
DrawGeometric limitLine = new DrawGeometric(DrawGeometric.LINE_ABSOLUTE, xmin, limitValue, xmax, limitValue);
limitLine.setColor(new Color(255,150,150));
canvas.add(deltaBox);
canvas.add(epsilonBox);
canvas.add(overlap);
canvas.add(xLine);
canvas.add(limitLine);
DrawString ds = new DrawString("a = #\nL = #\nf(a) = #", DrawString.TOP_LEFT,
new Value[] { xValue, limitValue, new ValueMath(func,xValue) });
ds.setBackgroundColor(Color.white);
ds.setFrameWidth(1);
subController.add(ds);
subController.add(deltaBox);
subController.add(epsilonBox);
subController.add(overlap);
subController.add(xLine);
subController.add(limitLine);
mainController.remove(canvas);
mainController.add(graph);
canvas.getCoordinateRect().setOnChange(mainController);
deltaSlider.setOnUserAction(subController);
epsilonSlider.setOnUserAction(subController);
deltaInput.setOnTextChange(subController);
epsilonInput.setOnTextChange(subController);
subController.add(deltaSlider);
subController.add(epsilonSlider);
subController.add(deltaInput);
subController.add(epsilonInput);
if (xInput != null) {
xSlider.setOnUserAction(subController);
xInput.setOnTextChange(subController);
subController.add(xSlider);
subController.add(xInput);
}
if (limitInput != null) {
limitSlider.setOnUserAction(subController);
limitInput.setOnTextChange(subController);
subController.add(limitSlider);
subController.add(limitInput);
}
super.setUpCanvas(); // Do the common setup: Add the axes, grid, etc
canvas.add(graph);
canvas.add(ds);
} // 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.
// After the function definition, there can be a semicolon and
// up to ten numbers (numbers can be separated by spaces and/or commas).
// The first four numbers specify the limits on the coordinate rect.
// .
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 limitsText = example.substring(pos+1);
example = example.substring(0,pos);
StringTokenizer toks = new StringTokenizer(limitsText, " ,");
double nums[] = new double[toks.countTokens()];
for (int i = 0; i < nums.length; i++) {
try {
nums[i] = (new Double(toks.nextToken())).doubleValue();
}
catch (Exception e) {
nums[i] = Double.NaN;
}
}
for (int i = 0; i < 4; i++)
if (nums.length >= i && !Double.isNaN(nums[i]))
limits[i] = nums[i];
if (nums.length > 4 && !Double.isNaN(nums[4]))
xValue.setVal( nums[4] );
else
xValue.setVal((limits[0]+limits[1])/2);
if (nums.length > 5 && !Double.isNaN(nums[5]))
limitValue.setVal( nums[5] );
else
limitValue.setVal((limits[0]+limits[1])/2);
if (nums.length > 8 && !Double.isNaN(nums[8]))
epsilonSlider.setMax( new Constant(nums[8]) );
else
epsilonSlider.setMax(new Constant(Math.abs(limits[2]-limits[3])/2));
if (nums.length > 9 && !Double.isNaN(nums[9]))
deltaSlider.setMax( new Constant(nums[9]) );
else
deltaSlider.setMax(new Constant(Math.abs(limits[0]-limits[1])/2));
if (nums.length > 6 && !Double.isNaN(nums[6])) {
epsilonInput.setVal( nums[6] );
epsilonSlider.setVal( nums[6] );
}
else {
epsilonInput.setVal(Math.abs(limits[2]-limits[3])/8);
epsilonSlider.setVal(Math.abs(limits[2]-limits[3])/8);
}
if (nums.length > 7 && !Double.isNaN(nums[7])) {
deltaInput.setVal( nums[7] );
deltaSlider.setVal( nums[7] );
}
else {
deltaInput.setVal(Math.abs(limits[0]-limits[1])/8);
deltaSlider.setVal(Math.abs(limits[0]-limits[1])/8);
}
}
// 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.
// Also, in this case, func is a "WrapperFunction". Set the
// definition of that WrapperFunction to be the same as f
try {
Function f = new SimpleFunction( parser.parse(example), xVar );
((WrapperFunction)func).setFunction(f);
}
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 EpsilonDelta();
app.init();
f.getContentPane().add (app);
f.pack();
f.setSize (new Dimension (500, 500));
f.setVisible(true);
}
} // end class EpsilonDelta
|