import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.border.*; import java.util.*; import java.text.*; public class Pyramid extends JApplet implements ActionListener { double alpha, beta, l, s, h, faceArea, volume; JPanel controlPanel; JLabel alphaLabel, betaLabel, lLabel, sLabel, hLabel, faceAreaLabel, volumeLabel; JTextField alphaTextField, betaTextField, lTextField, sTextField, hTextField, faceAreaTextField, volumeTextField; /* int endX, endY; //so mouseListener has access int rLen; int midX, midY; */ DecimalFormat d4, i1; public void init() { String input; d4 = new DecimalFormat ("0.0000"); i1 = new DecimalFormat ("0.00"); Container container = getContentPane(); 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); alphaLabel = new JLabel( "ANGLES \u03B1\u00B0" ); controlPanel.add( alphaLabel ); alphaTextField = new JTextField("60.0",4); alpha = Double.parseDouble(alphaTextField.getText()); alphaTextField.setHorizontalAlignment(JTextField.RIGHT); alphaTextField.addActionListener( this ); controlPanel.add( alphaTextField ); betaLabel = new JLabel( " \u03B2\u00B0" ); controlPanel.add( betaLabel ); //beta = Math.toRadians(alpha); betaTextField = new JTextField("0.1",4); //dummy value to avoid error betaTextField.setHorizontalAlignment(JTextField.RIGHT); betaTextField.addActionListener( this ); controlPanel.add( betaTextField ); hLabel = new JLabel( " LENGTHS: height h" ); controlPanel.add( hLabel ); hTextField = new JTextField("0.1",4); hTextField.setBackground(new Color(200,200,255)); hTextField.setHorizontalAlignment(JTextField.RIGHT); hTextField.addActionListener( this ); controlPanel.add( hTextField ); lLabel = new JLabel( " slant l" ); controlPanel.add( lLabel ); //l = chordLength(r,a); lTextField = new JTextField(".51",4); lTextField.setBackground(Color.YELLOW); lTextField.setHorizontalAlignment(JTextField.RIGHT); lTextField.addActionListener( this ); controlPanel.add( lTextField ); sLabel = new JLabel( " edge e" ); controlPanel.add( sLabel ); //h = heightLength(r,c); sTextField = new JTextField("0.708",4); sTextField.setBackground(Color.CYAN); sTextField.setHorizontalAlignment(JTextField.RIGHT); sTextField.addActionListener( this ); controlPanel.add( sTextField ); faceAreaLabel = new JLabel( " AREA: 1 face" ); controlPanel.add( faceAreaLabel ); //faceArea = sectorArea(r,a); faceAreaTextField = new JTextField("0.1",4); faceAreaTextField.setBackground(Color.PINK); faceAreaTextField.setHorizontalAlignment(JTextField.RIGHT); faceAreaTextField.addActionListener( this ); controlPanel.add( faceAreaTextField ); volumeLabel = new JLabel( " VOLUME" ); controlPanel.add( volumeLabel ); //triangleArea = triangleArea(r,a); volumeTextField = new JTextField("0.1",4); volumeTextField.setBackground(Color.PINK); volumeTextField.setHorizontalAlignment(JTextField.RIGHT); volumeTextField.addActionListener( this ); controlPanel.add( volumeTextField ); /*rLen = getHeight()/3; //mouseListener needs midX = getWidth()/2; midY = getHeight()/2; */ alphaTextField.postActionEvent(); //fires listener /* //incantation that responds to mouse move events: addMouseMotionListener( new MouseMotionAdapter() { public void mouseDragged( MouseEvent event) { int px = event.getX(); int py = event.getY(); double x=-999, y=-999; //inits to fake out compiler for showStatus double mouseDistance = distanceFormula(px,py, endX,endY); if (mouseDistance < 50) { //within 50 of endPoint if (a < 180) { //left right: px change x = (double)(px-midX)/rLen; if (x <= r && x >= -r) //avoid going under?? at 0 a = Math.toDegrees(Math.acos(x/r)); //if (a < 0) // ?? nope // a = 0; } else if (a > 180) { //left right: opp. of upper half circle x = (double)(midX-px)/rLen; if (x <= r && x >= -r) //avoid going under?? at 360 a = 180 + Math.toDegrees(Math.acos(x/r)); } else { //a==180 ?? if (py != midY) { //has to be at least one pixel above or below y = (double)(py-midY)/rLen; a = 180 + Math.toDegrees(Math.asin(y/r)); } } //showStatus("("+px+","+(getHeight()-py)+") x="+x+" y="+y+" a="+a); aTextField.setText(""+i1.format(a)); aTextField.postActionEvent(); } } } ); */ } public void setTextFields(double alpha, double beta, double h, double l, double s, double faceArea, double volume) { alphaTextField.setText(""+i1.format(alpha)); betaTextField.setText(""+i1.format(beta)); hTextField.setText(""+d4.format(h)); lTextField.setText(""+d4.format(l)); sTextField.setText(""+d4.format(s)); faceAreaTextField.setText(""+d4.format(faceArea)); volumeTextField.setText(""+d4.format(volume)); } public void actionPerformed( ActionEvent event ) { try { double alphaTry = Double.parseDouble(alphaTextField.getText()); if (alphaTry<=45 || alphaTry>=90) { JOptionPane.showMessageDialog(null, "angle must be between 45 and 90 degrees"+ "\n(45 is flat, 90 is infinitely tall)", "Pyramid: Invalid ANGLE DEGREES input", JOptionPane.ERROR_MESSAGE); return; } double betaTry = Double.parseDouble(betaTextField.getText()); if (betaTry<=0 || betaTry>=90) { JOptionPane.showMessageDialog(null, "angle must be between 0 and 90 degrees"+ "\n(0 is flat, 90 is infinitely tall)", "Pyramid: Invalid ANGLE input", JOptionPane.ERROR_MESSAGE); return; } double hTry = Double.parseDouble(hTextField.getText()); if (hTry<=0) { JOptionPane.showMessageDialog(null, "height length must be greater than 0", "Pyramid: Invalid HEIGHT input", JOptionPane.ERROR_MESSAGE); return; } double lTry = Double.parseDouble(lTextField.getText()); if (lTry<=0.5) { JOptionPane.showMessageDialog(null, "slant length must be greater than 0.5"+ "\n(0.5 is flat)", "Pyramid: Invalid slant length input", JOptionPane.ERROR_MESSAGE); return; } double sTry = Double.parseDouble(sTextField.getText()); if (sTry<1/Math.sqrt(2)) { JOptionPane.showMessageDialog(null, "edge length must be greater than 0.707"+ "\n(root 2 is flat)", "Pyramid: Invalid edge LENGTH input", JOptionPane.ERROR_MESSAGE); return; } double faceTry = Double.parseDouble(faceAreaTextField.getText()); if (faceTry<=0) { //FIX JOptionPane.showMessageDialog(null, "face area must be greater than 0 ", "Pyramid: Invalid FACE AREA input", JOptionPane.ERROR_MESSAGE); return; } double volumeTry = Double.parseDouble(volumeTextField.getText()); if (volumeTry<=0) { //FIX JOptionPane.showMessageDialog(null, "volume must be greater than 0 ", "Pyramid: Invalid VOLUME input", JOptionPane.ERROR_MESSAGE); return; } } catch (NumberFormatException e) { JOptionPane.showMessageDialog(null, "all values must be numbers", "Pyramid: Invalid input", JOptionPane.ERROR_MESSAGE); return; } if ( event.getSource() == alphaTextField ) { alpha = Double.parseDouble(alphaTextField.getText()); l = Math.tan(Math.toRadians(alpha)) / 2; s = Math.sqrt(l*l + 0.25); h = Math.sqrt(l*l - 0.25); beta = Math.toDegrees(Math.asin(h/l)); faceArea = l / 4; volume = h / 3; setTextFields(alpha,beta,h,l,s,faceArea,volume); repaint(); } else if ( event.getSource() == lTextField ) { l = Double.parseDouble(lTextField.getText()); alpha = Math.toDegrees(Math.atan(2*l)); alphaTextField.setText(""+i1.format(alpha)); alphaTextField.postActionEvent(); //fires its listener } else if ( event.getSource() == hTextField ) { h = Double.parseDouble(hTextField.getText()); l = Math.sqrt(h*h + 0.25); lTextField.setText(""+i1.format(l)); lTextField.postActionEvent(); //fires l's listener, which will fire alpha's } else if ( event.getSource() == sTextField ) { s = Double.parseDouble(sTextField.getText()); l = Math.sqrt(s*s - 0.25); lTextField.setText(""+i1.format(l)); lTextField.postActionEvent(); } else if ( event.getSource() == betaTextField ) { beta = Double.parseDouble(betaTextField.getText()); l = 1 / (2 * Math.cos(Math.toRadians(beta))); lTextField.setText(""+i1.format(l)); lTextField.postActionEvent(); } /* else if ( event.getSource() == sectorAreaTextField ) { sectorArea = Double.parseDouble(sectorAreaTextField.getText()); a = 360*sectorArea / (Math.PI*r*r); aTextField.setText(""+i1.format(a)); aTextField.postActionEvent(); //fires its listener } else if ( event.getSource() == triangleAreaTextField ) { triangleArea = Double.parseDouble(triangleAreaTextField.getText()); a = Math.toDegrees(Math.asin(2*triangleArea/(r*r))); aTextField.setText(""+i1.format(a)); aTextField.postActionEvent(); //fires its listener } */ } public void paint (Graphics g) { super.paint( g ); //erase g.setFont( new Font( "SansSerif", Font.BOLD, 12 ) ); g.drawString("Set any parameter ",5,50); int w = getWidth(); int h = getHeight(); int baseW=200; int xstart=5, ystart=100; g.drawRect(xstart,ystart, baseW,baseW); g.drawString("1",xstart+5,ystart+baseW/2); g.setColor(Color.CYAN); int apexX, apexY; apexX = (int)(xstart+baseW + l*baseW); apexY = (int)(ystart+baseW/2.0); g.drawLine(xstart+baseW,ystart, apexX,apexY); g.drawLine(xstart+baseW,ystart+baseW, apexX,apexY); g.setColor(Color.BLACK); g.drawString("\u03B1",xstart+baseW+3,ystart+18); g.drawString("\u03B2",xstart+baseW-8,ystart+baseW/2+50); g.drawString("e",(xstart+baseW+apexX)/2,(ystart+apexY)/2); g.setColor(Color.YELLOW); g.drawLine(xstart+baseW,ystart+baseW/2, apexX,apexY); g.setColor(Color.BLACK); g.drawString("l",(int)(xstart+baseW+l*baseW/2),ystart+baseW/2); /* g.drawString("("+d4.format(Math.cos(Math.toRadians(a))*r)+","+ d4.format(Math.sin(Math.toRadians(a))*r)+")", endX,endY); //arc g.setColor(Color.PINK); g.drawArc(midX-rLen,midY-rLen,2*rLen,2*rLen, 0,(int)a); //data on screen g.setColor( Color.BLACK ); g.drawString("area="+d4.format(Math.PI*r*r),w-200,45); g.drawString("circumference="+d4.format(2*Math.PI*r),w-200,60); if (a < 180) { g.setColor( Color.CYAN); g.drawString("base midpoint ("+d4.format((r+Math.cos(Math.toRadians(a))*r)/2)+ ","+d4.format(Math.sin(Math.toRadians(a))*r/2)+")",w-200,75); } */ } public double chordLength(double r, double a) { return Math.sqrt(2*r*r - 2*r*r*Math.cos(Math.toRadians(a))); } //height of isocelese triangle public double heightLength(double r, double c) { return Math.sqrt(r*r - c*c/4); } public double arcLength(double r, double a) { return 2*Math.PI*r * (a/360); } public double triangleArea(double r, double a) { return r*r/2 * Math.sin(Math.toRadians(a)); } public double sectorArea(double r, double a) { return Math.PI*r*r * (a/360); } public double distanceFormula (double x1, double y1, double x2, double y2){ return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); } //use Newton's method to solve g=PIr^2*Alpha/360 - r^2/2*sin(Alpha2PI/360) //letting x=Alpha2PI/360 K=2g/r^2. g is segmentArea // K=x-sin(x) //f(x)=K-x+sin(x) f'(x)=-1+cos(x) //x(n+1)=x(n) - (K-xn+sin(xn))/(-1+cos(xn) //Thanks to Andy Won for this math. //returns alpha in degrees. alpha=2PI/360 x public double NewtonsAlpha(double r, double g) { double xn, xn1=1, fx; //fakeout compiler double K=2*g/(r*r); xn = 1; //initial value. crucial choice. implies alpha=57 (1 rad) OK? fx = K - xn + Math.sin(xn); int iterations=1; while (Math.abs(fx) > .00001 && iterations<200) { //no more than 200 loops? .00001 OK? xn1 = xn - fx/(-1+Math.cos(xn)); fx = K - xn1 + Math.sin(xn1); xn = xn1; iterations++; } //seems to work for any segmentArea between 0 and semicircleArea (alpha=180) showStatus("iterations"+iterations); return 180/Math.PI * xn1; } }