[ 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 JCM components:




import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import edu.hws.jcm.data.*;
import edu.hws.jcm.draw.*;
import edu.hws.jcm.awt.*;

public class SecantTangentApplet  extends Applet {

   DisplayCanvas canvas;  // (Defined here so it can be used in the stop() method.)
   

   public void stop() {
        // When applet is stopped, release the memory used for double-buffering of the canvas.
      canvas.releaseResources();
   }
   

   public void init() {  // The init() method sets up the applet.
         
      // 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");

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

      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.
      
      DraggablePoint drag1 = new DraggablePoint();  // point where tangent is drawn
      DraggablePoint drag2 = new DraggablePoint();  // other point on secant line
      
      drag1.clampY(func);   // Both points are clamped to move along the function.
      drag2.clampY(func);
      
      drag1.setLocation(1,0);  // Set locations, but the y-coords will be reset
      drag2.setLocation(3,0);  //       according to the clamping specified above.
      
      drag1.setColor(Color.red);        // drag1 is red...
      drag1.setGhostColor(Color.pink);  //   but is shown in pink if it's off the graph
      
      drag2.setColor(new Color(0,200,0));           // drag2 is green...
      drag2.setGhostColor(new Color(180,225,180));  //    or light green if off the graph.


      // Create the tangent line and the secant line.  

      DrawGeometric secant = new DrawGeometric(DrawGeometric.INFINITE_LINE_ABSOLUTE,  
                                      drag1.getXVar(), drag1.getYVar(), 
                                      drag2.getXVar(), drag2.getYVar());  // line through 2 points
      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));
      info.setBackgroundColor(Color.lightGray);  /// Text area is filled with this color
                                                 /// before the text is drawn.
      info.setFrameWidth(1);  /// If the frame width is greater than 0, then a frame of this
                              /// width is drawn around the text.
      

      // 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);
      
      canvas.add(new Grid());  // A grid of horizontal and vertical lines.
                               // (This needs to be behind the axes.).
      canvas.add(new Axes());
      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 Panels
      // and not JCMPanels, I have to set up the conrollers by hand.
      
      Panel bottom = new Panel();
      bottom.setLayout(new BorderLayout(3,3));
      Panel funcPanel = new Panel();
      funcPanel.setBackground(Color.lightGray);
      funcPanel.setLayout(new BorderLayout(3,3));
      funcPanel.add(input, BorderLayout.CENTER);
      funcPanel.add(computeButton, BorderLayout.EAST);
      funcPanel.add(new Label(" f(x) = "), BorderLayout.WEST);
      bottom.add(funcPanel,BorderLayout.NORTH);
      Panel xInputPanel = new Panel();
      xInputPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
      xInputPanel.setBackground(Color.lightGray);
      xInputPanel.add(new Label("Tangent at x = "));
      xInputPanel.add(x1Input);
      xInputPanel.add(new Label("  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.add(input);       // graphControl checks the function input box.
      graphControl.add(graph);       // It will recompute the graph.
      graphControl.add(dragControl); // It will also tell dragControl to do its stuff.
      
      input.setOnUserAction(graphControl);         // graphControl.compute() is called when the
                                                   //    user hits return in the function input.
      computeButton.setOnUserAction(graphControl); // It is also called when the user hits
                                                   //    the compute button.
                                                   
      graphControl.setErrorReporter(canvas);  // Errors that occur when graphControl.compute() is
                                              //    running are reported on the canvas.
      
      dragControl.add(x1Input);  // dragControl checks the contents of the x-inputs
      dragControl.add(x2Input);  //    and recomputes everything except the graph.
      dragControl.add(drag1);
      dragControl.add(drag2);
      dragControl.add(tangent);
      dragControl.add(secant);
      dragControl.add(info);

      drag1.setOnUserAction(dragControl);     // dragControl.compute() is called when the
      drag2.setOnUserAction(dragControl);     //    user drags one of the points or types
      x1Input.setOnTextChange(dragControl);   //    in one of the x-input boxes.
      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()


   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 ]