import java.awt.*; /** Program: TraceTangent Purpose: animation: trace all tangent lines to curve @author: Paul Garrett, garrett@math.umn.edu @version: Wed, 09 July 1997 */ public class TraceTangent extends java.applet.Applet implements Runnable { Thread timerThread; Graphics offScreenGraphics; Image offScreenImage; final int height = 320; final int width = 550; final int drawHeight = 310; final int drawWidth = 450; final int inset = 5; final int inc = 4; final int range = 110; // want inc * range = 450 or so final int xaxInset = 50; // inset of x-axis from bottom, in PIXELS final int yaxInset = 50; // inset of y-axis from left of drawing area, ... PIXELS double x, y, x0, y0; int t, t0, t1; // t0 is begin, t1 is end, t is variable // final double[] theCoefficients = {0.0, 1.0, 0.0, 0.0, 0.0}; /* theCoefficients are in ascending order */ final double[] theCoefficients = {0.2, 1.5, -6.25, 8.75, -5.0, 1.0}; final double scale = 5.0; final int degree = 5; /**************/ // final String theURL = "http://www.math.umn.edu/~garrett/qy/TraceTangent.html"; // final boolean restrictAccess = true; // switch restrictions on URL /*******************************/ public void init() { // if (! restrictAccess || // this.getDocumentBase().toString().equals(theURL)) { offScreenImage = createImage(width,height); // } // else { // offScreenImage = createImage(30,30); // } offScreenGraphics = offScreenImage.getGraphics(); t0 = 0; t1 = 110; } public void start() { if (timerThread == null) { timerThread = new Thread(this); timerThread.start(); } repaint(); } public void stop() { if (timerThread != null) { timerThread.stop(); try { timerThread.join(); } catch (InterruptedException e) { } timerThread = null; } } void pause(int time) { try { Thread.sleep(time); } catch ( InterruptedException e) { } } public void run() { while (true) { if (t < t1) { pause(100); t++; repaint(); } else { pause(500); t = t0; repaint(); pause(500); } } } public void update(Graphics g) { paint(g); } /************************************************/ void drawAxes(Graphics g) { g.setColor(Color.black); g.fillRect(inset, drawHeight + inset - xaxInset, drawWidth, 2); // x-axis int[] xs = {inset + drawWidth + 2, inset + drawWidth - 10, inset + drawWidth - 6, inset + drawWidth - 10}; int[] ys = {drawHeight +inset - xaxInset, drawHeight+inset - xaxInset-6, drawHeight +inset- xaxInset, drawHeight+inset - xaxInset+6}; g.fillPolygon(new Polygon(xs, ys, 4)); // arrowhead on x-axis g.fillRect(inset+yaxInset-1, inset, 2, drawHeight); // y-axis int[] xs2 = {yaxInset+inset, yaxInset+inset - 6, yaxInset+inset, yaxInset+inset + 6}; int[] ys2 = {inset - 2, inset + 10, inset + 6, inset + 10}; g.fillPolygon(new Polygon(xs2, ys2, 4)); // arrowhead on y-axis } /********************************************************/ double theFunction(double x) { // should roughly map -0.5 < x < 2.5 // to -0.5 < y < 2.5 double out = 0.0; for (int i=degree; i>0; i--) { out = (out + theCoefficients[i]) * x; } out += theCoefficients[0]; out *= scale; return out; } double theDerivative(double x) { double out = 0.0; for (int i=degree; i>0; i--) { out = out * x + ((double) i) * theCoefficients[i]; } out *= scale; return out; } int xToPix (double x) { // rescales -1 < x < 2 to ... return (int) (x * ((double) drawWidth - yaxInset) / 2.0) + inset + yaxInset; } int yToPix (double y) { // rescales [-1,2] to ... return drawHeight + inset - xaxInset - (int) ( y * ((double) drawHeight - xaxInset) / 2.0); } double tToX (int t) { // rescales [0,range] to [-1,2] return ((double) (t * inc - yaxInset)) * 2.0 / ((double) drawWidth -yaxInset); } void drawCurve(Graphics g) { g.setColor(Color.red); for (int i=0; i<= range; i++) { g.drawLine(xToPix(tToX(i)), yToPix(theFunction(tToX(i))), xToPix(tToX(i+1)), yToPix(theFunction(tToX(i+1)))); } g.setColor(Color.red); for (int i=0; i<= range; i++) { g.drawLine(xToPix(tToX(i)), yToPix(theFunction(tToX(i))) - 1, xToPix(tToX(i+1)), yToPix(theFunction(tToX(i+1))) - 1); } } void drawTangent(Graphics g) { // depends on the global vble 't' g.setColor(Color.white); double r = ((double)(drawHeight - xaxInset)) / ((double) drawWidth - yaxInset); double m = theDerivative(tToX(t)); double ell = 0.4/Math.sqrt(1.0+m*m*r*r); g.drawLine( xToPix(tToX(t) - ell), yToPix(theFunction(tToX(t)) - m * ell), xToPix(tToX(t) + ell), yToPix(theFunction(tToX(t)) + m * ell)); g.setColor(Color.black); g.fillOval(xToPix(tToX(t))-2, yToPix(theFunction(tToX(t)))-2, 6, 6); } /*****************************************************/ void drawOffScreen() { offScreenGraphics.setColor(Color.gray); offScreenGraphics.fillRect(0,0,width,height); offScreenGraphics.setColor(Color.black); drawAxes(offScreenGraphics); drawCurve(offScreenGraphics); drawTangent(offScreenGraphics); } public void paint(Graphics g) { drawOffScreen(); g.drawImage(offScreenImage,0,0,this); } } //__THE__END__