/*
Java Applet masspring1.java
April 1997 - Michael J. Hurben

This applet demonstrates the damped simple harmonic
motion of a mass on a spring with friction. The user can
click and drag the mass to an initial position, and then
release it to begin the motion. Various parameters can be
adjusted at any time.

The applet uses double buffering in an attempt to
eliminate (or reduce) the flicker in the animation.  
*/

import java.applet.Applet;
import java.awt.*;

public class masspring1 extends Applet implements Runnable
{
   Dimension offDimension,d;  // Variables used to create an 'offscreen'
   Image offImage;            // image via the update() method, to help 
   Graphics offGraphics;      // reduce flicker.
   int time=0;                 
   double mass=100000;         
   double k=1;                
   int set=0;
   int space;
   int x=200;
   int inx=200;
   int mx=200;
   double freq = Math.sqrt(k/mass);   // Standard formula for frequency
   double damp=0.0001;                // Damping constant [1/sec].

   Color ltblue = new Color(0, 150, 255);  // Define ltblue color
   Thread t;                   
   Button b1, b2, b3, b4, b5, b6, b7, b8, b9;
                                           
   public void init()                     //  Initialize :
   {                                      //  Set up the user interface
      setLayout(new BorderLayout(10,10));
      Panel p1 = new Panel();
      Panel p2 = new Panel();
      p1.setLayout(new GridLayout(2,4));
      p2.setLayout(new FlowLayout());
      b1 = new Button("Increase mass");   
      b2 = new Button("Decrease mass");    
      b3 = new Button("Increase k");         
      b4 = new Button("Decrease k");       
      b5 = new Button("More Damping");
      b6 = new Button("Less Damping");
      b7 = new Button("Pause");
      b8 = new Button("Resume");
      b9 = new Button("Finished");
      p1.add(b1);
      p1.add(b2);
      p1.add(b3);
      p1.add(b4);
      p1.add(b5);
      p1.add(b6);
      p1.add(b7);
      p1.add(b8);
      p2.add(b9);
      add("North", p1);
      add("South", p2);
      t=new Thread(this);
      t.start();      
   }
                                         //
   public void paint(Graphics g)         //  The guts of the painting
   {                                     //  is done in the update()
      d=size();                          //  method below.
      update(g);                         //
   }

   public boolean mouseDrag(Event e, int mDx, int mDy)
   {
      if(mDy > 100 && mDy <150)
      {
         time=0;
         set=0;
         if (mDx > 300)
         {
         x=300;
         }
         else if (mDx < 100)
         {
         x=100;
         }
         else
         {
         x=mDx;                        
         }
         mx=x;
         inx=x;
         repaint();
         return true;
      }
      else
      {
         return false;
      }
   }

   public boolean mouseUp(Event e, int mDx, int mDy)
   {
      set=1;                           //  This insures that the mass
      return true;                     //  is not released into motion
   }                                   //  until the mouse button is up.

   public boolean action(Event e, Object o)
   {
      if (o.equals("Increase mass"))   //  Respond to button pushes.
      {
         mass = mass*1.1;
      }
      else if (o.equals("Decrease mass"))
      {
         mass = mass*0.9;
      }
      else if (o.equals("Increase k"))
      {
         k = k*1.1;
      }
      else if (o.equals("Decrease k"))
      {
         k = k*0.9;
      }
      else if (o.equals("More Damping"))
      {
         damp = damp*1.1;
      }
      else if (o.equals("Less Damping"))
      {
         damp = damp*0.9;
      }
      else if (o.equals("Pause"))
      {
         t.suspend();
      }
      else if (o.equals("Resume"))
      {
         t.resume();
      }
      else if (o.equals("Finished"))
      {
         t.stop();
      }
      return true;
      }

      public void run()      // Run an infinite loop where the M vector
      {                      // position is calculated as a function of
         while(true)         // time.
         {
            double freq = Math.sqrt(k/mass); 
            int a = (int) ((inx-200)*(Math.exp(time*damp*(-1)))*
              (Math.cos(time*freq)));
            mx= 200+a;
             if (set!=0)         //
             {                   //  This insures that motion does not
                repaint();       //  begin until mouse button is released.
                time=time+1;     //
             }
         }
    }

