Site hosted by Angelfire.com: Build your free website today!
/*
Java Applet precess2.java
March 1997 - Michael J. Hurben

This applet demonstrates the damped precessional
motion of a magnetic moment in the presence of an
external magnetic field.  The user can click and
drag the tip of the magnetization vector to an initial
position, and then release it to begin the motion.
The external field strength and the damping 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 precess2 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 tipLength=16;          // Settings for the arrow tip
   int tipWidth=10;           // size. 

   int time=0;                // 
   int Hfield=20;             // Arbitrary measure of field H.      
   int mx=100;                // Initial x-position of M vector.
   int my=50;                 // Initial y-position of M vector.
   int tip1x=100;             //
   int tip1y=50;              // Used to draw arrow head.
   int tip2x=100;             //
   int tip2y=50;              
   int set=0;

   double freq=(2.0*3.1415/2000.);  // Period = 2000 'thread cycles.'
   double damp=0.0001;              // Damping constant [1/sec].

   double sinPhi=0;          // Phi is the angle between the M and H
   double cosPhi=1;          // vectors.

   Thread t;                   
   Button b1, b2, b3, b4, b5, b6, b7;

   int[] hArrowXpoints =                       //
     {100, 100+tipWidth/2, 100-tipWidth/2};    //  Arrays which set 
   int[] hArrowYpoints = {50-Hfield,           //  the initial points
     50-Hfield+tipLength,                      //  used by the Polygon()
     50-Hfield+tipLength};                     //  method to draw the
   int[] mArrowXpoints =                       //  tips on the vectors.
     {100, 100+tipWidth/2, 100-tipWidth/2};    //
   int[] mArrowYpoints = {50,                  //
     50+tipLength,                              
     50+tipLength};                            
                                           //
   public void init()                      //  Initialize :
   {                                       //  Set up the user interface
      setLayout(new BorderLayout(10,10));  //  and statrt the thread.
      Panel p1 = new Panel();              //
      p1.setLayout(new GridLayout(7,1));
      b1 = new Button("Increase H");      
      b2 = new Button("Decrease H");     
      b3 = new Button("More Damping");
      b4 = new Button("Less Damping");
      b5 = new Button("Pause");
      b6 = new Button("Resume");
      b7 = new Button("Finish");
      p1.add(b1);
      p1.add(b2);
      p1.add(b3);
      p1.add(b4);
      p1.add(b5);
      p1.add(b6);
      p1.add(b7);
      add("East", p1);
      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(mDx<200)

      {
      time=0;                           //  The mouseDrag event is
      set=0;                            //  used only to reposition the
      sinPhi=(mDx-100)/Math.sqrt        //  M vector.
        ((mDx-100)*(mDx-100)
        +(150-mDy)*(150-mDy));
      cosPhi=(150-mDy)/Math.sqrt

        ((mDx-100)*(mDx-100)
        +(150-mDy)*(150-mDy));         
      repaint();
      }
      return true;
   }

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

   public boolean action(Event e, Object o)
   {
      if (o.equals("Increase H"))         //  Respond to button pushes.
      {
         freq = freq*1.1;

         Hfield = Hfield+2;

      }
      else if (o.equals("Decrease H"))
      {
         freq = freq*0.9;

         Hfield = Hfield-2;

      }
      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("Finish"))
      {
         t.stop();
      }
      hArrowYpoints[0] = 50-Hfield;              //
      hArrowYpoints[1] = 50-Hfield+tipLength;    // Change length of H.
      hArrowYpoints[2] = 50-Hfield+tipLength;    //
      return true;
   }

      public void run()      // Run an infinite loop where the M vector
      {                      // position is calculated as a function of
         while(true)         // time.
         {
            int a = (int) (100*sinPhi*(Math.exp(time*damp*(-1)))*
              (Math.cos(time*freq)));
            int b = (int) (50*sinPhi*(Math.exp(time*damp*(-1)))*
              (Math.sin(time*freq)));
            mx= 100+a;

            my= (int) (150-100*Math.sqrt(1-(sinPhi)*(sinPhi)*
              Math.exp((-2)*time*damp))-b);

            //  Now calculate the vertices for the triangular vector tip

            tip1x=mx+(int)(((100-mx)*tipLength+(tipWidth/2)*(my-150))/

              Math.sqrt((my-150)*(my-150)+(mx-100)*(mx-100)));
            tip2x=mx+(int)(((100-mx)*tipLength-(tipWidth/2)*(my-150))/

              Math.sqrt((my-150)*(my-150)+(mx-100)*(mx-100)));
            tip1y=my+(int)(((150-my)*tipLength-(tipWidth/2)*(mx-100))/

              Math.sqrt((my-150)*(my-150)+(mx-100)*(mx-100)));
            tip2y=my+(int)(((150-my)*tipLength+(tipWidth/2)*(mx-100))/

              Math.sqrt((my-150)*(my-150)+(mx-100)*(mx-100)));
             mArrowXpoints[0] = mx;

             mArrowXpoints[1] = tip1x;

             mArrowXpoints[2] = tip2x;

             mArrowYpoints[0] = my;

             mArrowYpoints[1] = tip1y;

             mArrowYpoints[2] = tip2y;


             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 Magnetic Field Vector

       offGraphics.setColor(Color.blue);
       offGraphics.drawLine(100, 150, 100, (50-Hfield));
       offGraphics.fillPolygon(hArrowXpoints, hArrowYpoints, 3);

       // Draw the Magnetization vector

       offGraphics.setColor(Color.red);
       offGraphics.drawLine(100, 150, mx, my);
       offGraphics.fillPolygon(mArrowXpoints, mArrowYpoints, 3);

       // Make sure the M vector actually goes in front & behind!

       if( mx > 90-tipWidth/2  && mx < 110+tipWidth/2

         && my  < (int) (150-100*Math.sqrt(1-(sinPhi)*(sinPhi)*
         Math.exp((-2)*time*damp))))
          {
          offGraphics.setColor(Color.blue);
          offGraphics.drawLine(100, 150, 100, (50-Hfield));
          offGraphics.fillPolygon(hArrowXpoints, hArrowYpoints, 3);
          }        
        g.drawImage(offImage, 0, 0, this);
    }

}