import java.awt.*; import java.awt.event.*; import java.applet.*; import java.util.*; public class BouncyApplet extends Applet implements ActionListener{ Ball bert; int nRings = 100; double drop=0, press, mass, radius=10, decay, kappa, dt; Panel header, footer, basics, options, results; MyCanvas diagram; Timer myTimer; Label title, dropLbl, dropULbl, pressLbl, pressULbl, ctLbl, ct, fpLbl,fp, efLbl, ef; TextField dropTxF, pressTxF, nRingsTxF, dtTxF, radiusTxF, massTxF, kappaTxF, decayTxF; Button goBtn, optBtn; int y = 0; // needed for graphical output of error reporting boolean ok = true; public void init() { setBackground(Color.white); setFont(new Font("SansSerif", Font.PLAIN,14)); setLayout(new BorderLayout()); GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); header = new Panel(gridbag); optBtn = new Button("show options"); optBtn.setFont(new Font("SanSerif",Font.ITALIC,14)); c.weightx = 1; gridbag.setConstraints(optBtn, c); header.add(optBtn); title = new Label("Bouncy Ball"); title.setFont(new Font("Serif", Font.ITALIC + Font.BOLD, 24)); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(title, c); header.add(title); footer = new Panel(new GridLayout(2,1)); results = new Panel(); ctLbl = new Label("Contact", Label.RIGHT); ct = new Label("time "); fpLbl = new Label("Footprint", Label.RIGHT); fp = new Label("diam. "); efLbl = new Label("Effic.", Label.RIGHT); ef = new Label(" % "); results.add(ctLbl); results.add(ct); results.add(fpLbl); results.add(fp); results.add(efLbl); results.add(ef); basics = new Panel(); dropLbl = new Label("Drop",Label.RIGHT); dropTxF = new TextField("1.0",4); dropULbl = new Label("m"); basics.add(dropLbl); basics.add(dropTxF); basics.add(dropULbl); pressLbl = new Label("Pressure",Label.RIGHT); pressTxF = new TextField("20",4); pressULbl = new Label("kPa "); basics.add(pressLbl); basics.add(pressTxF); basics.add(pressULbl); goBtn = new Button(" GO "); goBtn.setFont(new Font("SanSerif",Font.BOLD, 16)); basics.add(goBtn); // register the Listener: goBtn must send events somewhere. // In this case, we send them to the applet "this" which // therefore must have an "actionPerformed()" method. goBtn.addActionListener(this); footer.add(basics); footer.add(results); add(footer, BorderLayout.SOUTH); diagram = new MyCanvas(); add(diagram, BorderLayout.CENTER); validate(); optBtn.addActionListener(this); // register the Listener (this Applet) add(header, BorderLayout.NORTH); // options panel is displayed dynamically // uses flow layout with items grouped by using secondary panels GridBagLayout gb39 = new GridBagLayout(); GridBagConstraints c39 = new GridBagConstraints(); c39.fill = GridBagConstraints.HORIZONTAL; options = new Panel(gb39); options.setFont(new Font("SanSerif", Font.PLAIN, 14)); Label ballProps = new Label("The Ball ...."); ballProps.setFont(new Font("Serif", Font.ITALIC, 16)); c39.gridwidth = GridBagConstraints.REMAINDER; gb39.setConstraints(ballProps,c39); options.add(ballProps); c39.weightx = 1; Label radiusLbl = new Label("radius"); radiusTxF = new TextField("10",4); Label radiusULbl = new Label("cm"); c39.gridwidth = 1; gb39.setConstraints(radiusLbl,c39); gb39.setConstraints(radiusTxF,c39); c39.gridwidth = GridBagConstraints.REMAINDER; gb39.setConstraints(radiusULbl,c39); options.add(radiusLbl); options.add(radiusTxF); options.add(radiusULbl); Label massLbl = new Label("mass"); massTxF = new TextField("250",4); Label massULbl = new Label("g"); c39.gridwidth = 1; gb39.setConstraints(massLbl,c39); gb39.setConstraints(massTxF,c39); options.add(massLbl); options.add(massTxF); c39.gridwidth = GridBagConstraints.REMAINDER; gb39.setConstraints(massULbl,c39); options.add(massULbl); Label kappaLbl = new Label("el. mod."); kappaTxF = new TextField("25",4); Label kappaULbl = new Label("kN/m"); c39.gridwidth = 1; gb39.setConstraints(kappaLbl,c39); gb39.setConstraints(kappaTxF,c39); options.add(kappaLbl); options.add(kappaTxF); c39.gridwidth = GridBagConstraints.REMAINDER; gb39.setConstraints(kappaULbl,c39); options.add(kappaULbl); Label decayLbl = new Label("decay time"); decayTxF = new TextField("5",4); Label decayULbl = new Label("ms"); c39.gridwidth = 1; gb39.setConstraints(decayLbl,c39); gb39.setConstraints(decayTxF,c39); options.add(decayLbl); options.add(decayTxF); c39.gridwidth = GridBagConstraints.REMAINDER; gb39.setConstraints(decayULbl,c39); options.add(decayULbl); Label simPrec = new Label("Simulation"); simPrec.setFont(new Font("Serif", Font.ITALIC, 16)); c39.gridwidth = GridBagConstraints.REMAINDER; gb39.setConstraints(simPrec,c39); options.add(simPrec); Label nRingsLbl = new Label("no. of rings"); nRingsTxF = new TextField("100",4); Label nRingsULbl = new Label(" "); c39.gridwidth = 1; gb39.setConstraints(nRingsLbl,c39); gb39.setConstraints(nRingsTxF,c39); options.add(nRingsLbl); options.add(nRingsTxF); c39.gridwidth = GridBagConstraints.REMAINDER; gb39.setConstraints(nRingsULbl,c39); options.add(nRingsULbl); Label dtLbl = new Label("time step"); dtTxF = new TextField("10",4); Label dtULbl = new Label('\u00B5'+"s"); c39.gridwidth = 1; gb39.setConstraints(dtLbl,c39); gb39.setConstraints(dtTxF,c39); options.add(dtLbl); options.add(dtTxF); c39.gridwidth = GridBagConstraints.REMAINDER; gb39.setConstraints(dtULbl,c39); options.add(dtULbl); } public void start() { bert = new Ball(this); } public void actionPerformed(ActionEvent ae) { String str = ae.getActionCommand(); long msec ; if (str.equals(" GO ")) { if (dataOK()) { goBtn.setLabel("STOP"); bert = new Ball(this); ct.setText("time "); fp.setText("diam. "); ef.setText(" % "); MyTimerTask doFrame = new MyTimerTask(); myTimer = new Timer(); myTimer.scheduleAtFixedRate(doFrame,20,20); } else return; } else if (str.equals("STOP")) { myTimer.cancel(); goBtn.setLabel(" GO "); } else if (str.equals("show options")) { add(options, BorderLayout.WEST); optBtn.setLabel("hide options"); validate(); } else if (str.equals("hide options")) { remove(options); optBtn.setLabel("show options"); validate(); } } boolean dataOK() { y = 0; ok = true; nRings = Integer.parseInt(nRingsTxF.getText()); if (nRings < 8) { report("Minimum number of rings = 8"); nRingsTxF.setText("8"); } if (nRings > 1000) { report("Maximum number of rings = 1000"); nRingsTxF.setText("1000"); } press = Double.parseDouble(pressTxF.getText()); if (press < 0) { report("Minimum pressure = 0"); pressTxF.setText("0"); } if (press > 1000) { report("Maximum pressure = 500kPa."); pressTxF.setText("500"); } drop = Double.parseDouble(dropTxF.getText()); if (drop < 0.01) { report("Minimum drop height = 0.01 m" ); dropTxF.setText("0.01"); } if (drop > 100) { report("Maximum drop height = 100 m"); dropTxF.setText("100"); } mass = Double.parseDouble(massTxF.getText()); if (mass < 1) { report("Minimum mass = 1 g" ); massTxF.setText("1"); } if (mass > 5000) { report("Maximum mass = 5000 g"); massTxF.setText("5000"); } radius = Double.parseDouble(radiusTxF.getText()); if (radius <1) { report("Minimum radius = 1 cm" ); radiusTxF.setText("1"); } if (radius > 50) { report("Maximum radius = 50 cm"); dropTxF.setText("50"); } if (ok) { double dti = Math.sqrt(mass/press/radius)/nRings/6; dti = Double.parseDouble(dps(dti*10000,0)); if (dti<1) { report("Impossible combination of data!"); } dt = Double.parseDouble(dtTxF.getText()); if (dt < 1) { report("Minimum time step = 1 "+'\u00B5'+"s"); dtTxF.setText("1"); } if (dt > dti) { report("Maximum time step = " + dti); dtTxF.setText("" + dti); } kappa = Double.parseDouble(kappaTxF.getText()); if (kappa < 1) { report("Minimum elastic mod. = 1 kN/m"); kappaTxF.setText("1"); } if (kappa > 500) { report("Maximum elastic mod. = 500"); kappaTxF.setText("500"); } } if (ok) { double decay0 = dt*nRings*nRings/20000; decay0 = Double.parseDouble(dps(decay0,0)); decay = Double.parseDouble(decayTxF.getText()); if (decay < decay0) { report("Minimum decay time = " + decay0 + " ms"); decayTxF.setText("" + decay0); } if (decay > 1000) { report("Maximum decay time = 1000 ms"); decayTxF.setText("1000"); } } if (!ok) report("Review values and try again."); return ok; } void report(String str) { Graphics g = diagram.getGraphics(); g.setColor(Color.white); g.fillRect(0,y,400,50); g.setColor(Color.black); g.drawString(str,5,y+20); y +=25; ok = false; } String dps(double x, int d) { String s = "" + x; int i = s.indexOf("."); if (i < 0) return s; else return s.substring(0,i+d); } class MyCanvas extends Canvas { public MyCanvas() {;} public void paint(Graphics g) { Dimension d = getSize(); double scale = 2.5*d.height; int dia = (int) scale/5; int mid = d.width/2; int floor = d.height-6; int n = nRings*2; int x[] = new int[n]; int y[] = new int[n]; g.setColor(Color.white); g.fillRect(0,0,d.width,floor+1); g.setColor(Color.lightGray); g.fillRect(0,floor+1,d.width,5); g.setColor(Color.black); for (int i = 0; i