    public void update(Graphics g)
    {                                         //
       if((offGraphics ==null)                // Setup an off-screen image
        ||(d.width !=offDimension.width)      // via the update() method.
        || (d.height != offDimension.height)) //
       {
       offDimension=d;
       offImage=createImage(d.width, d.height);
       offGraphics=offImage.getGraphics();
       }
       offGraphics.setColor(getBackground());
       offGraphics.fillRect(0,0, d.width, d.height);
       
       // Draw the wall and floor

       offGraphics.setColor(Color.black);
       offGraphics.drawLine(50, 150, 50, 100);
       offGraphics.drawLine(50, 150, 350, 150);
       offGraphics.drawLine(50, 150, 40, 140);
       offGraphics.drawLine(40, 140, 40, 90);
       offGraphics.drawLine(40, 90, 50, 100);
       offGraphics.drawLine(50, 140, 340, 140);
       offGraphics.drawLine(350, 150, 340, 140);

       // "Erase" the black lines in background as necessary

       offGraphics.setColor(getBackground());
       offGraphics.drawLine(mx-10, 140, mx+50, 140);

       if (mx > 289)
       {
       offGraphics.drawLine(340, 140, mx+50, mx-150); 
       }

       // Draw the mass

       offGraphics.setColor(Color.red);
       offGraphics.drawRect(mx, 100, 50, 50);
       offGraphics.drawLine(mx, 150, mx-10, 140);
       offGraphics.drawLine(mx-10, 140, mx-10, 90);
       offGraphics.drawLine(mx-10, 90, mx, 100);
       offGraphics.drawLine(mx-10, 90, mx+40, 90);
       offGraphics.drawLine(mx+40, 90, mx+50, 100);

       // Draw the spring

       space=(int) ((mx-75)/11);

       // Light blue parts:

       offGraphics.setColor(ltblue);

       offGraphics.drawLine((60+space), 130, (60+2*space), 110);
       offGraphics.drawLine((59+space), 130, (59+2*space), 110);
       offGraphics.drawLine((61+space), 130, (61+2*space), 110);

       offGraphics.drawLine((60+3*space), 130, (60+4*space), 110);
       offGraphics.drawLine((59+3*space), 130, (59+4*space), 110);
       offGraphics.drawLine((61+3*space), 130, (61+4*space), 110);

       offGraphics.drawLine((60+5*space), 130, (60+6*space), 110);
       offGraphics.drawLine((61+5*space), 130, (61+6*space), 110);
       offGraphics.drawLine((59+5*space), 130, (59+6*space), 110);

       offGraphics.drawLine((60+7*space), 130, (60+8*space), 110);
       offGraphics.drawLine((61+7*space), 130, (61+8*space), 110);
       offGraphics.drawLine((59+7*space), 130, (59+8*space), 110);

       offGraphics.drawLine((60+9*space), 130, (60+10*space), 110);
       offGraphics.drawLine((61+9*space), 130, (61+10*space), 110);
       offGraphics.drawLine((59+9*space), 130, (59+10*space), 110);

       // Dark blue parts:

       offGraphics.setColor(Color.blue);

       offGraphics.drawLine(50, 120, 60, 120);
       offGraphics.drawLine(50, 121, 60, 121);
       offGraphics.drawLine(50, 119, 60, 119);

       offGraphics.drawLine((60+11*space), 120, mx-5, 120);
       offGraphics.drawLine((60+11*space), 121, mx-5, 121);
       offGraphics.drawLine((60+11*space), 119, mx-5, 119);

       offGraphics.drawLine(60, 120, (60+space), 130);
       offGraphics.drawLine(60, 121, (59+space), 130);
       offGraphics.drawLine(60, 119, (61+space), 130);

       offGraphics.drawLine((60+2*space), 110, (60+3*space), 130);
       offGraphics.drawLine((59+2*space), 110, (59+3*space), 130);
       offGraphics.drawLine((61+2*space), 110, (61+3*space), 130);

       offGraphics.drawLine((60+4*space), 110, (60+5*space), 130);
       offGraphics.drawLine((59+4*space), 110, (59+5*space), 130);
       offGraphics.drawLine((61+4*space), 110, (61+5*space), 130);

       offGraphics.drawLine((60+6*space), 110, (60+7*space), 130);
       offGraphics.drawLine((59+6*space), 110, (59+7*space), 130);
       offGraphics.drawLine((61+6*space), 110, (61+7*space), 130);

       offGraphics.drawLine((60+8*space), 110, (60+9*space), 130);
       offGraphics.drawLine((59+8*space), 110, (59+9*space), 130);
       offGraphics.drawLine((61+8*space), 110, (61+9*space), 130);

       offGraphics.drawLine((60+10*space), 110, (60+11*space), 120);
       offGraphics.drawLine((61+10*space), 110, (60+11*space), 119);
       offGraphics.drawLine((59+10*space), 110, (60+11*space), 121);

       g.drawImage(offImage, 0, 0, this);
    }
}