/* Virtual Physics Lab: Pendulum */ import java.awt.*; import java.applet.*; public class pendulum extends Applet implements Runnable{ public MediaTracker tracker; public Image offScreenImage; public Image theBox; public boolean copyRight = false; Thread moveThread; private static final int MOVEPAUSE = 50; public boolean stopWatch = false, myGo = false, myPause = false; public long t0, t1, tpause; public String timeout = "0", timeout1 = "", timeout2 = "", timeout3 = ""; public Color colorBack = new Color(0, 80, 0); public Color colorBob1 = new Color(120, 0, 0); public Color colorBob2 = new Color(150,0, 0); public Color colorBob3 = new Color(180,0, 0); public int dt = 0, minutes=0, hours=0; public double time=0.0; public int ix0 = 275, iy0 = 97, ix, iy, iPendL; public double pendL, x=0, y, A, omega; public boolean dragBob = false; public void start() { if(myGo) { if(moveThread == null){ moveThread = new Thread(this); moveThread.start(); } } } public void stop() { if(moveThread != null){ moveThread.stop(); try { moveThread.join(); } catch (InterruptedException e) { } } moveThread=null; } public void run() { while (true){ try { moveThread.sleep(MOVEPAUSE); }catch(InterruptedException e) { } repaint(); } } public void init() { super.init(); // load the backgrond image tracker= new MediaTracker(this); theBox = this.getImage(getCodeBase(),"bg.jpg"); tracker.addImage(theBox,0); try { tracker.waitForID(0); } catch (InterruptedException e) { } offScreenImage = createImage(500,350); pendL = 0.5+0.5*Math.random(); y = pendL; iPendL = (int)(200*pendL); //{{INIT_CONTROLS setLayout(null); resize(500,350); //}} } public void update(Graphics g){ Graphics offg = offScreenImage.getGraphics(); paint(offg); g.drawImage(offScreenImage, 0, 0, this); } public void paint(Graphics g){ g.setColor(Color.gray); g.fillRect(0,0,500,350); g.drawImage(theBox,91,0,theBox.getWidth(this),theBox.getHeight(this),this); g.setColor(colorBack); g.fillRect(0,220,140,130); g.setColor(Color.white); g.drawRect(3,223,134,124); g.setColor(Color.black); g.fillRect(6,226,128,40); if (stopWatch) { dt = (int)(System.currentTimeMillis() - t1); time = dt/1000.; if (time >= 60) { time = time - 60.0; t1 = t1 + 60000; minutes++; } if (minutes == 60) { minutes = 0; hours++; } if (hours < 1) { if (minutes < 1) { timeout = ""+time; } else { if (time < 10) { timeout = ""+minutes+":0"+time; } else { timeout = ""+minutes+":"+time; } } } else { String outmin = ""+minutes; if (minutes < 10) outmin = "0"+minutes; String outsec = ""+time; if (time < 10) outsec = "0"+time; timeout = ""+hours+":"+outmin+":"+outsec; } } g.setColor(Color.red); g.setFont(new Font("Courier", Font.BOLD, 24)); g.drawString(timeout,15,257); g.setFont(new Font("Courier", Font.BOLD, 18)); if (!timeout1.equals("")) { // lap time 1 display g.setColor(Color.white); g.drawString("1>",15,290); g.setColor(Color.red); g.drawString(timeout1,45,290); } if (!timeout2.equals("")) { // lap time 2 display g.setColor(Color.white); g.drawString("2>",15,310); g.setColor(Color.red); g.drawString(timeout2,45,310); } if (!timeout3.equals("")) { // lap time 3 display g.setColor(Color.white); g.drawString("3>",15,330); g.setColor(Color.red); g.drawString(timeout3,45,330); } // pendulum // T = 2 pi (L/g)^(1/2) // omega = (g/L)^(1/2) / (1 + k^2/4 + 9k^4/64 + ...) with k=sin(theta0/2) // theta(t) = A cos(omega t) if (dragBob) { g.setColor(Color.blue); g.drawLine(ix0,iy0,ix0,iy0+100); double angle = 90.0 - 180.0*Math.atan2(y,x)/Math.PI; A = angle*Math.PI/180.; // initial angular amplitude //g.drawString("sA = "+sA,10,30); //g.drawString("theFactor = "+theFactor,10,50); //g.drawString("omega ="+omega,10,70); if (angle > 0) { g.drawString(outString(""+angle,4),ix0+2,iy0+30); } else { g.drawString(outString(""+angle,5),ix0+2,iy0+30); } } else { int it = (int)(System.currentTimeMillis() - t0); double t = it/1000.; A = A*0.9998; // damping of amplitude double sA = Math.sin(A/2.); // calculate large amplitude corrections double theFactor = 1.0 + sA*sA/4.0 + 9.0*sA*sA*sA*sA/64.0; omega = Math.sqrt(9.81/pendL) / theFactor; // omega with large amplitude corrections double thetanow = A * Math.cos(omega*t); x = pendL*Math.sin(thetanow); y = pendL*Math.cos(thetanow); } ix = (int)(200*x); iy = (int)(200*y); g.setColor(Color.black); g.drawLine(ix0,iy0,ix0+ix,iy0+iy); g.setColor(colorBob1); g.fillOval(ix0+ix-8,iy0+iy-8,17,17); g.setColor(colorBob2); g.fillOval(ix0+ix-7,iy0+iy-7,13,13); g.setColor(colorBob3); g.fillOval(ix0+ix-6,iy0+iy-6, 9, 9); g.setColor(Color.white); g.fillOval(ix0+ix-4,iy0+iy-4, 2, 2); // copyright notice: if (copyRight) { g.setColor(Color.green); g.fillRect(100,100,240,70); g.setColor(Color.white); g.setFont(new Font("Helvetica", Font.PLAIN, 18)); g.drawString("This applet was written by:",110,120); g.drawString("Wolfgang Bauer",110,140); g.drawString("Copyright: WB 1999",110,160); } } public boolean handleEvent(Event event) { if (event.id == Event.KEY_PRESS){ String thePressedKey = ""+(char)event.key; if (thePressedKey.equalsIgnoreCase("w")) { copyRight = !copyRight; repaint(); } if (thePressedKey.equalsIgnoreCase("s")) { stopWatch = !stopWatch; if (stopWatch) { t1 = System.currentTimeMillis(); minutes = 0; hours = 0; timeout = "0"; timeout1 = ""; timeout2 = ""; timeout3 = ""; myGo = true; myPause = false; start(); } else { myGo= false; myPause = false; stop(); } repaint(); } if (thePressedKey.equalsIgnoreCase("p")) { myPause = !myPause; if (!myPause) { t1 = t1 + System.currentTimeMillis() - tpause; stopWatch = true; myGo = true; start(); } else { tpause = System.currentTimeMillis(); stopWatch = false; myGo= false; stop(); } repaint(); } if (thePressedKey.equalsIgnoreCase("c")) { minutes = 0; hours = 0; timeout = "0"; timeout1 = ""; timeout2 = ""; timeout3 = ""; myPause = false; myGo = false; stopWatch = false; stop(); repaint(); } if (thePressedKey.equals("1")) { timeout1 = timeout; repaint(); } if (thePressedKey.equals("2")) { timeout2 = timeout; repaint(); } if (thePressedKey.equals("3")) { timeout3 = timeout; repaint(); } } if (event.target == this && event.id == Event.MOUSE_DOWN) { pendulum_MouseDown(event); return true; } if (event.target == this && event.id == Event.MOUSE_DRAG) { pendulum_MouseDrag(event); return true; } if (event.target == this && event.id == Event.MOUSE_UP) { pendulum_MouseUp(event); return true; } return super.handleEvent(event); } //{{DECLARE_CONTROLS //}} public String outString(String inString, int l){ // returns the first l chars of string int ls = (int)Math.min(inString.length(),l); return inString.substring(0,ls); } void pendulum_MouseDown(Event event) { int xx = event.x; int yy = event.y; if (Math.abs(xx-ix-ix0)<10 && Math.abs(yy-iy-iy0)<10) { dragBob = true; repaint(); } } void pendulum_MouseDrag(Event event) { int xx = event.x; int yy = event.y; if (dragBob) { ix = Math.min(iPendL,Math.max((xx-ix0),-iPendL)); iy = (int)(Math.sqrt(-1.0*ix*ix + 1.0*iPendL*iPendL)); x = ix/200.; y = iy/200.; repaint(); } } void pendulum_MouseUp(Event event) { dragBob = false; t1 = System.currentTimeMillis(); t0 = t1; myGo = true; stopWatch = true; start(); repaint(); } }