/* * This is the CurvePanel class for the Famous Curves applet. * Author: Ben Soares < bs@st-and.ac.uk > * */ import java.awt.*; import java.applet.*; public class CurvePanel extends Panel { // class variable static Color darkGreen; // member variables int pointstage; //stage at which a chosen point is (0=no point chosen, 1=point chosen) int pointX, pointY; //chosen point position int circlestage; //stage at which a chosen circle is (0=no circle chosen, 1=choosing radius, 2=dragging circle) int circleX, circleY, circleCX, circleCY, circleR; //chosen circle centre position, circumference point, and radius int associatedcurveindex; //which associated curve option is selected /* (0=None, 1=Evolute, 2=Involute, 3=Inverse, 4=Pedal, * 5=Negative Pedal, 6=Caustic, 7=Caustic (parallel lines)) */ int associatedcurve[][]; //the pixel points of the associated curve Curve curve; //the curve being dealt with boolean setaxis; //have Curves class variables been set? boolean clear; //do you want to clear the curvepanel picture? double a, b, c, d, e, f, h, k, m, n, p;// the curves original parameter values int steps = 1; // how many steps to take at each line plot of curve // CurvePanel constructor methods public CurvePanel(Curve curve, int associatedcurveindex) { setBackground(Color.white); this.setaxis = false; this.curve = curve; Font font = new Font("Helvetica", Font.PLAIN, 12); setFont(font); // Label label = new Label(curve.name, Label.CENTER); // add(label); this.pointstage = 0; this.circlestage = 0; this.pointX = 0; this.pointY = 0; this.circleX = 0; this.circleY = 0; this.circleCX = 0; this.circleCY = 0; this.circleR = 0; this.associatedcurveindex = associatedcurveindex; this.clear = false; darkGreen = new Color(0,140,0); } public CurvePanel(Curve curve){ setBackground(Color.white); this.setaxis = false; int xsc = (int)(size().width/(curve.xrange*(3/2))); int ysc = (int)(size().height/(curve.yrange*(3/2))); int sc = Math.min(xsc, ysc); Curve.xsc = sc; Curve.ysc = sc; Curve.Ox = (int)(curve.xb*Curve.xsc*(-3/2)); Curve.Oy = (int)(curve.yt*Curve.xsc*(3/2)); Curve.xsize = size().width; Curve.ysize = size().height; this.curve = curve; Font font = new Font("Helvetica", Font.PLAIN, 14); setFont(font); // Label label = new Label(curve.name, Label.CENTER); // add(label); this.pointstage = 0; this.circlestage = 0; this.pointX = 0; this.pointY = 0; this.circleX = 0; this.circleY = 0; this.circleCX = 0; this.circleCY = 0; this.circleR = 0; this.associatedcurveindex = 0; this.clear = false; darkGreen = new Color(0,140,0); } /* end of constructor methods */ // recalculate associated curve method (for scales and translations) public void recalculate() { switch (associatedcurveindex) { case 0: // "None" break; case 1: // "Evolute" this.associatedcurve = curve.evolutePixels(); break; case 2: // "Involute" this.associatedcurve = curve.involutePixels(pointX, pointY); break; case 3: // "Inverse" this.associatedcurve = curve.inversePixels(circleX, circleY, circleCX, circleCY); break; case 4: // Pedal this.associatedcurve = curve.pedalPixels(pointX, pointY); break; case 5: // Negative pedal this.associatedcurve = curve.negativePedalPixels(pointX, pointY); break; case 6: // Caustic this.associatedcurve = curve.causticPixels(pointX, pointY); break; case 7: // Caustic (parallel lines) this.associatedcurve = curve.causticPixels(pointX, pointY, new String("parallel")); break; } this.pointX = Curve.xPointToPixel(Curve.xPixelToPoint(pointX)); this.pointY = Curve.yPointToPixel(Curve.yPixelToPoint(pointY)); this.circleX = Curve.xPointToPixel(Curve.xPixelToPoint(circleX)); this.circleY = Curve.yPointToPixel(Curve.yPixelToPoint(circleY)); this.circleCX = Curve.xPointToPixel(Curve.xPixelToPoint(circleCX)); this.circleCY = Curve.yPointToPixel(Curve.yPixelToPoint(circleCY)); this.circleR = (int)(Math.sqrt((circleCX-circleX)*(circleCX-circleX) + (circleCY-circleY)*(circleCY-circleY))); } /* end of recalculate method */ // beginning of scale method public void scale (double f) { this.pointX = Curve.xPointToPixel(f*Curve.xPixelToPoint(this.pointX)); this.pointY = Curve.yPointToPixel(f*Curve.yPixelToPoint(this.pointY)); this.circleX = Curve.xPointToPixel(f*Curve.xPixelToPoint(this.circleX)); this.circleY = Curve.yPointToPixel(f*Curve.yPixelToPoint(this.circleY)); this.circleCX = Curve.xPointToPixel(f*Curve.xPixelToPoint(this.circleCX)); this.circleCY = Curve.yPointToPixel(f*Curve.yPixelToPoint(this.circleCY)); this.circleR = (int)(Math.sqrt((circleCX-circleX)*(circleCX-circleX)+(circleCY-circleY)*(circleCY-circleY))); } /* end of scale method */ // beginning of translate method public void translate (int xt, int yt) { this.pointX = this.pointX + xt; this.pointY = this.pointY + yt; this.circleX = this.circleX + xt; this.circleY = this.circleY + yt; this.circleCX = this.circleCX + xt; this.circleCY = this.circleCY + yt; } /* end of translate method */ // beginning of setParameters method public void setParameters(double a, double b, double c, double d, double e, double f, double h, double k, double m, double n, double p) { this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; this.h = h; this.k = k; this.m = m; this.n = n; this.p = p; } /* end of setParameters method */ // beginning of resetCurveParameters method public void resetCurveParameters() { this.curve.a = this.a; this.curve.b = this.b; this.curve.c = this.c; this.curve.d = this.d; this.curve.e = this.e; this.curve.f = this.f; this.curve.h = this.h; this.curve.k = this.k; this.curve.m = this.m; this.curve.n = this.n; this.curve.p = this.p; } /* end of resetCurveParameters method */ // mousedown method public boolean mouseDown(Event e, int mx, int my) { switch (associatedcurveindex) { case 0: // "None" break; case 1: // "Evolute" // note this should be drawn from when it is chosen break; case 2: // "Involute" pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.involutePixels(pointX, pointY); repaint(); break; case 3: // "Inverse" boolean redraw = true; double mR = Math.sqrt( (mx-circleX)*(mx-circleX) + (my-circleY)*(my-circleY) ); // mouse distance from centre switch (circlestage) { case 0: // no circle yet circleX = mx; circleY = my; circleCX = mx; circleCY = my; circleR = 2; circlestage = 1; break; case 1: // after choosing radius if ( circleR-1 < mR && mR < circleR+2 ) { // if mouse is "on" circumference circleCX = mx; circleCY = my; circleR = (int)(mR); circlestage = 1; redraw = false; } else if ( mR < 4 ) { // if mouse is "on" centre circleX = mx; circleY = my; circlestage = 2; redraw = false; } else { // otherwise start new circle circleX = mx; circleY = my; circleCX = mx; circleCY = my; circleR = 2; circlestage = 1; } break; case 2: // after dragging circle (same as after choosing radius) if ( circleR-2 < mR && mR < circleR+3 ) { // if mouse is "on" circumference circleCX = mx; circleCY = my; circleR = (int)(mR); circlestage = 1; redraw = false; } else if ( mR < 3 ) { // if mouse is "on" centre circleX = mx; circleY = my; circlestage = 2; redraw = false; } else { // otherwise start new circle circleX = mx; circleY = my; circleCX = mx; circleCY = my; circleR = 2; circlestage = 1; } break; } associatedcurve = curve.inversePixels(circleX, circleY, circleCX, circleCY); if (redraw) { repaint(); } break; case 4: // Pedal pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.pedalPixels(pointX, pointY); repaint(); break; case 5: // Negative pedal pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.negativePedalPixels(pointX, pointY); repaint(); break; case 6: // Caustic pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.causticPixels(pointX, pointY); repaint(); break; case 7: // Caustic (parallel lines) pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.causticPixels(pointX, pointY, new String("parallel")); repaint(); break; } return true; } /* end of mousedown method */ // mousedrag method public boolean mouseDrag(Event e, int mx, int my) { switch (associatedcurveindex) { case 0: // "None" break; case 1: // "Evolute" // note that this should be drawn from when it is chosen break; case 2: // "Involute" pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.involutePixels(pointX, pointY); repaint(); break; case 3: // "Inverse" switch (circlestage) { case 0: // no circle yet (this should never happen) circleX = mx; circleY = my; circleCX = mx; circleCY = my; circleR = 2; circlestage = 1; break; case 1: // choosing radius double mR = Math.sqrt( (mx-circleX)*(mx-circleX) + (my-circleY)*(my-circleY) ); // mouse distance from centre circleCX = mx; circleCY = my; circleR = Math.max(2,(int)(mR)); circlestage = 1; break; case 2: // dragging circle circleX = mx; circleY = my; circleCX = mx + circleR; circleCY = my; circlestage = 2; break; } associatedcurve = curve.inversePixels(circleX, circleY, circleCX, circleCY); repaint(); break; case 4: // Pedal pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.pedalPixels(pointX, pointY); repaint(); break; case 5: // Negative pedal pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.negativePedalPixels(pointX, pointY); repaint(); break; case 6: // Caustic pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.causticPixels(pointX, pointY); repaint(); break; case 7: // Caustic (parallel lines) pointX = mx; pointY = my; pointstage = 1; associatedcurve = curve.causticPixels(pointX, pointY, new String("parallel")); repaint(); break; } return true; } /* end of mousedrag method */ // paint method public void paint(Graphics g) { if (!this.setaxis) { int sc; sc = (int)(size().height/(curve.yrange)); Curve.xsc = sc; Curve.ysc = sc; Curve.Ox = (int)(-curve.xb*sc+(size().width-size().height)/2); // Curve.Ox = (int)(size().width/2 + (curve.xb+curve.xt)/2*sc) Curve.Oy = (int)(+curve.yt*sc); Curve.xsize = size().width; Curve.ysize = size().height; this.curve.setCurve(); this.curve.translate(0, 0); this.translate(0, 0); this.setaxis = true; } if (this.clear) { g.setColor(Color.white); g.fillRect(0, 0, size().width-1, size().height-1); this.clear = false; } g.setColor(Color.lightGray); //draw axis g.drawLine(Curve.Ox, 0, Curve.Ox, size().height); g.drawLine(0, Curve.Oy, size().width, Curve.Oy); g.setColor(Color.blue); //draw the main curve int acx1, acy1, acx2, acy2, acx0, acy0; int j = 0; for (int i=0; i<=curve.nop-steps; i+=steps) { acx1 = curve.fxpixels[i]; acy1 = curve.fypixels[i]; acx2 = curve.fxpixels[i+steps]; acy2 = curve.fypixels[i+steps]; // the next "if" checks to see at least one of the endpoints is on screen if ((0 < acx2 && acx2 < Curve.xsize && 0 < acy2 && acy2 < Curve.ysize) || (0 < acx1 && acx1 < Curve.xsize && 0 < acy1 && acy1 < Curve.ysize)) { // the next "if" checks to see the points aren't too far away if (Math.abs(acx1 - acx2) < size().height/2 && Math.abs(acy1 - acy2) < size().width/2) { g.drawLine(acx1, acy1, acx2, acy2); } } j = i; } if (j!=curve.nop-1) { j++; acx1 = curve.fxpixels[j]; acy1 = curve.fypixels[j]; acx2 = curve.fxpixels[curve.fxpixels.length-1]; acy2 = curve.fypixels[curve.fxpixels.length-1]; // the next "if" checks to see at least one of the endpoints is on screen if ((0 < acx2 && acx2 < Curve.xsize && 0 < acy2 && acy2 < Curve.ysize) || (0 < acx1 && acx1 < Curve.xsize && 0 < acy1 && acy1 < Curve.ysize)) { // the next "if" checks to see the points aren't too far away if (Math.abs(acx1 - acx2) < size().height/2 && Math.abs(acy1 - acy2) < size().width/2) { g.drawLine(acx1, acy1, acx2, acy2); } } } g.setColor(Color.green); //draw a point if appropriate if (pointstage > 0) { g.fillArc(pointX-2, pointY-2, 4, 4, 0, 360); } //draw circle if appropriate if (circlestage > 0) { g.fillArc(circleX-2, circleY-2, 4, 4, 0, 360); g.setColor(darkGreen); g.drawArc(circleX-circleR, circleY-circleR, 2*circleR, 2*circleR, 0, 360); } //draw a line if appropriate if (associatedcurveindex == 7 && pointstage>0) { g.setColor(darkGreen); if (pointX == Curve.Ox) { if (pointY == Curve.Oy) { g.drawLine(0, Curve.Oy, size().width, Curve.Oy); } else { g.drawLine(Curve.Ox, 0, Curve.Ox, size().height); } } else { int linepoints[][] = Curve.lineEnds(Curve.yPixelToPoint(pointY)/Curve.xPixelToPoint(pointX), 0.0); g.drawLine(linepoints[0][0], linepoints[1][0], linepoints[0][1], linepoints[1][1]); } } g.setColor(Color.red); //draw associated curve if appropriate if ( (associatedcurveindex>0 && pointstage+circlestage>0) || (associatedcurveindex==1) ) { for (int i=0; i<=curve.nop+2-steps; i+=steps) { acx1 = associatedcurve[0][i]; acy1 = associatedcurve[1][i]; acx2 = associatedcurve[0][i+steps]; acy2 = associatedcurve[1][i+steps]; // the next "if" checks to see at least one of the endpoints is on screen if ((0 < acx2 && acx2 < Curve.xsize && 0 < acy2 && acy2 < Curve.ysize) || (0 < acx1 && acx1 < Curve.xsize && 0 < acy1 && acy1 < Curve.ysize)) { // the next "if" checks to see the points aren't too far away if (Math.abs(acx1 - acx2) < size().height/2 && Math.abs(acy1 - acy2) < size().width/2) { g.drawLine(acx1, acy1, acx2, acy2); } } j = i; } if (j!=curve.nop-1) { j++; acx1 = associatedcurve[0][j]; acy1 = associatedcurve[1][j]; acx2 = associatedcurve[0][associatedcurve[0].length-1]; acy2 = associatedcurve[1][associatedcurve[1].length-1]; // the next "if" checks to see at least one of the endpoints is on screen if ((0 < acx2 && acx2 < Curve.xsize && 0 < acy2 && acy2 < Curve.ysize) || (0 < acx1 && acx1 < Curve.xsize && 0 < acy1 && acy1 < Curve.ysize)) { // the next "if" checks to see the points aren't too far away if (Math.abs(acx1 - acx2) < size().height/2 && Math.abs(acy1 - acy2) < size().width/2) { g.drawLine(acx1, acy1, acx2, acy2); } } } } g.setColor(darkGreen); // outline point or centre of circle if appropriate if (pointstage > 0 && associatedcurveindex != 7) { g.drawArc(pointX-2, pointY-2, 4, 4, 0, 360); } if (circlestage > 0) { g.drawArc(circleX-2, circleY-2, 4, 4, 0, 360); } } /* end of paint method */ } /* end of CurvePanel class */