import java.*; import java.awt.*; public class Proof1 extends java.applet.Applet { Proof1Canvas displayer; int state; Button LNEFbutton; Button LENFbutton; Button LELNbutton; Button continuebutton; Button restartbutton; public void init(){ state = 1; displayer = new Proof1Canvas(); displayer.resize(550,300); add(displayer); continuebutton=new Button("Continue"); restartbutton=new Button("Restart"); add(continuebutton); add(restartbutton); LNEFbutton = new Button("LN || EF"); LENFbutton = new Button("LE || NF"); LELNbutton = new Button("LE per. LN"); add(LNEFbutton); add(LENFbutton); add(LELNbutton); setBackground(Color.lightGray); } public void addstate2buttons(){ LNEFbutton.show(); LENFbutton.show(); LELNbutton.show(); } public void removestate2buttons(){ LNEFbutton.hide(); LENFbutton.hide(); LELNbutton.hide(); } public void paint(Graphics g){ if(state==1) removestate2buttons(); displayer.repaint(); } public boolean action(Event ev, Object arg){ if(ev.target instanceof Button && state > 0){ if("Continue".equals(arg)){ switch(state){ case 1: addstate2buttons(); case 3: case 21: case 23: state++; break; case 2: removestate2buttons(); state = 3; break; case 25: case 22: case 24: addstate2buttons(); state = 2; break; case 4: state = 5; continuebutton.hide(); break; default: } } if("Restart".equals(arg)){ if(state == 2){ removestate2buttons(); } if(state == 5){ continuebutton.show(); } state = 1; } if("LN || EF".equals(arg)){ removestate2buttons(); state = 21; } if("LE || NF".equals(arg)){ removestate2buttons(); state = 23; } if("LE per. LN".equals(arg)){ removestate2buttons(); state = 25; } displayer.setState(state); repaint(); return true; } return false; } } class Proof1Canvas extends Canvas{ int state; Font font; int fsize; DPoint a,b,c; DPoint l,m,n; DPoint p,q,r; DPoint h; DPoint d,e,f; DLine sideab,sidebc,sideca,altap,altbq,altcr; DLine ln,ef,le,nf,bh,ch, ah,lm,mf,fd,dl,dm,dp,pm; DPoint center; double radius; public Proof1Canvas(){ font = new Font("TimesRoman", Font.PLAIN, 12); fsize = 2+font.getSize(); state = 1; a = new DPoint(40.0,20.0,"A"); b = new DPoint(270.0,20.0,"B"); c = new DPoint(120.0,150.0,"C"); sideab = new DLine(a,b); sidebc = new DLine(b,c); sideca = new DLine(c,a); l = sideab.midpoint(); m = sidebc.midpoint(); n = sideca.midpoint(); l.label = "L"; m.label = "M"; n.label = "N"; r = sideab.footalt(c); p = sidebc.footalt(a); q = sideca.footalt(b); p.label = "P"; q.label = "Q"; r.label = "R"; altap = new DLine(a,p); altbq = new DLine(b,q); altcr = new DLine(c,r); h = altap.intersect(altbq); h.label = "H"; d = new DLine(a,h).midpoint(); e = new DLine(b,h).midpoint(); f = new DLine(c,h).midpoint(); d.label = "D"; e.label = "E"; f.label = "F"; center = l.circumcenter(m,n); center.label = "CENTER"; radius = center.dist(l); ln = new DLine(l,n); ef = new DLine(e,f); le = new DLine(l,e); nf = new DLine(n,f); bh = new DLine(b,h); ch = new DLine(c,h); ah = new DLine(a,h); lm = new DLine(l,m); mf = new DLine(m,f); fd = new DLine(f,d); dl = new DLine(d,l); dm = new DLine(d,m); dp = new DLine(d,p); pm = new DLine(p,m); } public void paint(Graphics g) { switch (state) { case 1: { draw1(g); break; } case 2: { draw2(g); break; } case 3: { draw3(g); break; } case 4: { draw4(g); break; } case 5: { draw5(g); break; } case 21: { draw21(g); break; } case 22: { draw22(g); break; } case 23: { draw23(g); break; } case 24: { draw24(g); break; } case 25: { draw25(g); break; } } } public void setState(int s){ state = s; } public void draw1(Graphics g) { g.setColor(Color.black); g.setFont(font); sideab.Show(g); sidebc.Show(g); sideca.Show(g); a.Show(g,7); b.Show(g,1); c.Show(g,4); g.setColor(Color.red); g.drawString("L,M,N are the midpoints of the sides.",300,20); l.Show(g,0); m.Show(g,3); n.Show(g,5); g.setColor(Color.green); g.drawString("P,Q,R are the feet of the altitudes.",300, 20+fsize); p.Show(g,3); q.Show(g,5); r.Show(g,0); altap.Show(g); altbq.Show(g); altcr.Show(g); g.setColor(Color.blue); h.Show(g,7); g.drawString("H is the orthocenter.",300,20+2*fsize); g.setColor(Color.cyan); d.Show(g,1); e.Show(g,7); f.Show(g,3); g.drawString("D,E,F are the midpoints of AH, BH and CH.",300,20+3*fsize); } public void draw2(Graphics g){ draw1(g); g.setColor(Color.black); g.drawString("For more explanation, press a button.",10,180); g.drawString("We have LN || EF, LE || NF and LE perpendicular to LN.",10,180+fsize); g.drawString("Therefore LNFE is a rectangle.",10,180+2*fsize); g.setColor(Color.orange); ln.Show(g); ef.Show(g); le.Show(g); nf.Show(g); } public void draw3(Graphics g){ draw1(g); g.setColor(Color.orange); ln.Show(g); ef.Show(g); le.Show(g); nf.Show(g); g.setColor(Color.black); g.drawString("We have that LNFE is a rectangle; similarly, LMFD is a rectangle.",10,180+fsize); g.drawString("Therefore L,M,N,D,E, and F are all on the circle with diameter LF",10,180+2*fsize); g.drawString("because LF is a diagonal of both rectangles, so that all 6 points",10,180+3*fsize); g.drawString("at the vertices of the rectangles are equidistant from the midpoint of LF.",10,180+4*fsize); g.setColor(Color.red); lm.Show(g); mf.Show(g); fd.Show(g); dl.Show(g); } public void draw4(Graphics g){ draw1(g); g.setColor(Color.black); g.drawString("Finally, P, Q and R are on the circle with diameter LF.",10,180); g.drawString("For point P, since AP is an altitude of triangle ABC,",10,180+fsize); g.drawString("angle DPM is a right angle. Since the diameter DM of the",10,180+2*fsize); g.drawString("subtends a right angle at P, P must be on the circle.",10,180+3*fsize); g.drawString("Similarly, Q and R are on the circle.",10,180+4*fsize); g.setColor(Color.red); dm.Show(g); dp.Show(g); pm.Show(g); } public void draw5(Graphics g){ draw1(g); g.setColor(Color.magenta); g.drawOval( (int)(center.x-radius),(int)(center.y-radius),(int)(2.0*radius),(int)(2.0*radius)); center.Show(g,1); } public void draw21(Graphics g){ draw1(g); g.setColor(Color.orange); ln.Show(g); sidebc.Show(g); sideab.Show(g); sideca.Show(g); g.setColor(Color.black); g.drawString("LN || BC because LN joins the midpoints",10,180); g.drawString("of two sides AB, AC of triangle ABC.",10,180+fsize); } public void draw22(Graphics g){ draw1(g); g.setColor(Color.orange); sidebc.Show(g); bh.Show(g); ch.Show(g); ef.Show(g); g.setColor(Color.black); g.drawString("LN || BC because LN joins the midpoints",10,180); g.drawString("of two sides AB, AC of triangle ABC.",10,180+fsize); g.drawString("EF || BC because E,F are the midpoints",10,180+2*fsize); g.drawString("of two sides BH, CH of triangle BCH.",10,180+3*fsize); g.drawString("Therefore LN || EF because both are || BC.",10,180+4*fsize); } public void draw23(Graphics g){ draw1(g); g.setColor(Color.orange); le.Show(g); ah.Show(g); sideab.Show(g); bh.Show(g); g.setColor(Color.black); g.drawString("LE || AH because LE joins the midpoints",10,180); g.drawString("of two sides AB, BH of triangle ABH.",10,180+fsize); } public void draw24(Graphics g){ draw1(g); g.setColor(Color.orange); sideca.Show(g); ah.Show(g); ch.Show(g); nf.Show(g); g.setColor(Color.black); g.drawString("LE || AH because LE joins the midpoints",10,180); g.drawString("of two sides AB, BH of triangle ABH.",10,180+fsize); g.drawString("NF || AH because N,F are the midpoints",10,180+2*fsize); g.drawString("of two sides AC, CH of triangle ACH.",10,180+3*fsize); g.drawString("Therefore LE || NF because both are || BC.",10,180+4*fsize); } public void draw25(Graphics g){ draw1(g); g.setColor(Color.orange); le.Show(g); ln.Show(g); sidebc.Show(g); g.setColor(Color.black); g.drawString("We have LE || AP (see the proof that LE || NF),",10,180); g.drawString("AP perpendicular to BC (AP is an altitude),",10,180+fsize); g.drawString("and BC || LN (from the proof that LN || EF).",10,180+2*fsize); g.drawString("Therefore LE is perdendicular to LN.",10, 180+4*fsize); } } class DPoint{ double x, y; String label; public DPoint(double first, double second, String name){ x = first; y = second; label = name; } public DPoint(double first, double second){ x = first; y = second; label = ""; } public void Show(Graphics g, int where){ int first = (int) x; int second = (int) y; // where tells us where to place the character // relative to the point --- 0 = north, 1 = northeast, // 2 = east, ..., 7 = northwest. int xoffs[] = {0,3,5,6,-3,-10,-12,-10}; int yoffs[] = {-5,-3,0,10,13,10,0,-3}; int offsetx = xoffs[where]; int offsety = yoffs[where]; g.drawOval(first-1,second-1,2,2); g.drawString(label,first+offsetx,second+offsety); } public double dist(DPoint q){ return Math.sqrt((q.x - x)*(q.x - x) + (q.y - y)*(q.y - y)); } public DPoint orthocenter(DPoint m, DPoint n){ // orthocenter of triangle DLine sidemn = new DLine(m,n); DLine sidelm = new DLine(this,m); DPoint foot1 = sidemn.footalt(this); DPoint foot2 = sidelm.footalt(n); DLine alt1 = new DLine(this, foot1); DLine alt2 = new DLine(n, foot2); return alt1.intersect(alt2); } public DPoint circumcenter(DPoint b, DPoint c){ // circumcenter of triangle formed by the 3 points DPoint l = new DLine(this,b).midpoint(); DPoint m = new DLine(this,c).midpoint(); DPoint n = new DLine(b,c).midpoint(); return l.orthocenter(m,n); } } class DLine{ DPoint p,q; public DLine(DPoint first, DPoint second){ p = first; q = second; } public void Show(Graphics g){ int x1 = (int) p.x; int y1 = (int) p.y; int x2 = (int) q.x; int y2 = (int) q.y; g.drawLine(x1,y1,x2,y2); } public DPoint lambdapoint(double lambda){ // The result is the point a fraction lambda // of the way from point p to point q. For example, // if lambda == 0.5, we get the midpoint. In // vector notation, r = p*(1-lambda) + q*lambda. return(new DPoint(q.x*lambda + p.x*(1.0-lambda), q.y*lambda + p.y*(1.0-lambda))); } public DPoint midpoint(){ return lambdapoint(0.5); } public DPoint intersect(DLine m){ double numerator = (m.q.x-q.x)*(m.q.y-m.p.y) - (m.q.x-m.p.x)*(m.q.y-q.y); double denominator = (p.x-q.x)*(m.q.y-m.p.y) - (m.q.x-m.p.x)*(p.y-q.y); double lambda = 1.0 - numerator / denominator; return( lambdapoint(lambda)); } public DPoint footalt(DPoint c){ // foot of the altitude from point c to this line // determine lambda so that // lambdapoint h on line qp satisfies // dot product ch.pq == 0. double lambda = ( (q.x-p.x)*(q.x-c.x) + (q.y-p.y)*(q.y-c.y) ) / ( (q.x-p.x)*(q.x-p.x) + (q.y-p.y)*(q.y-p.y) ); return lambdapoint(1.0-lambda); } }