//TriangleApplet.java import java.awt.*; import javax.swing.border.*; import java.awt.event.*; import javax.swing.*; import java.util.*; import java.text.*; public class TriangleApplet extends JApplet implements ActionListener { //, ItemListener { JPanel controlPanel; JLabel x1Label, y1Label, x2Label, y2Label, x3Label, y3Label, scaleLabel; JTextField x1TextField, y1TextField, x2TextField, y2TextField, x3TextField, y3TextField, scaleTextField; JCheckBox centroidCheckBox, circumCheckBox, orthoCheckBox, ninepointCheckBox, incircleCheckBox, excircleCheckBox, eulerCheckBox; boolean showCentroid, showCircum, showOrtho, showNinepoint, showIncircle, showExcircle, showEuler; int x1, y1, x2, y2, x3, y3; double sx1, sy1, sx2, sy2, sx3, sy3; int clicks; double scale; DecimalFormat d4, d2; public void init() { clicks = 0; d4 = new DecimalFormat ("0.0000"); d2 = new DecimalFormat ("0.00"); Container container = getContentPane(); container.setLayout(null); //** no Layout Manager //container.setLayout( new BorderLayout() ); controlPanel = new JPanel(); controlPanel.setLayout(new FlowLayout()); controlPanel.setBackground(Color.MAGENTA); controlPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED)); //container.add(controlPanel,BorderLayout.NORTH); controlPanel.setBounds(0,0, getWidth(),35); container.add(controlPanel); Box checkBoxes = new Box(BoxLayout.Y_AXIS); checkBoxes.setBounds(1,40,80,200); //**absolute position:x,y, width, height container.add(checkBoxes); x1Label = new JLabel( "X1" ); controlPanel.add( x1Label ); x1TextField = new JTextField("",4); //a = Double.parseDouble(xTextField.getText()); x1TextField.setHorizontalAlignment(JTextField.RIGHT); x1TextField.addActionListener( this ); controlPanel.add( x1TextField ); y1Label = new JLabel( "Y1" ); controlPanel.add( y1Label ); y1TextField = new JTextField("",4); //a = Double.parseDouble(xTextField.getText()); y1TextField.setHorizontalAlignment(JTextField.RIGHT); y1TextField.addActionListener( this ); controlPanel.add( y1TextField ); x2Label = new JLabel( "X2" ); controlPanel.add( x2Label ); x2TextField = new JTextField("",4); //a = Double.parseDouble(xTextField.getText()); x2TextField.setHorizontalAlignment(JTextField.RIGHT); x2TextField.addActionListener( this ); controlPanel.add( x2TextField ); y2Label = new JLabel( "Y2" ); controlPanel.add( y2Label ); y2TextField = new JTextField("",4); //a = Double.parseDouble(xTextField.getText()); y2TextField.setHorizontalAlignment(JTextField.RIGHT); y2TextField.addActionListener( this ); controlPanel.add( y2TextField ); x3Label = new JLabel( "X3" ); controlPanel.add( x3Label ); x3TextField = new JTextField("",4); //a = Double.parseDouble(xTextField.getText()); x3TextField.setHorizontalAlignment(JTextField.RIGHT); x3TextField.addActionListener( this ); controlPanel.add( x3TextField ); y3Label = new JLabel( "Y3" ); controlPanel.add( y3Label ); y3TextField = new JTextField("",4); //a = Double.parseDouble(xTextField.getText()); y3TextField.setHorizontalAlignment(JTextField.RIGHT); y3TextField.addActionListener( this ); controlPanel.add( y3TextField ); scaleLabel = new JLabel( "Screen height" ); controlPanel.add( scaleLabel ); scaleTextField = new JTextField("100",4); scale = Double.parseDouble(scaleTextField.getText()) / getHeight(); scaleTextField.setHorizontalAlignment(JTextField.RIGHT); scaleTextField.addActionListener( this ); controlPanel.add( scaleTextField ); //centroidCheckBox = new JCheckBox( "Centroid", true ); centroidCheckBox = new JCheckBox( "", true ); centroidCheckBox.setBackground(Color.BLUE); checkBoxes.add( centroidCheckBox ); centroidCheckBox.addActionListener( this ); //circumCheckBox = new JCheckBox( "Circum", true ); circumCheckBox = new JCheckBox( "", true ); circumCheckBox.setBackground(Color.RED); circumCheckBox.setBounds(0,0,60,30); checkBoxes.add( circumCheckBox ); //circumCheckBox.addItemListener( this ); circumCheckBox.addActionListener( this ); //orthoCheckBox = new JCheckBox( "Ortho", true ); orthoCheckBox = new JCheckBox( "", true ); orthoCheckBox.setBackground(Color.GREEN); checkBoxes.add( orthoCheckBox ); orthoCheckBox.addActionListener( this ); //ninepointCheckBox = new JCheckBox( "Ninepoint", true ); ninepointCheckBox = new JCheckBox( "", true ); ninepointCheckBox.setBackground(Color.CYAN); checkBoxes.add( ninepointCheckBox ); ninepointCheckBox.addActionListener( this ); //incircleCheckBox = new JCheckBox( "Incircle", true ); incircleCheckBox = new JCheckBox( "", true ); incircleCheckBox.setBackground(Color.MAGENTA); checkBoxes.add( incircleCheckBox ); incircleCheckBox.addActionListener( this ); //excircleCheckBox = new JCheckBox( "Excircles", true ); excircleCheckBox = new JCheckBox( "", true ); excircleCheckBox.setBackground(Color.GRAY); checkBoxes.add( excircleCheckBox ); excircleCheckBox.addActionListener( this ); //eulerCheckBox = new JCheckBox( "Euler", true ); eulerCheckBox = new JCheckBox( "", true ); eulerCheckBox.setBackground(Color.YELLOW); checkBoxes.add( eulerCheckBox ); eulerCheckBox.addActionListener( this ); showCentroid = showCircum = showOrtho = showNinepoint = showIncircle = showExcircle = showEuler = true; addMouseListener( //anonymous inner class overrides mouseClicked new MouseAdapter() { public void mouseClicked( MouseEvent event) { clicks++; //System.out.println("clicks= "+clicks); switch (clicks) { case 1: x1 = event.getX(); y1 = getHeight() - event.getY(); sx1 = x1*scale; sy1 = y1*scale; x1TextField.setText(""+d2.format(sx1)); y1TextField.setText(""+d2.format(sy1)); break; case 2: x2 = event.getX(); y2 = getHeight() - event.getY(); sx2 = x2*scale; sy2 = y2*scale; x2TextField.setText(""+d2.format(sx2)); y2TextField.setText(""+d2.format(sy2)); break; case 3: x3 = event.getX(); y3 = getHeight() - event.getY(); sx3 = x3*scale; sy3 = y3*scale; x3TextField.setText(""+d2.format(sx3)); y3TextField.setText(""+d2.format(sy3)); break; default: clicks = 3; //set it back to 3?? return; //do not repaint } repaint(); } } ); //incantation that responds to mouse move events: addMouseMotionListener( //anonymous inner class overrides mouseMoved //creates a $n class file which must be uploaded to web site new MouseMotionAdapter() { public void mouseMoved( MouseEvent event) { showStatus("("+d2.format(event.getX()*scale)+","+d2.format((getHeight()-event.getY())*scale)+")"); if (clicks == 0) { x1TextField.setText(""+d2.format(event.getX()*scale)); y1TextField.setText(""+d2.format((getHeight()-event.getY())*scale)); } else if (clicks == 1) { x2TextField.setText(""+d2.format(event.getX()*scale)); y2TextField.setText(""+d2.format((getHeight()-event.getY())*scale)); } else if (clicks == 2) { x3TextField.setText(""+d2.format(event.getX()*scale)); y3TextField.setText(""+d2.format((getHeight()-event.getY())*scale)); } } public void mouseDragged( MouseEvent event) { double px = event.getX()*scale; double py = (getHeight()-event.getY())*scale; showStatus("DRAGGING ("+d2.format(px)+","+d2.format(py)+")"); double mouseDistance[] = new double[3]; mouseDistance[0] = distanceFormula(px,py, sx1,sy1); mouseDistance[1] = distanceFormula(px,py, sx2,sy2); mouseDistance[2] = distanceFormula(px,py, sx3,sy3); if (mouseDistance[0]=len13 && len12>=len23) { double cos3 = (len13*len13+len23*len23-len12*len12) / (2*len13*len23); ang3 = Math.toDegrees(Math.acos(cos3)); double sin2 = len13*Math.sin(Math.toRadians(ang3)) / len12; ang2 = Math.toDegrees(Math.asin(sin2)); ang1 = 180 - ang2 - ang3; } else if (len13>=len12 && len13>=len23) { double cos2 = (len12*len12+len23*len23-len13*len13) / (2*len12*len23); ang2 = Math.toDegrees(Math.acos(cos2)); double sin1 = len23*Math.sin(Math.toRadians(ang2)) / len13; ang1 = Math.toDegrees(Math.asin(sin1)); ang3 = 180 - ang1 - ang2; } else { //len23 is longest double cos1 = (len12*len12+len13*len13-len23*len23) / (2*len12*len13); ang1 = Math.toDegrees(Math.acos(cos1)); double sin3 = len12*Math.sin(Math.toRadians(ang1)) / len23; ang3 = Math.toDegrees(Math.asin(sin3)); ang2 = 180 - ang1 - ang3; } g.setColor( Color.CYAN ); g.fillOval((int)(x12mid/scale)-2,height-(int)(y12mid/scale)-2,3,3); //g.drawString(""+len12,x12mid,height-y12mid); g.fillOval((int)(x13mid/scale)-2,height-(int)(y13mid/scale)-2,3,3); //g.drawString(""+len13,x13mid,height-y13mid); g.fillOval((int)(x23mid/scale)-2,height-(int)(y23mid/scale)-2,3,3); //g.drawString(""+len23,x23mid,height-y23mid); double xc, yc; //centroid (center of mass/gravity) of triangle xc = (sx1+sx2+sx3) / 3; yc = (sy1+sy2+sy3) / 3; if (showCentroid) { g.setColor( Color.BLUE ); g.fillOval((int)(xc/scale)-2,height-(int)(yc/scale)-2,4,4); //g.drawString("("+xc+","+yc+")",xc,yc); //median: line from midpoint to oppposite vertex. g.drawLine( (int)(sx1/scale), height-(int)(sy1/scale), (int)(x23mid/scale), height-(int)(y23mid/scale) ); g.drawLine( (int)(sx2/scale), height-(int)(sy2/scale), (int)(x13mid/scale), height-(int)(y13mid/scale) ); g.drawLine( (int)(sx3/scale), height-(int)(sy3/scale), (int)(x12mid/scale), height-(int)(y12mid/scale) ); } //the medians intersect at the centroid. //centroid is 2/3 of way from vertex to midpoint: double median1Length = distanceFormula(sx1,sy1, x23mid,y23mid); //Math.sqrt((sx1-x23mid)*(sx1-x23mid) + (sy1-y23mid)*(sy1-y23mid)); double median2Length = distanceFormula(sx2,sy2, x13mid,y13mid);//Math.sqrt((sx2-x13mid)*(sx2-x13mid) + (sy2-y13mid)*(sy2-y13mid)); double median3Length = distanceFormula(sx3,sy3, x12mid,y12mid);//Math.sqrt((sx3-x12mid)*(sx3-x12mid) + (sy3-y12mid)*(sy3-y12mid)); double vertex1CentroidLength = distanceFormula(sx1,sy1, xc,yc); //Math.sqrt((sx1-xc)*(sx1-xc) + (sy1-yc)*(sy1-yc)); double vertex2CentroidLength = distanceFormula(sx2,sy2, xc,yc);//Math.sqrt((sx2-xc)*(sx2-xc) + (sy2-yc)*(sy2-yc)); double vertex3CentroidLength = distanceFormula(sx3,sy3, xc,yc);//Math.sqrt((sx3-xc)*(sx3-xc) + (sy3-yc)*(sy3-yc)); /*g.setColor( Color.YELLOW ); g.drawLine( x12mid,y12mid, xc, yc ); g.drawLine( x13mid,y13mid, xc, yc ); g.drawLine( x23mid,y23mid, xc, yc ); */ //circle centered at vertex, touching centroid /* g.setColor( Color.MAGENTA ); int len1c = (int)Math.sqrt((x1-xc)*(x1-xc) + (y1-yc)*(y1-yc)); g.drawOval(x1-len1c, y1-len1c, 2*len1c, 2*len1c); int len2c = (int)Math.sqrt((x2-xc)*(x2-xc) + (y2-yc)*(y2-yc)); g.drawOval(x2-len2c, y2-len2c, 2*len2c, 2*len2c); int len3c = (int)Math.sqrt((x3-xc)*(x3-xc) + (y3-yc)*(y3-yc)); g.drawOval(x3-len3c, y3-len3c, 2*len3c, 2*len3c); */ //equation for each of the 3 lines double m12, m13, m23; //slopes double b12, b13, b23; //y-intercepts m12 = (sy2-sy1)/(sx2-sx1); m13 = (sy3-sy1)/(sx3-sx1); m23 = (sy3-sy2)/(sx3-sx2); //??change neg inf to pos inf?? b12 = sy1 - m12*sx1; b13 = sy1 - m13*sx1; b23 = sy2 - m23*sx2; double mp12, mp13, mp23; //slopes of perpendicular line double bp12, bp13, bp23; //y-intercepts of perpendicular line thru midpoint //perpendicular bisector of the triangle lines mp12 = -1/m12; mp13 = -1/m13; mp23 = -1/m23; bp12 = y12mid - mp12*x12mid; bp13 = y13mid - mp13*x13mid; bp23 = y23mid - mp23*x23mid; //intersection of 2 of the perpendicular bisectors: circumcenter //will be intersection of other. don't use any (near)vertical bisector. double xcircum, ycircum; /* g.drawString("12p Eq: m="+mp12,width-300,162); g.drawString("13p Eq: m="+mp13,width-300,182); g.drawString("23p Eq: m="+mp23,width-300,202); */ if (mp12!=Double.POSITIVE_INFINITY && mp12!=Double.NEGATIVE_INFINITY && mp13!=Double.POSITIVE_INFINITY && mp13!=Double.NEGATIVE_INFINITY && Math.abs(mp12)<30 && Math.abs(mp13)<30) { xcircum = (bp13-bp12)/(mp12-mp13); ycircum = mp12*xcircum + bp12; } else if (mp13!=Double.POSITIVE_INFINITY && mp13!=Double.NEGATIVE_INFINITY && mp23!=Double.POSITIVE_INFINITY && mp23!=Double.NEGATIVE_INFINITY && Math.abs(mp13)<30 && Math.abs(mp23)<30) { xcircum = (bp23-bp13)/(mp13-mp23); ycircum = mp13*xcircum + bp13; } else { xcircum = (bp23-bp12)/(mp12-mp23); ycircum = mp12*xcircum + bp12; } double rCircum = distanceFormula(sx1,sy1, xcircum,ycircum);//Math.sqrt((sx1-xcircum)*(sx1-xcircum)+(sy1-ycircum)*(sy1-ycircum)); //Warning: nearly horizontal lines cause b to be extreme, causing problems. if (showCircum) { g.setColor( Color.RED ); g.fillOval((int)(xcircum/scale)-2,height-(int)(ycircum/scale)-2,4,4); //lines from midpoints to the intersection g.drawLine((int)(x12mid/scale),height-(int)(y12mid/scale),(int)(xcircum/scale),height-(int)(ycircum/scale)); g.drawLine((int)(x13mid/scale),height-(int)(y13mid/scale),(int)(xcircum/scale),height-(int)(ycircum/scale)); g.drawLine((int)(x23mid/scale),height-(int)(y23mid/scale),(int)(xcircum/scale),height-(int)(ycircum/scale)); //length from any vertiex to the intersection is radius of circumcircle: g.drawOval((int)((xcircum-rCircum)/scale),height-(int)((ycircum+rCircum)/scale), 2*(int)(rCircum/scale),2*(int)(rCircum/scale)); // change y's - to + } double perpBi1d, perpBi2d, perpBi3d; perpBi1d = distanceFormula(xcircum,ycircum, x12mid,y12mid); perpBi2d = distanceFormula(xcircum,ycircum, x13mid,y13mid); perpBi3d = distanceFormula(xcircum,ycircum, x23mid,y23mid); //****** altitude is perpendicular to line going thru opposite vertex double bAlt12, bAlt13, bAlt23; //y-intercepts of altitude bAlt12 = sy3 - mp12*sx3; //oppposite vertex is point on altitude bAlt13 = sy2 - mp13*sx2; bAlt23 = sy1 - mp23*sx1; double xAlt12, yAlt12, xAlt13, yAlt13, xAlt23, yAlt23; //intersection of altitude on line 12. special cases if (m12 == 0) { //12 is horizontal xAlt12 = sx3; yAlt12 = sy1; //or y2, same } else if (mp12 == 0) { //12 is vertical xAlt12 = sx1; //or x2, same yAlt12 = sy3; } else { //neither horizontal nor vertical xAlt12 = (bAlt12-b12)/(m12-mp12); //intersection of altitude on line 12 yAlt12 = m12*xAlt12 + b12; } //intersection of altitude on line 13 if (m13 == 0) { //13 is horizontal xAlt13 = sx2; yAlt13 = sy1; //or y3, same } else if (mp13 == 0) { //13 is vertical xAlt13 = sx1; //or x3, same yAlt13 = sy2; } else { //neither horizontal nor vertical xAlt13 = (bAlt13-b13)/(m13-mp13); //intersection of altitude on line 13 yAlt13 = m13*xAlt13 + b13; } //intersection of altitude on line 23 if (m23 == 0) { //23 is horizontal xAlt23 = sx1; yAlt23 = sy2; //or y3, same } else if (mp23 == 0) { //23 is vertical xAlt23 = sx2; //or x3, same yAlt23 = sy1; } else { //neither horizontal nor vertical xAlt23 = (bAlt23-b23)/(m23-mp23); //intersection of altitude on line 23 yAlt23 = m23*xAlt23 + b23; } if (showOrtho) { g.setColor( Color.GREEN ); g.drawLine((int)(xAlt12/scale),height-(int)(yAlt12/scale),(int)(sx3/scale),height-(int)(sy3/scale)); g.drawLine((int)(xAlt13/scale),height-(int)(yAlt13/scale),(int)(sx2/scale),height-(int)(sy2/scale)); g.drawLine((int)(xAlt23/scale),height-(int)(yAlt23/scale),(int)(sx1/scale),height-(int)(sy1/scale)); } //intersection of two altitudes (other will be same): orthocenter double xortho, yortho; //avoid the (near)infinitys if (mp12!=Double.POSITIVE_INFINITY && mp12!=Double.NEGATIVE_INFINITY && mp13!=Double.POSITIVE_INFINITY && mp13!=Double.NEGATIVE_INFINITY && Math.abs(mp12)<30 && Math.abs(mp13)<30) { xortho = (bAlt13-bAlt12)/(mp12-mp13); yortho = mp12*xortho + bAlt12; } else if (mp13!=Double.POSITIVE_INFINITY && mp13!=Double.NEGATIVE_INFINITY && mp23!=Double.POSITIVE_INFINITY && mp23!=Double.NEGATIVE_INFINITY && Math.abs(mp13)<30 && Math.abs(mp23)<30) { xortho = (bAlt23-bAlt13)/(mp13-mp23); yortho = mp13*xortho + bAlt13; } else { xortho = (bAlt23-bAlt12)/(mp12-mp23); yortho = mp12*xortho + bAlt12; } g.fillOval((int)(xortho/scale)-2,height-(int)(yortho/scale)-2,4,4); double alt1d, alt2d, alt3d; alt1d = distanceFormula(xAlt23,yAlt23, sx1,sy1); alt2d = distanceFormula(xAlt13,yAlt13, sx2,sy2); alt3d = distanceFormula(xAlt12,yAlt12, sx3,sy3); double v1_orthoCd, v2_orthoCd, v3_orthoCd; v1_orthoCd = distanceFormula(xortho,yortho, sx1,sy1); v2_orthoCd = distanceFormula(xortho,yortho, sx2,sy2); v3_orthoCd = distanceFormula(xortho,yortho, sx3,sy3); //Euler line: circumcenter, centroid, and orthocenter are collinear. // centroid in between, 1/3 way from circum to ortho (ortho to centroid is twice centroid to circum) // Midpoint of Euler line is center of 9point circle. if (showEuler) { g.setColor( Color.YELLOW ); g.drawLine((int)(xortho/scale),height-(int)(yortho/scale), (int)(xcircum/scale),height-(int)(ycircum/scale)); } double orthoCentroidDistance, circumCentroidDistance; orthoCentroidDistance = distanceFormula(xortho,yortho, xc,yc);// Math.sqrt((xortho-xc)*(xortho-xc) + (yortho-yc)*(yortho-yc)); circumCentroidDistance = distanceFormula(xcircum,ycircum, xc,yc);//Math.sqrt((xcircum-xc)*(xcircum-xc) + (ycircum-yc)*(ycircum-yc)); double eulerLength = orthoCentroidDistance + circumCentroidDistance; //***** nine-point circle. center is midpoint between orthocenter and circumcenter, // (i.e midpoint of Euler line) //radius is half the circumcircle's radius. //the 9 points are: // the 3 midpoints, // the 3 intersections of the altitudes with their base (or extension), // the midpoints of the portion of altitude between the vertices and the orthocenter. double x9pt = (xortho+xcircum)/2; double y9pt = (yortho+ycircum)/2; double r9pt = .5 * rCircum; if (showNinepoint) { g.setColor( Color.CYAN ); g.fillOval((int)(x9pt/scale)-2,height-(int)(y9pt/scale)-2,4,4); g.drawOval((int)((x9pt-r9pt)/scale),height-(int)((y9pt+r9pt)/scale),2*(int)(r9pt/scale),2*(int)(r9pt/scale)); } // ??? changed y's - to + //incircle: center is intersection of angle bisectors. double xincircle=-999, yincircle=-999; /* double mB12_13, mB12_23, mB13_23; double mBp12_13, mBp12_23, mBp13_23; // double mPos12=Math.abs(m12),mPos13=Math.abs(m13),mPos23=Math.abs(m23); // if (Math.signum(m12)==Math.signum(m13) && mB12_13 = Math.tan((Math.atan(m12)+Math.atan(m13))/2); mB12_23 = Math.tan((Math.atan(m12)+Math.atan(m23))/2); mB13_23 = Math.tan((Math.atan(m13)+Math.atan(m23))/2); //atan range is I and IV quadrants, i.e -PI/2 to PI/2 //so II maps into IV and III maps into I, hard to determine what's what... mBp12_13 = -1/mB12_13; //maybe it's the one perpendicular...? mBp12_23 = -1/mB12_23; mBp13_23 = -1/mB13_23; double bB12_13 = y1 - mB12_13*x1; double bB12_23 = y2 - mB12_23*x2; double bB13_23 = y3 - mB13_23*x3; //perpendicular lines' b double bBp12_13 = y1 - mBp12_13*x1; double bBp12_23 = y2 - mBp12_23*x2; double bBp13_23 = y3 - mBp13_23*x3; //I can't figure out the math, so am searching for the intersection //of 3 lines: {(a,b,c)x(1,2,3)} abc ab3 a2c a23 1bc 1b3 12c 123 //KLUDGE double mB[]={mB12_13,mB12_23,mB13_23, mBp12_13,mBp12_23,mBp13_23}; //a b c 1 2 3 double bB[]={bB12_13,bB12_23,bB13_23, bBp12_13,bBp12_23,bBp13_23}; int xin1, yin1, xin2, yin2, xin3, yin3; int[] xes ={x1,x2,x3}; Arrays.sort(xes); //in order. test if intersection is within triangle's box int[] yes ={y1,y2,y3}; Arrays.sort(yes); for (int i=0; i<2; i++) for (int j=0; j<2; j++) for (int k=0; k<2; k++) { xin1 = (int)Math.round((bB[i*3]-bB[j*3+1])/(mB[j*3+1]-mB[i*3])); yin1 = (int)Math.round((mB[j*3+1]*xin1 + bB[j*3+1])); xin2 = (int)Math.round(((bB[i*3]-bB[k*3+2])/(mB[k*3+2]-mB[i*3]))); yin2 = (int)Math.round((mB[k*3+2]*xin2 + bB[k*3+2])); xin3 = (int)Math.round(((bB[j*3+1]-bB[k*3+2])/(mB[k*3+2]-mB[j*3+1]))); yin3 = (int)Math.round((mB[k*3+2]*xin3 + bB[k*3+2])); if (xin1==xin2 && xin1==xin3 && yin1==yin2 && yin1==yin3 && xin1>=xes[0] && xin1<=xes[2] && yin1>=yes[0] && yin1<=yes[2] ) { xincircle = xin1; yincircle = yin1; } } //DOUBLE KLUDGE. bletcherousity. if (xincircle == -999) { //didn't find, probably becuase an INF slope for (int i=0; i<2; i++) for (int j=0; j<2; j++) for (int k=0; k<2; k++) { xin1=xin2=xin3=yin1=yin2=yin3=Integer.MAX_VALUE; if (mB[j*3+1]!=Double.POSITIVE_INFINITY && mB[j*3+1]!=Double.NEGATIVE_INFINITY && mB[i*3]!=Double.POSITIVE_INFINITY && mB[i*3]!=Double.NEGATIVE_INFINITY) { xin1 = (int)Math.round((bB[i*3]-bB[j*3+1])/(mB[j*3+1]-mB[i*3])); yin1 = (int)Math.round((mB[j*3+1]*xin1 + bB[j*3+1])); } if (mB[i*3]!=Double.POSITIVE_INFINITY && mB[i*3]!=Double.NEGATIVE_INFINITY && mB[k*3+2]!=Double.POSITIVE_INFINITY && mB[k*3+2]!=Double.NEGATIVE_INFINITY) { xin2 = (int)Math.round(((bB[i*3]-bB[k*3+2])/(mB[k*3+2]-mB[i*3]))); yin2 = (int)Math.round((mB[k*3+2]*xin2 + bB[k*3+2])); } if (mB[j*3+1]!=Double.POSITIVE_INFINITY && mB[j*3+1]!=Double.NEGATIVE_INFINITY && mB[k*3+2]!=Double.POSITIVE_INFINITY && mB[k*3+2]!=Double.NEGATIVE_INFINITY) { xin3 = (int)Math.round(((bB[j*3+1]-bB[k*3+2])/(mB[k*3+2]-mB[j*3+1]))); yin3 = (int)Math.round((mB[k*3+2]*xin3 + bB[k*3+2])); } if (xin1==xin2 && yin1==yin2 && xin1>=xes[0] && xin1<=xes[2] && yin1>=yes[0] && yin1<=yes[2] ) { xincircle = xin1; yincircle = yin1; } if (xin1==xin3 && yin1==yin3 && xin1>=xes[0] && xin1<=xes[2] && yin1>=yes[0] && yin1<=yes[2] ) { xincircle = xin1; yincircle = yin1; } if (xin2==xin3 && yin2==yin3 && xin2>=xes[0] && xin2<=xes[2] && yin2>=yes[0] && yin2<=yes[2] ) { xincircle = xin2; yincircle = yin2; } } } */ //forget all the nonsense above, here's a formula for the incenter: //xi*lengthOpposite... xincircle = (sx1*len23 + sx2*len13 + sx3*len12) / (len12 + len13 + len23); yincircle = (sy1*len23 + sy2*len13 + sy3*len12) / (len12 + len13 + len23); double ext1m, ext2m, ext3m; double p12extX, p12extY, p13extX, p13extY, p23extX, p23extY; double len1_p12ext, len2_p12ext, len1_p13ext, len3_p13ext, len2_p23ext, len3_p23ext; double excircle12X, excircle12Y, excircle13X, excircle13Y, excircle23X, excircle23Y; double excircle12R, excircle13R, excircle23R; double inradius=0; //if (xincircle != -999) { //??still needed? inradius = 2 * area / (len12 + len13 + len23); //wow! if (showIncircle) { g.setColor(Color.MAGENTA); g.fillOval((int)(xincircle/scale)-2,height-(int)(yincircle/scale)-2,4,4); g.drawLine((int)(sx1/scale),height-(int)(sy1/scale),(int)(xincircle/scale), height-(int)(yincircle/scale)); g.drawLine((int)(sx2/scale),height-(int)(sy2/scale),(int)(xincircle/scale), height-(int)(yincircle/scale)); g.drawLine((int)(sx3/scale),height-(int)(sy3/scale),(int)(xincircle/scale), height-(int)(yincircle/scale)); g.drawOval((int)((xincircle-inradius)/scale), height-(int)((yincircle+inradius)/scale), 2*(int)(inradius/scale),2*(int)(inradius/scale)); // changed y's - to + } //exterior angle bisectors (are perpendicular to interior bisectors) ext1m = -1/ ((sy1-yincircle)/(sx1-xincircle)); //showStatus("1m="+((sy1-yincircle)/(sx1-xincircle)) +" ext1m="+ext1m); ext2m = -1/ ((sy2-yincircle)/(sx2-xincircle)); ext3m = -1/ ((sy3-yincircle)/(sx3-xincircle)); //g.setColor(Color.RED); p12extX = (-ext2m*sx2 + sy2 + ext1m*sx1 - sy1) / (ext1m - ext2m); p12extY = ext1m*p12extX - ext1m*sx1 + sy1; //g.fillRect((int)(p12extX/scale), height-(int)(p12extY/scale) ,2,2); p13extX = (-ext3m*sx3 + sy3 + ext1m*sx1 - sy1) / (ext1m - ext3m); p13extY = ext1m*p13extX - ext1m*sx1 + sy1; //g.fillRect((int)(p13extX/scale), height-(int)(p13extY/scale) ,2,2); p23extX = (-ext3m*sx3 + sy3 + ext2m*sx2 - sy2) / (ext2m - ext3m); p23extY = ext2m*p23extX - ext2m*sx2 + sy2; //g.fillRect((int)(p23extX/scale), height-(int)(p23extY/scale) ,2,2); len1_p12ext = distanceFormula(sx1,sy1, p12extX,p12extY); len2_p12ext = distanceFormula(sx2,sy2, p12extX,p12extY); len1_p13ext = distanceFormula(sx1,sy1, p13extX,p13extY); len3_p13ext = distanceFormula(sx3,sy3, p13extX,p13extY); len2_p23ext = distanceFormula(sx2,sy2, p23extX,p23extY); len3_p23ext = distanceFormula(sx3,sy3, p23extX,p23extY); //g.setColor(Color.GRAY); excircle12X = (sx1*len2_p12ext + sx2*len1_p12ext + p12extX*len12) / (len12 + len1_p12ext + len2_p12ext); excircle12Y = (sy1*len2_p12ext + sy2*len1_p12ext + p12extY*len12) / (len12 + len1_p12ext + len2_p12ext); excircle12R = 2*heronArea(len12,len1_p12ext,len2_p12ext) / (len12+len1_p12ext+len2_p12ext); excircle13X = (sx1*len3_p13ext + sx3*len1_p13ext + p13extX*len13) / (len13 + len1_p13ext + len3_p13ext); excircle13Y = (sy1*len3_p13ext + sy3*len1_p13ext + p13extY*len13) / (len13 + len1_p13ext + len3_p13ext); excircle13R = 2*heronArea(len13,len1_p13ext,len3_p13ext) / (len13+len1_p13ext+len3_p13ext); excircle23X = (sx2*len3_p23ext + sx3*len2_p23ext + p23extX*len23) / (len23 + len2_p23ext + len3_p23ext); excircle23Y = (sy2*len3_p23ext + sy3*len2_p23ext + p23extY*len23) / (len23 + len2_p23ext + len3_p23ext); excircle23R = 2*heronArea(len23,len2_p23ext,len3_p23ext) / (len23+len2_p23ext+len3_p23ext); if (showExcircle) { g.setColor(Color.GRAY); g.drawLine(0,height-(int)((ext1m*-sx1+sy1)/scale), width,height-(int)((ext1m*(width*scale-sx1)+sy1)/scale)); g.drawLine(0,height-(int)((ext2m*-sx2+sy2)/scale), width,height-(int)((ext2m*(width*scale-sx2)+sy2)/scale)); g.drawLine(0,height-(int)((ext3m*-sx3+sy3)/scale), width,height-(int)((ext3m*(width*scale-sx3)+sy3)/scale)); g.fillRect((int)(excircle12X/scale), height-(int)(excircle12Y/scale) ,2,2); g.drawOval((int)((excircle12X-excircle12R)/scale), height-(int)((excircle12Y+excircle12R)/scale), 2*(int)(excircle12R/scale),2*(int)(excircle12R/scale)); g.fillRect((int)(excircle13X/scale), height-(int)(excircle13Y/scale) ,2,2); g.drawOval((int)((excircle13X-excircle13R)/scale), height-(int)((excircle13Y+excircle13R)/scale), 2*(int)(excircle13R/scale),2*(int)(excircle13R/scale)); g.fillRect((int)(excircle23X/scale), height-(int)(excircle23Y/scale) ,2,2); g.drawOval((int)((excircle23X-excircle23R)/scale), height-(int)((excircle23Y+excircle23R)/scale), 2*(int)(excircle23R/scale),2*(int)(excircle23R/scale)); } // } double ang1Bid, ang2Bid, ang3Bid; ang1Bid = distanceFormula(xincircle,yincircle, sx1,sy1); ang2Bid = distanceFormula(xincircle,yincircle, sx2,sy2); ang3Bid = distanceFormula(xincircle,yincircle, sx3,sy3); /* g.drawLine(x1,height-y1,0,height-(int)bB12_13); g.drawLine(x1,height-y1,1000,height-(int)(mB12_13*1000+bB12_13)); g.setColor(Color.PINK); g.drawLine(x1,height-y1,0,height-(int)bBp12_13); g.drawLine(x1,height-y1,1000,height-(int)(mBp12_13*1000+bBp12_13)); g.setColor(Color.MAGENTA); g.drawLine(x2,height-y2,0,height-(int)bB12_23); g.drawLine(x2,height-y2,1000,height-(int)(mB12_23*1000+bB12_23)); g.setColor(Color.PINK); g.drawLine(x2,height-y2,0,height-(int)bBp12_23); g.drawLine(x2,height-y2,1000,height-(int)(mBp12_23*1000+bBp12_23)); g.setColor(Color.MAGENTA); g.drawLine(x3,height-y3,0,height-(int)bB13_23); g.drawLine(x3,height-y3,1000,height-(int)(mB13_23*1000+bB13_23)); g.setColor(Color.PINK); g.drawLine(x3,height-y3,0,height-(int)bBp13_23); g.drawLine(x3,height-y3,1000,height-(int)(mBp13_23*1000+bBp13_23)); */ int leftstart=30, linelength=15, ystart=50, ygap=21; g.setColor( Color.BLUE ); g.drawLine(leftstart,ystart,leftstart+linelength,ystart); g.drawString(" medians: CENTROID:("+d2.format(xc)+","+d2.format(yc)+")",leftstart+linelength,ystart+4); g.setColor( Color.RED ); g.drawLine(leftstart,ystart+1*ygap,leftstart+linelength,ystart+1*ygap); g.drawString(" perpendicular bisectors: CIRCUMCENTER:("+d2.format(xcircum)+","+d2.format(ycircum)+")"+ " r:"+d2.format(rCircum),leftstart+linelength,ystart+1*ygap+4); g.setColor( Color.GREEN ); g.drawLine(leftstart,ystart+2*ygap,leftstart+linelength,ystart+2*ygap); g.drawString(" altitudes: ORTHOCENTER:("+d2.format(xortho)+","+d2.format(yortho)+")", leftstart+linelength,ystart+2*ygap+4); g.setColor( Color.CYAN ); g.drawLine(leftstart,ystart+3*ygap,leftstart+linelength,ystart+3*ygap); g.drawString(" nine-point circle: ("+d2.format(x9pt)+","+d2.format(y9pt)+")"+ " r:"+d2.format(r9pt)+" (=1/2 circumcircle)",leftstart+linelength,ystart+3*ygap+4); g.setColor( Color.MAGENTA ); g.drawLine(leftstart,ystart+4*ygap,leftstart+linelength,ystart+4*ygap); g.drawString(" angle bisectors: INCIRCLE: ("+d2.format(xincircle)+","+d2.format(yincircle)+")"+ " r:"+d2.format(inradius)+" (=2A/P)",leftstart+linelength,ystart+4*ygap+4); g.setColor( Color.GRAY ); g.drawLine(leftstart,ystart+5*ygap,leftstart+linelength,ystart+5*ygap); g.drawString(" exterior angle bisectors. EXCIRCLES",leftstart+linelength,ystart+5*ygap+4); g.setColor( Color.YELLOW ); g.drawLine(leftstart,ystart+6*ygap,leftstart+linelength,ystart+6*ygap); g.drawString(" Euler line",leftstart+linelength,ystart+6*ygap+4); g.setColor( Color.BLACK ); g.drawString("area="+d2.format(area),width-300,12); g.drawString("perimeter="+d2.format(len12+len13+len23),width-300,22); String triType="scalene"; if ((int)(ang1*100)/100==60 || (int)(ang2*100)/100==60 || (int)(ang3*100)/100==60) //instead of below which doesn't work triType = "equilateral"; //with .01 degree // 44.57 31.29 102.57 31.29 73.57 81.519 if (len12==len13 || len12==len23 || len13==len23) if (len12==len13 && len12==len23) //not working?? triType = "equilateral"; else triType = "isosceles"; g.drawString(triType,width-300,32); String triTypeAngs="acute"; //unless otherwise below //System.out.println("m12="+m12+" m13="+m13+" m23="+m23+" mp12="+mp12+" mp13="+mp13+" mp23="+mp23); double[] sides ={len12,len13,len23}; Arrays.sort(sides); a = sides[0]; b=sides[1]; c=sides[2]; //if (m12==-mp13 || m12==-mp23 || m13==-mp23) //doesn't work? //if (a*a+b*b == c*c) //rounding error doesn't let it happen //showStatus("a="+a+" b="+b+" c="+c); if (ang1==90 || ang2==90 || ang3==90) triTypeAngs = "right"; else if (a*a+b*b < c*c) triTypeAngs = "obtuse"; //check for obtuse g.drawString(triTypeAngs,width-200,32); if (m12==Double.NEGATIVE_INFINITY || m12==Double.POSITIVE_INFINITY) g.drawString("12 Eq: m=Infinity b=?",width-300,52); else g.drawString("12 Eq: m="+((int)(m12*100)/100.)+" b="+((int)(b12*100)/100.),width-300,52); if (m13==Double.NEGATIVE_INFINITY || m13==Double.POSITIVE_INFINITY) g.drawString("13 Eq: m=Infinity b=?",width-300,62); else g.drawString("13 Eq: m="+((int)(m13*100)/100.)+" b="+((int)(b13*100)/100.),width-300,62); if (m23==Double.NEGATIVE_INFINITY || m23==Double.POSITIVE_INFINITY) g.drawString("23 Eq: m=Infinity b=?",width-300,72); else g.drawString("23 Eq: m="+((int)(m23*100)/100.)+" b="+((int)(b23*100)/100.),width-300,72); g.drawString("12 len="+d2.format(len12)+" midpt=("+d2.format(x12mid)+","+d2.format(y12mid)+")",width-300,82); g.drawString("13 len="+d2.format(len13)+" midpt=("+d2.format(x13mid)+","+d2.format(y13mid)+")",width-300,92); g.drawString("23 len="+d2.format(len23)+" midpt=("+d2.format(x23mid)+","+d2.format(y23mid)+")",width-300,102); //DecimalFormat d2 = new DecimalFormat ("0.00"); g.drawString("angle 1="+d2.format(ang1)+"\u00B0", width-300,112); g.drawString("angle 2="+d2.format(ang2)+"\u00B0", width-300,122); g.drawString("angle 3="+d2.format(ang3)+"\u00B0", width-300,132); g.setColor( Color.YELLOW ); g.drawString("Euler line d: "+d2.format(eulerLength),width-300,142); g.setColor( Color.CYAN ); g.drawString("midpt:("+d2.format(x9pt)+","+d2.format(y9pt)+")",width-150,142); g.setColor( Color.GREEN ); g.drawString("orthoC",width-300,152); g.setColor( Color.BLUE ); g.drawString(" centroidC",width-250,152); g.setColor( Color.YELLOW ); g.drawString(" = d: "+d2.format(orthoCentroidDistance)+" (2/3)",width-180,152); g.setColor( Color.RED ); g.drawString("circumC",width-300,162); g.setColor( Color.BLUE ); g.drawString(" centroidC",width-250,162); g.setColor( Color.YELLOW ); g.drawString(" + d: "+d2.format(circumCentroidDistance)+" (1/3)",width-180,162); g.setColor( Color.BLUE ); g.drawString("median1 d: "+d2.format(median1Length),width-300,182); g.drawString("V1 to centroid d: "+d2.format(vertex1CentroidLength),width-150,182); g.drawString("median2 d: "+d2.format(median2Length),width-300,192); g.drawString("V2 to centroid d: "+d2.format(vertex2CentroidLength),width-150,192); g.drawString("median3 d: "+d2.format(median3Length),width-300,202); g.drawString("V3 to centroid d: "+d2.format(vertex3CentroidLength),width-150,202); /*double area12, area13, area23; //subtriangles about centroid. Each 1/3 total area area12 = heronArea(len12,vertex1CentroidLength,vertex2CentroidLength); area13 = heronArea(len13,vertex1CentroidLength,vertex3CentroidLength); area23 = heronArea(len23,vertex2CentroidLength,vertex3CentroidLength); showStatus("area12="+area12+" area13="+area13+" area23="+area23);*/ g.drawString(" each subtriangle about centroid area="+d2.format(area/3),width-300,212); g.setColor( Color.RED ); g.drawString("perpendicular bisector 12 d: "+d2.format(perpBi1d),width-300,222); g.drawString("perpendicular bisector 13 d: "+d2.format(perpBi2d),width-300,232); g.drawString("perpendicular bisector 23 d: "+d2.format(perpBi3d),width-300,242); g.setColor( Color.GREEN ); g.drawString("altitude 1 d: "+d2.format(alt1d)+" ("+d2.format(xAlt23)+","+d2.format(yAlt23)+ ") V1\u2192orthoC d: "+d2.format(v1_orthoCd),width-300,262); g.drawString("altitude 2 d: "+d2.format(alt2d)+" ("+d2.format(xAlt13)+","+d2.format(yAlt13)+ ") V2\u2192orthoC d: "+d2.format(v2_orthoCd),width-300,272); g.drawString("altitude 3 d: "+d2.format(alt3d)+" ("+d2.format(xAlt12)+","+d2.format(yAlt12)+ ") V3\u2192orthoC d: "+d2.format(v3_orthoCd),width-300,282); g.setColor( Color.MAGENTA ); g.drawString("angle 1 bisector to incircleC d: "+d2.format(ang1Bid),width-300,302); g.drawString("angle 2 bisector to incircleC d: "+d2.format(ang2Bid),width-300,312); g.drawString("angle 3 bisector to incircleC d: "+d2.format(ang3Bid),width-300,322); g.setColor( Color.GRAY ); g.drawString("excircle 12: ("+d2.format(excircle12X)+","+d2.format(excircle12Y)+ ") r="+d2.format(excircle12R),width-300,342); g.drawString("excircle 13: ("+d2.format(excircle13X)+","+d2.format(excircle13Y)+ ") r="+d2.format(excircle13R),width-300,352); g.drawString("excircle 23: ("+d2.format(excircle23X)+","+d2.format(excircle23Y)+ ") r="+d2.format(excircle23R),width-300,362); g.setColor( Color.BLACK ); g.drawLine( (int)(sx1/scale), height-(int)(sy1/scale), (int)(sx2/scale), height-(int)(sy2/scale) ); //triangle's lines g.drawLine( (int)(sx1/scale), height-(int)(sy1/scale), (int)(sx3/scale), height-(int)(sy3 /scale)); g.drawLine( (int)(sx3/scale), height-(int)(sy3/scale), (int)(sx2/scale), height-(int)(sy2/scale) ); //"bold" the lines g.drawLine( (int)(sx1/scale)+1, height-((int)(sy1/scale)+1), (int)(sx2/scale)+1, height-((int)(sy2/scale)+1) ); //triangle's lines g.drawLine( (int)(sx1/scale)+1, height-((int)(sy1/scale)+1), (int)(sx3/scale)+1, height-((int)(sy3/scale)+1) ); g.drawLine( (int)(sx3/scale)+1, height-((int)(sy3/scale)+1), (int)(sx2/scale)+1, height-((int)(sy2/scale)+1) ); g.drawLine( (int)(sx1/scale)+1, height-((int)(sy1/scale)), (int)(sx2/scale)+1, height-((int)(sy2/scale)) ); //triangle's lines g.drawLine( (int)(sx1/scale)+1, height-((int)(sy1/scale)), (int)(sx3/scale)+1, height-((int)(sy3/scale)) ); g.drawLine( (int)(sx3/scale)+1, height-((int)(sy3/scale)), (int)(sx2/scale)+1, height-((int)(sy2/scale)) ); g.drawLine( (int)(sx1/scale), height-((int)(sy1/scale)+1), (int)(sx2/scale), height-((int)(sy2/scale)+1) ); //triangle's lines g.drawLine( (int)(sx1/scale), height-((int)(sy1/scale)+1), (int)(sx3/scale), height-((int)(sy3/scale)+1) ); g.drawLine( (int)(sx3/scale), height-((int)(sy3/scale)+1), (int)(sx2/scale), height-((int)(sy2/scale)+1) ); g.drawString("("+d2.format(sx1)+","+d2.format(sy1)+")",(int)(sx1/scale),height-(int)(sy1/scale)); g.drawString("("+d2.format(sx2)+","+d2.format(sy2)+")",(int)(sx2/scale),height-(int)(sy2/scale)); g.drawString("("+d2.format(sx3)+","+d2.format(sy3)+")",(int)(sx3/scale),height-(int)(sy3/scale)); g.setFont( new Font( "Serif", Font.BOLD, 16 ) ); if (sx1sy2 && sy1>sy3) //leftmost or topmost g.drawString("1",(int)(sx1/scale)-12,height-(int)(sy1/scale)); else g.drawString("1",(int)(sx1/scale),height-(int)(sy1/scale)+13); //put it below me if (sx2sy1 && sy2>sy3) //leftmost or topmost g.drawString("2",(int)(sx2/scale)-12,height-(int)(sy2/scale)); else g.drawString("2",(int)(sx2/scale),height-(int)(sy2/scale)+13); if (sx3sy1 && sy3>sy2) //leftmost or topmost g.drawString("3",(int)(sx3/scale)-12,height-(int)(sy3/scale)); else g.drawString("3",(int)(sx3/scale),height-(int)(sy3/scale)+13); //redraw the various centers: g.setColor( Color.CYAN ); //midpts g.fillOval((int)(x12mid/scale)-2,height-(int)(y12mid/scale)-2,3,3); g.fillOval((int)(x13mid/scale)-2,height-(int)(y13mid/scale)-2,3,3); g.fillOval((int)(x23mid/scale)-2,height-(int)(y23mid/scale)-2,3,3); g.setColor( Color.BLUE ); //centroid g.fillOval((int)(xc/scale)-2,height-(int)(yc/scale)-2,4,4); g.setColor( Color.RED ); //circumcenter g.fillOval((int)(xcircum/scale)-2,height-(int)(ycircum/scale)-2,4,4); g.setColor( Color.GREEN ); //orthocenter g.fillOval((int)(xortho/scale)-2,height-(int)(yortho/scale)-2,4,4); g.setColor( Color.CYAN ); //9-point g.fillOval((int)(x9pt/scale)-2,height-(int)(y9pt/scale)-2,4,4); if (xincircle != -999) { //incenter g.setColor(Color.MAGENTA); g.fillOval((int)(xincircle/scale)-2,height-(int)(yincircle/scale)-2,4,4); } } } public double distanceFormula (double x1, double y1, double x2, double y2){ return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); } public double heronArea(double a, double b, double c) { double s = .5 * (a+b+c); return Math.sqrt(s*(s-a)*(s-b)*(s-c)); } }