[ prev | main | next ]

Secant and Tangent Lines Applet



This applet shows the graph of a function along with a tangent line at a point on the graph and a secant line to another point on the graph. You can move either point by dragging it with your mouse or by entering a new value for the x-coordinate in one of the input boxes at the bottom of the applet. The input boxes give finer control over the x-coordinates of the points, while dragging the points is more dynamic.

(The "points" in this applet belong to the class DraggablePoint in the package edu.hws.jcm.draw. Note that if you drag one of the points off the graph of the function, it becomes a lighter-colored "ghost" of itself that can later be dragged back onto the graph. Similarly, if the value of the function at a given x-coordinate puts the point outside the canvas, it will be drawn as a "ghost" at the edge of the canvas.)

The following source code shows how the applet is built from WCM components:



import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Insets;

import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JPanel;

import net.sourceforge.webcompmath.awt.ComputeButton;
import net.sourceforge.webcompmath.awt.Controller;
import net.sourceforge.webcompmath.awt.ExpressionInput;
import net.sourceforge.webcompmath.awt.Tie;
import net.sourceforge.webcompmath.awt.Tieable;
import net.sourceforge.webcompmath.awt.VariableInput;
import net.sourceforge.webcompmath.data.Function;
import net.sourceforge.webcompmath.data.Parser;
import net.sourceforge.webcompmath.data.Value;
import net.sourceforge.webcompmath.data.ValueMath;
import net.sourceforge.webcompmath.data.Variable;
import net.sourceforge.webcompmath.draw.CoordinateRect;
import net.sourceforge.webcompmath.draw.DisplayCanvas;
import net.sourceforge.webcompmath.draw.DraggablePoint;
import net.sourceforge.webcompmath.draw.DrawGeometric;
import net.sourceforge.webcompmath.draw.DrawString;
import net.sourceforge.webcompmath.draw.Graph1D;
import net.sourceforge.webcompmath.draw.Grid;
import net.sourceforge.webcompmath.draw.LimitControlPanel;
import net.sourceforge.webcompmath.draw.TangentLine;
import net.sourceforge.webcompmath.draw.WcmAxes;

