import java.awt.*; /** Program: QuadraticLagrange17 Purpose: interpolate quadratic curves through 3 points @author: Paul Garrett, garrett@math.umn.edu @version: 17, Wed Jan 15 21:58:00 CST 1997 */ public class QuadraticLagrange17 extends java.applet.Applet { float quadraticCoefficient, linearCoefficient, constantCoefficient; float[] xcoord, ycoord; // points to interpolate int theWidth, theHeight; // of applet area: use only 90%?! float xMin, xMax, yMin, yMax; // in native numbers int numberSubintervals; // for xcoord float[] yValues; int[] yIntValues; // renormalized int-ized versions int[] xIntValues; // ditto int numberHandles; // number points to interpolate... e.g., 2 boolean queryMouseDown; // true if down, etc. int theIndex; // of point picked-up by mouse int inc; // size of handles float inf; // lower bound for distance apart of roots... float margin; // margin... Image offScreenImage; // for double-buffering Graphics offScreenGraphics; // ditto /* Above are all the instance variables.... */ public void init() { add(new Button("Rescale to fit the screen")); theWidth = this.size().width; theHeight = this.size().height; queryMouseDown = false; inc = 5; inf = (float) .01; margin = (float) .08; // rather than .05 offScreenImage = createImage(theWidth, theHeight); offScreenGraphics = offScreenImage.getGraphics(); // standard... numberSubintervals = 30; yValues = new float[numberSubintervals + 1]; yIntValues = new int[numberSubintervals + 1]; xIntValues = new int[numberSubintervals + 1]; numberHandles = 3; // for quadratic curves xMin = (float) -1; xMax = (float) 3; xcoord = new float[numberHandles]; ycoord = new float[numberHandles]; xcoord[0] = (float) 0; ycoord[0] = (float) -1; xcoord[1] = (float) 1; ycoord[1] = (float) 0; xcoord[2] = (float) 2; ycoord[2] = (float) 3; computeValues(); // gives new equation computeScalingMaps(); computeIntValues(); repaint(); } void computeCoefficients() { // watch out for division by zero float denom2 = (xcoord[2] - xcoord[1])*(xcoord[2] - xcoord[0]); float denom1 = (xcoord[1] - xcoord[0])*(xcoord[1] - xcoord[2]); float denom0 = (xcoord[0] - xcoord[1])*(xcoord[0] - xcoord[2]); if (Math.abs(denom0) < inf || Math.abs(denom1) < inf || Math.abs(denom2) < inf ) { } // Do nothing if the numbers are too close together... else { quadraticCoefficient = ycoord[0]/denom0 + ycoord[1]/denom1 + ycoord[2]/denom2; linearCoefficient = - ( ycoord[0] * (xcoord[1] + xcoord[2])/denom0 + ycoord[1] * (xcoord[0] + xcoord[2])/denom1 + ycoord[2] * (xcoord[0] + xcoord[1])/denom2 ); constantCoefficient = ycoord[0] * xcoord[1] * xcoord[2]/denom0 + ycoord[1] * xcoord[0] * xcoord[2]/denom1 + ycoord[2] * xcoord[0] * xcoord[1]/denom2 ; } // recompute coefficients only if denominators are not // ridiculously small } float theFunction(float in) { float out = in * quadraticCoefficient + linearCoefficient; out = out * in + constantCoefficient; return out; } void computeValues() { // computes values computeCoefficients(); float tmp; for (int i = 0; i <= numberSubintervals; i++) { yValues[i] = theFunction(xMin + i * (xMax - xMin) /numberSubintervals); } } void computeIntValues() { for (int i = 0; i <= numberSubintervals; i++) { yIntValues[i] = yScale(yValues[i]); xIntValues[i] = (int) (margin * theWidth + i * ((1-2*margin) * theWidth) /((float) numberSubintervals)); } } void computeScalingMaps() { // finds yMax, yMin, etc. yMin = 0; yMax = 0; float tmp; for (int i = 0; i <= numberSubintervals; i++) { if (yValues[i] > yMax) { yMax = yValues[i]; } else if (yValues[i] < yMin) { yMin = yValues[i]; } } } public boolean action(Event e, Object arg) { if (e.target instanceof Button) { computeScalingMaps(); // will already have values... computeIntValues(); repaint(); } return true; } int xScale(float in) { int out = (int) (margin * theWidth + (in - xMin) * ((1-2*margin) * theWidth) /((float) (xMax - xMin))); return out; } int yScale(float in) { float tmp = (float) (margin * theHeight + (in - yMin) * ((1-2*margin) * theHeight) /((float) (yMax - yMin))); int out = theHeight - (int) tmp; // turn it upside-down return out; } float xUnScale(int in) { // map from integer back to native float out; out = ((float) in) - (float) (margin * theWidth); out = (float) (out / ((1-2*margin) * theWidth)); out = xMin + out * (xMax - xMin); return out; } float yUnScale(int in) { // map from integer back to native float out; out = (float)(in) - (float) (margin * theHeight); out = (float) (out /((1-2*margin) * theHeight)); out = yMax - out * (yMax - yMin); return out; } public void update(Graphics g) { // over-ride: don't clear the screen paint(g); } void drawAxes(Graphics g) { // depends upon xMax, yMax, and the xScale, yScale... g.fillRect(xScale(xMin), yScale(0), xScale(xMax)-xScale(xMin), 2); // x-axis g.fillRect(xScale(0), yScale(yMax), 2, yScale(yMin) - yScale(yMax)); // y-axis g.drawLine(xScale(xMax), yScale(0), xScale(xMax) - 7, yScale(0) - 3); g.drawLine(xScale(xMax), yScale(0)+1, xScale(xMax) - 7, yScale(0) + 4); // was arrowhead on x-axis g.drawLine(xScale(0), yScale(yMax), xScale(0) - 3, yScale(yMax) + 7); g.drawLine(xScale(0)+1, yScale(yMax), xScale(0) + 4, yScale(yMax) + 7); } void drawHandles(Graphics g) { for (int i=0; i < numberHandles; i++) { g.fillRect(xScale(xcoord[i])-inc, yScale(ycoord[i])-inc, 2 * inc + 1, 2 * inc + 1); } } public boolean mouseDrag(Event e, int x, int y) { if (queryMouseDown == true) { xcoord[theIndex] = xUnScale(x); ycoord[theIndex] = yUnScale(y); computeValues(); computeIntValues();// NB without rescaling... repaint(); } return true; } public boolean mouseUp(Event e, int x, int y) { if (queryMouseDown) { queryMouseDown = false; } return true; } public boolean mouseDown(Event e, int x, int y) { if ((Math.abs(x-xScale(xcoord[0])) <= inc) && (Math.abs(y-yScale(ycoord[0])) <= inc)) { queryMouseDown = true; theIndex = 0; } else if ((Math.abs(x-xScale(xcoord[1])) <= inc) && (Math.abs(y-yScale(ycoord[1])) <= inc)) { queryMouseDown = true; theIndex = 1; } else if ((Math.abs(x-xScale(xcoord[2])) <= inc) && (Math.abs(y-yScale(ycoord[2])) <= inc)) { queryMouseDown = true; theIndex = 2; } return true; } public void paint(Graphics g) { String str = new String("The equation is y = "); offScreenGraphics.setColor(Color.white); offScreenGraphics.fillRect(0,0,theWidth,theHeight); offScreenGraphics.setColor(Color.black); for (int i=0; i <= (numberSubintervals-1) ; i++) { offScreenGraphics.drawLine(xIntValues[i], yIntValues[i], xIntValues[i+1], yIntValues[i+1]); } drawAxes(offScreenGraphics); // see above drawHandles(offScreenGraphics); // see above str += "(" + quadraticCoefficient + ") * x^2 + "; str += "(" + linearCoefficient + ") * x + "; str += "(" + constantCoefficient + ")"; offScreenGraphics.drawString(str, 10, theHeight - 2); // aesthetic choice g.drawImage(offScreenImage, 0, 0, this); } } // the end