/* 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); } }