//SphericalCap.java 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 SphericalCap extends JApplet implements ActionListener { double r, h, a, alpha; JLabel rLabel, aLabel, alphaLabel, hLabel; JTextField rTextField, aTextField, alphaTextField, hTextField; JLabel haHLabel, haALabel; JTextField haHField, haAField; int rLen; int midX, midY; DecimalFormat d2, d1; public void init() { String input; d2 = new DecimalFormat ("0.00"); d1 = new DecimalFormat ("0.0"); Container container = getContentPane(); //container.setLayout( new BorderLayout() ); container.setLayout(null); //** no Layout Manager JPanel controlPanel = new JPanel(); controlPanel.setLayout(new GridLayout(4,2)); controlPanel.setBackground(Color.MAGENTA); controlPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED)); controlPanel.setBounds(0,0, 150,100); container.add(controlPanel); JPanel haPanel = new JPanel(); haPanel.setLayout(new FlowLayout()); haPanel.setBackground(Color.MAGENTA); haPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED)); haPanel.setBounds(0,200, 150,30); container.add(haPanel); rLabel = new JLabel( "radius" ); controlPanel.add( rLabel ); rTextField = new JTextField("1.0",4); r = Double.parseDouble(rTextField.getText()); rTextField.setBackground(new Color(200,200,255)); //rTextField.setForeground(Color.WHITE); rTextField.setHorizontalAlignment(JTextField.RIGHT); rTextField.addActionListener( this ); controlPanel.add( rTextField ); hLabel = new JLabel( "h" ); controlPanel.add( hLabel ); h = 0.5; hTextField = new JTextField(""+d2.format(h),4); hTextField.setBackground(Color.PINK); hTextField.setHorizontalAlignment(JTextField.RIGHT); hTextField.addActionListener( this ); controlPanel.add( hTextField ); aLabel = new JLabel( "a" ); controlPanel.add( aLabel ); a = aLength(r,h); aTextField = new JTextField(""+d2.format(a),4); aTextField.setBackground(Color.CYAN); aTextField.setHorizontalAlignment(JTextField.RIGHT); aTextField.addActionListener( this ); controlPanel.add( aTextField ); alphaLabel = new JLabel( "contact \u00B0" ); controlPanel.add( alphaLabel ); alpha = contactAngle(r,h); alphaTextField = new JTextField(""+d2.format(alpha),4); alphaTextField.setBackground(Color.YELLOW); alphaTextField.setHorizontalAlignment(JTextField.RIGHT); alphaTextField.addActionListener( this ); controlPanel.add( alphaTextField ); //the h and a together panel haHLabel = new JLabel( "h" ); haPanel.add( haHLabel ); //h = 0.5; haHField = new JTextField("",4); haHField.setBackground(Color.PINK); haHField.setHorizontalAlignment(JTextField.RIGHT); haHField.addActionListener( this ); haPanel.add( haHField ); haALabel = new JLabel( "a" ); haPanel.add( haALabel ); //h = 0.5; haAField = new JTextField("",4); haAField.setBackground(Color.CYAN); haAField.setHorizontalAlignment(JTextField.RIGHT); haAField.addActionListener( this ); haPanel.add( haAField ); rLen = getHeight()/2-20; //mouseListener needs //hLen = (int)(rLen*(h/r)); midX = getWidth()/2; midY = getHeight()/2; rTextField.setText("1.0"); rTextField.postActionEvent(); //fires listener addMouseMotionListener( new MouseMotionAdapter() { public void mouseDragged( MouseEvent event) { int px = event.getX(); int py = event.getY(); int hLen = (int)(rLen*(h/r)); int dy; double mouseDistance = distanceFormula(px,py, midX,midY-rLen+hLen); if (mouseDistance < 30) { //within 30 of h-a intersection point dy = midY - py; //(double)py/rLen; if (dy>=0 && dy<=rLen) { h = r- r*(double)dy/rLen; //showStatus("h="+h); hTextField.setText(""+d2.format(h)); hTextField.postActionEvent(); } } } } ); } public void setTextFields(double r, double h, double a, double alpha ) { rTextField.setText(""+d2.format(r)); hTextField.setText(""+d2.format(h)); aTextField.setText(""+d2.format(a)); alphaTextField.setText(""+d2.format(alpha)); } public void actionPerformed( ActionEvent event ) { double haATry, haHTry; try { double rTry = Double.parseDouble(rTextField.getText()); if (rTry<0) { JOptionPane.showMessageDialog(null, "radius must be greater than 0", "SphericalCap: Invalid RADIUS input", JOptionPane.ERROR_MESSAGE); return; } double hTry = Double.parseDouble(hTextField.getText()); if (hTry<0 || hTry>r) { JOptionPane.showMessageDialog(null, "height length must be between 0 and radius", "SphericalCap: Invalid h input", JOptionPane.ERROR_MESSAGE); return; } double aTry = Double.parseDouble(aTextField.getText()); if (aTry<0 || aTry>r) { JOptionPane.showMessageDialog(null, "a length must be between 0 and radius", "SphericalCap: Invalid a input", JOptionPane.ERROR_MESSAGE); return; } double alphaTry = Double.parseDouble(alphaTextField.getText()); if (alphaTry<0 || alphaTry>90) { JOptionPane.showMessageDialog(null, "angle must be between 0 and 90 degrees", "SphericalCap: Invalid ANGLE DEGREES input", JOptionPane.ERROR_MESSAGE); return; } if (!haHField.getText().equals("")) { haHTry = Double.parseDouble(haHField.getText()); if (haHTry<0) { JOptionPane.showMessageDialog(null, "height must be greater than 0", "SphericalCap: Invalid height input", JOptionPane.ERROR_MESSAGE); return; } } if (!haAField.getText().equals("")) { haATry = Double.parseDouble(haAField.getText()); if (haATry<0) { JOptionPane.showMessageDialog(null, "'a' must be greater than 0", "SphericalCap: Invalid 'a' input", JOptionPane.ERROR_MESSAGE); return; } /* else if (haATry < haHTry) { JOptionPane.showMessageDialog(null, "'a' must be greater than height h", "SphericalCap: Invalid 'a' input", JOptionPane.ERROR_MESSAGE); return; } */ } } catch (NumberFormatException e) { JOptionPane.showMessageDialog(null, "all values must be numbers", "SphericalCap: Invalid input", JOptionPane.ERROR_MESSAGE); return; } if ( event.getSource() == alphaTextField ) { alpha = Double.parseDouble(alphaTextField.getText()); h = hLengthAlpha(r,alpha); a = aLength(r,h); setTextFields(r,h,a,alpha); repaint(); } else if ( event.getSource() == rTextField ) { double newR = Double.parseDouble(rTextField.getText()); h = h * newR/r; r = newR; a = aLength(r,h); alpha = contactAngle(r,h); setTextFields(r,h,a,alpha); repaint(); } else if ( event.getSource() == aTextField ) { a = Double.parseDouble(aTextField.getText()); h = hLength(r,a); alpha = contactAngle(r,h); setTextFields(r,h,a,alpha); repaint(); } else if ( event.getSource() == hTextField ) { h = Double.parseDouble(hTextField.getText()); a = aLength(r,h); alpha = contactAngle(r,h); setTextFields(r,h,a,alpha); repaint(); } else if (event.getSource()==haHField && !haAField.getText().equals("") || event.getSource()==haAField && !haHField.getText().equals("")) { if (Double.parseDouble(haHField.getText()) > Double.parseDouble(haAField.getText())) { JOptionPane.showMessageDialog(null, "'a' must be greater than height h", "SphericalCap: Invalid 'a' input", JOptionPane.ERROR_MESSAGE); return; } h = Double.parseDouble(haHField.getText()); a = Double.parseDouble(haAField.getText()); r = rLength(h,a); alpha = contactAngle(r,h); setTextFields(r,h,a,alpha); haHField.setText(""); haAField.setText(""); repaint(); } } public void paint (Graphics g) { super.paint( g ); //erase g.setFont( new Font( "SansSerif", Font.BOLD, 12 ) ); int w = getWidth(); int he = getHeight(); int hLen = (int)(rLen*(h/r)); int aLen = (int)(rLen*(a/r)); g.drawString("Set any parameter ",5,130); g.drawString("OR Drag h-a intersection point up or down",5,145); g.drawString("h and a determine r. Enter both.",5,190); int arcH=(int)(hLen/4.0); //g.setColor(Color.PINK); g.setColor(Color.MAGENTA); g.fillArc(midX-aLen,midY-(rLen-hLen)-arcH,2*aLen,2*arcH, 0,360); //arc piece below 'a' line //within bounding box, if point within rLen of origin for (int x=midX-aLen; x<=midX+aLen; x++) for (int y=midY-(rLen-hLen)-hLen; y<=midY-(rLen-hLen); y++) if (distanceFormula(x,y,midX,midY) <=rLen) g.drawLine(x,y,x,y); //arc is of an oval in the bounding box. is not the cap of circle //g.fillArc(midX-aLen,midY-(rLen-hLen)-hLen,2*aLen,2*hLen, 0,180); g.setColor(Color.BLACK); g.drawArc(midX-aLen,midY-(rLen-hLen)-arcH,2*aLen,2*arcH, 0,360); g.drawOval(midX-rLen, midY-rLen, 2*rLen, 2*rLen); g.fillRect(midX-1,midY-1, 3,3); g.setColor(Color.BLUE); g.drawLine(midX,midY, midX ,midY-rLen); g.setColor(Color.RED); g.drawLine(midX,midY-rLen, midX,midY-rLen+hLen); g.drawString(""+d2.format(h),midX+2,midY-rLen+hLen/2); g.setColor(Color.BLACK); g.drawString("h",midX-10,midY-rLen+hLen/2); g.setColor(Color.CYAN); g.drawLine(midX,midY-rLen+hLen, midX+aLen,midY-rLen+hLen); g.drawString(""+d2.format(a),midX+aLen/2,midY-rLen+hLen+10); g.setColor(Color.BLACK); g.drawString("a",midX+aLen/3,midY-rLen+hLen+10); g.drawLine(midX,midY, midX+aLen,midY-rLen+hLen); g.drawString("r",(midX+midX+aLen)/2-5,(midY+midY-rLen+hLen)/2+10); g.setColor(Color.GREEN); int centroidH = (int)(rLen*(centroid(r,h)/r)); g.fillRect(midX-1,midY-centroidH, 3,3); g.setColor(Color.YELLOW); int aX, aY, aX2, aY2, aX3, aY3; aX = (int)(Math.cos(Math.toRadians(alpha)) * rLen + midX); aY = he - (int)(Math.sin(Math.toRadians(alpha)) * rLen + midY); double mNR = -1.0 / ((double)(aY-midY)/(aX-midX)); g.drawLine(0,(int)(aY-mNR*aX), w,(int)(mNR*w+aY-mNR*aX)); if (alpha < 70) g.fillArc(aX-15,aY-15,30,30, 180,(int)alpha); else if (alpha < 85) g.drawArc(aX-15,aY-15,30,30, 180,(int)alpha); if (alpha == 0) //vertical g.drawLine(aX,0, aX,he); //data on screen double hemiVol, hemiArea, capVol, capArea; hemiVol = 2.0/3*Math.PI*r*r*r; hemiArea = 2*Math.PI*r*r; capVol = Math.PI*h*h/3*(3*r-h); capArea = 2*Math.PI*r*h; g.setColor( Color.BLACK ); g.drawString("Hemisphere volume="+d2.format(hemiVol),w-200,15); g.drawString("Hemisphere surface area="+d2.format(hemiArea),w-200,30); g.setColor( Color.MAGENTA); g.drawString("Cap volume="+d2.format(capVol),w-200,45); g.drawString(" "+d1.format(capVol/hemiVol*100)+"% of hemisphere volume",w-200,60); g.drawString("Cap surface area="+d2.format(capArea),w-200,75); g.drawString(" "+d1.format(capArea/hemiArea*100)+"% of hemisphere area",w-200,90); g.setColor( Color.BLACK ); g.drawString("h/a="+d2.format(h/a),w-200,105); g.setColor(Color.GREEN); g.drawString("geometric centroid="+d2.format(centroid(r,h)),w-200,125); } public double aLength(double r, double h) { return Math.sqrt(h*(2*r-h)); } public double hLength(double r, double a) { return r - Math.sqrt(r*r - a*a); } public double rLength(double h, double a) { return (a*a + h*h) / (2 * h); } //calculate h given r and (a new) alpha public double hLengthAlpha(double r, double alpha) { return r - r*Math.sin(Math.toRadians(alpha)); } public double contactAngle(double r, double h) { return Math.toDegrees(Math.asin((r-h)/r)); } public double centroid(double r, double h) { return (3*(2*r-h)*(2*r-h)) / (4*(3*r-h)); } public double distanceFormula (double x1, double y1, double x2, double y2){ return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); } }