/**
* This applet is an example of how to use WCM.
*/
public class SecantTangentApplet extends JApplet {

private static final long serialVersionUID = 6469351577377411521L;

DisplayCanvas canvas;

/**
* Overrides init() in JApplet to set up the applet.
*
* @see java.applet.Applet#init()
*/
public void init() {

// Create the parser to parse function definitions.
Parser parser = new Parser();
Variable x = new Variable("x");
parser.add(x);

// Create the basic input elements.
ComputeButton computeButton = new ComputeButton("New Function");

// x-coord where tangent line is drawn.
VariableInput x1Input = new VariableInput();
// x-coord for other point of secant line.
VariableInput x2Input = new VariableInput();

ExpressionInput input = new ExpressionInput(" sqrt(x)", parser);
Function func = input.getFunction(x);

Graph1D graph = new Graph1D(func);
graph.setColor(Color.black);

/*
* Create two DraggablePoint objects, which will be the points on the
* canvas that the user can drag. The x-coordinate of drag1 will be tied
* later to x1Input, so that either drag1 or x1Input can be used for
* setting the values of the point. Same for drag2 and x2Input.
*/
// point where tangent is drawn
DraggablePoint drag1 = new DraggablePoint();
// other point on secant line
DraggablePoint drag2 = new DraggablePoint();

// Both points are clamped to move along the function.
drag1.clampY(func);
drag2.clampY(func);

/*
* Set locations, but the y-coords will be reset according to the
* clamping specified above.
*/
drag1.setLocation(1.0D, 0.0D);
drag2.setLocation(3.0D, 0.0D);

// drag1 is red...
drag1.setColor(Color.red);
// but is shown in pink if it's off the graph
drag1.setGhostColor(Color.pink);

// drag2 is green...
drag2.setColor(new Color(0, 200, 0));
// or light green if off the graph.
drag2.setGhostColor(new Color(180, 225, 180));

// Create the tangent line and the secant line through 2 points.
DrawGeometric secant = new DrawGeometric(
DrawGeometric.INFINITE_LINE_ABSOLUTE, drag1.getXVar(), drag1
.getYVar(), drag2.getXVar(), drag2.getYVar());
secant.setColor(new Color(0, 200, 0));
TangentLine tangent = new TangentLine(drag1.getXVar(), func);
tangent.setColor(Color.red);

/*
* Create a DrawString to display the slopes of the tangent and secant.
* (Note how the ValueMath class is used to create Value objects that
* compute the slopes.)
*/
Value tangentSlope = new ValueMath(func.derivative(1), drag1.getXVar());
Value secantSlope = new ValueMath(new ValueMath(drag2.getYVar(), drag1
.getYVar(), '-'), new ValueMath(drag2.getXVar(), drag1
.getXVar(), '-'), '/');
DrawString info = new DrawString(
"Tangent Slope = #\n Secant Slope = #", DrawString.TOP_LEFT,
new Value[] { tangentSlope, secantSlope });
info.setFont(new Font("Monospaced", Font.PLAIN, 10));
// Text area is filled with this color before the text is drawn.
info.setBackgroundColor(Color.lightGray);
/*
* If the frame width is greater than 0, then a frame of this width is
* drawn around the text.
*/
info.setFrameWidth(1);

/*
* Create the canvas and limit control panel, and add all the visible
* objects to the canvas.
*/
canvas = new DisplayCanvas(new CoordinateRect(-1, 5, -1, 3));
LimitControlPanel limits = new LimitControlPanel(
LimitControlPanel.SET_LIMITS | LimitControlPanel.RESTORE
| LimitControlPanel.EQUALIZE
| LimitControlPanel.ZOOM_IN
| LimitControlPanel.ZOOM_OUT, false);
limits.addCoords(canvas);
limits.setBackground(Color.lightGray);
limits.setErrorReporter(canvas);

/*
* A grid of horizontal and vertical lines. (This needs to be behind the
* axes.).
*/
canvas.add(new Grid());
canvas.add(new WcmAxes());
canvas.add(drag1);
canvas.add(drag2);
canvas.add(tangent);
canvas.add(secant);
canvas.add(graph);
canvas.add(info);

/*
* Lay out the components in the applet. Since I use Janels and not
* WcmPanels, I have to set up the controllers by hand.
*/
JPanel bottom = new JPanel();
bottom.setLayout(new BorderLayout(3, 3));
JPanel funcPanel = new JPanel();
funcPanel.setBackground(Color.lightGray);
funcPanel.setLayout(new BorderLayout(3, 3));
funcPanel.add(input, BorderLayout.CENTER);
funcPanel.add(computeButton, BorderLayout.EAST);
funcPanel.add(new JLabel(" f(x) = "), BorderLayout.WEST);
bottom.add(funcPanel, BorderLayout.NORTH);
JPanel xInputPanel = new JPanel();
xInputPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
xInputPanel.setBackground(Color.lightGray);
xInputPanel.add(new JLabel("Tangent at x = "));
xInputPanel.add(x1Input);
xInputPanel.add(new JLabel(" Secant to x = "));
xInputPanel.add(x2Input);
bottom.add(xInputPanel, BorderLayout.CENTER);

setLayout(new BorderLayout(3, 3));
setBackground(Color.darkGray);
add(canvas, BorderLayout.CENTER);
add(limits, BorderLayout.EAST);
add(bottom, BorderLayout.SOUTH);

/*
* Set up Controllers for the applet. This is essential for making the
* applet active. I use two controllers -- graphControl, which
* recomputes everything when the definition of the function is changed,
* and dragControl, which only recomputes stuff that relates to the
* tangent line and secant line.
*/
Controller graphControl = new Controller();
Controller dragControl = new Controller();

// graphControl checks the function input box.
graphControl.add(input);
// It will recompute the graph.
graphControl.add(graph);
// It will also tell dragControl to do its stuff.
graphControl.add(dragControl);

/*
* graphControl.compute() is called when the user hits return in the
* function input.
*/
input.setOnUserAction(graphControl);
/*
* It is also called when the user hits the compute button.
*/
computeButton.setOnUserAction(graphControl);

/*
* Errors that occur when graphControl.compute() is running are reported
* on the canvas.
*/
graphControl.setErrorReporter(canvas);

/*
* dragControl checks the contents of the x-inputs and recomputes
* everything except the graph.
*/
dragControl.add(x1Input);
dragControl.add(x2Input);
dragControl.add(drag1);
dragControl.add(drag2);
dragControl.add(tangent);
dragControl.add(secant);
dragControl.add(info);

/*
* dragControl.compute() is called when the user drags one of the points
* or types in one of the x-input boxes.
*/
drag1.setOnUserAction(dragControl);
drag2.setOnUserAction(dragControl);
x1Input.setOnTextChange(dragControl);
x2Input.setOnTextChange(dragControl);

/*
* By adding Tie's to dragControl, we make sure that the positions of
* the draggable points are synchronized with the contents of the
* x-input boxes.
*/
dragControl.add(new Tie((Tieable) drag1.getXVar(), x1Input));
dragControl.add(new Tie((Tieable) drag2.getXVar(), x2Input));

} // end init()

/**
* @see java.awt.Container#getInsets()
*/
public Insets getInsets() {
// Set up a three-pixel border between the edges of the applet and its
// contents.
return new Insets(3, 3, 3, 3);
}

} // end class SecantTangentApplet



[ prev | main | next ]