import java.awt.*;
import java.applet.*;
import java.lang.*;

public class SpringMass extends Applet
{
      Graphics      sG;

      Graphics      bG;
      Image         bI;

      Graphics      cG;
      Image         cI;

      Color         back         = new Color(247, 243, 234);
      Color         pback        = new Color(192, 255, 192);
      Color         plines       = new Color(0, 255, 0);
      Color         tback        = new Color(255, 192, 128);
      Color         tlines       = new Color(192, 96, 0);
      Color         positiveback = new Color(255, 128, 128);
      Color         negativeback = new Color(192, 192, 255);
      Color         positive     = new Color(255, 0, 0);
      Color         negative     = new Color(64, 64, 255);
      Color         black        = new Color(0, 0, 0);
      Color         grey         = new Color(128, 128, 128);
      Color         magenta      = new Color(255, 0, 0);

      int           bottom       = 60;
      int           width        = 481;
      int           height       = 261;

      double        ytop         = 1.0;
      double        ttop         = 18.8495;
      int           n            = 100;
      double        h            = ttop/(n * 200);
      double        newx, oldx, qx;
      double        startx       = 1.0;
      double        newv, oldv, qv;
      double        startv       = 0.0;

      double        friction     = 0.0;
      int           ifriction    = bottom + 100;      

      public void init()
      {
             bI = createImage(this.size().width, this.size().height);
             bG = bI.getGraphics();
             cI = createImage(this.size().width, this.size().height);
             cG = cI.getGraphics();
             drawback();
             cG.drawImage(bI, 0, 0, this);
             drawcart(startx, startv);
      }

      public void paint(Graphics g)
      {
             g.drawImage(cI, 0, 0, this);
             sG = getGraphics();
      }

      public void update(Graphics g)
      {
             g.drawImage(cI, 0, 0, this);
      }

      public int yscale(double y)
      {
             int z;
             z = (int) (bottom + java.lang.Math.round(100.0 * (1.0 - y)/ytop));
             return z;
      }

      public int tscale(double t)
      {
             int z;
             z = (int) java.lang.Math.round(200.0 * t / ttop);
             return z;
      }

      public int xscale(double x)
      {
             int z;
             z = (int) (320 + java.lang.Math.round(100.0 * x/ytop));
             return z;
      }

      public void drawcart(double x, double v)
      {
             double   dx;
             cG.setColor(tlines);
             cG.fillRect(xscale(x) - 20, 10, 41, 27);
             cG.setColor(black);
             cG.fillOval(xscale(x) - 15, 32, 9, 9);
             cG.fillOval(xscale(x) +  7, 32, 9, 9);
             cG.fillOval(xscale(x) - 2, yscale(v) - 2, 5, 5);
             cG.drawLine(xscale(x), 15, xscale(x), 36);
             cG.drawLine(xscale(x) - 4, 32, xscale(x) + 4, 32);
             cG.drawLine(xscale(x) - 3, 33, xscale(x) + 3, 33);            
             cG.drawLine(xscale(x) - 2, 34, xscale(x) + 2, 34);            
             cG.drawLine(xscale(x) - 1, 35, xscale(x) + 1, 35);
             dx = (((xscale(x) - 20) * ytop - 320 * ytop)/100 + 3.09)/62;
             cG.drawLine(xscale(-3.09), 25, xscale(-3.09 + dx), 15);
             cG.drawLine(xscale(x) - 20, 25, xscale(x - dx) - 20, 15);
             for (int i = 0; i < 30; i = i + 2)
             {
                 cG.drawLine(xscale(-3.09 * ytop + 2 * i * dx + dx), 15, 
                             xscale(-3.09 * ytop + 2 * i * dx + 3 * dx), 35);
                 cG.drawLine(xscale(-3.09 * ytop + 2 * i * dx + 3 * dx), 35,
                             xscale(-3.09 * ytop + 2 * i * dx + 5 * dx), 15);
             }            
      }

      public void drawback()
      {
             bG.setColor(back);
             bG.fillRect(0, 0, width, height);
             bG.setColor(tback);
             bG.fillRect(0, bottom, 201, 201);
             bG.setColor(tlines);
             for (int i = 0; i < 201; i = i + 20)
             {
                 bG.drawLine(0, yscale(ytop) + i, 200, yscale(ytop) + i);
                 bG.drawLine(i, yscale(-ytop), i, yscale(ytop));
             }
             bG.setColor(pback);
             bG.fillRect(220, bottom, 201, 201);
             bG.setColor(plines);
             for (int i = 0; i < 201; i = i + 20)
             {
                 bG.drawLine(220, yscale(ytop) + i, 420, yscale(ytop) + i);
                 bG.drawLine(220 + i, yscale(-ytop), 220 + i, yscale(ytop));
             }
             bG.setColor(negativeback);
             bG.fillRect(440, bottom, 41, 101);
             bG.setColor(positiveback);
             bG.fillRect(440, bottom + 100, 41, 101);
             bG.setColor(negative);
             if (ifriction == bottom + 100)
             {   bG.setColor(grey);        }
             if (ifriction > bottom + 100)
             {   bG.setColor(positive);    }
             bG.fillRect(455, ifriction, 11, height - ifriction);
             bG.setColor(black);
             bG.drawLine(460, bottom, 460, bottom + 200);
             for (int i = 0; i < 201; i = i + 10)
             {
                 bG.drawLine(450, bottom + i, 470, bottom + i);
             }
             bG.drawLine(440, bottom + 100, 480, bottom + 100);
             bG.setColor(grey);
             bG.fillRect(0, 0, 11, 41);
             bG.fillRect(0, 40, width, 11); 
      }

       public boolean mouseDown(Event evt, int mx, int my)
       {
             if ((my > bottom - 1) && (mx > 440))
             {
                 friction = (bottom +100 - my)/500.0;
                 ifriction = my;
                 drawback();
                 cG.drawImage(bI, 0, 0, this);
                 drawback();
                 sG.drawImage(cI, 0, 0, this);
                 return true;
             }
             if (mx > 219)
             {
                 startx = ytop * (mx - 320)/100;
                 startv = 0;
                 if (my > bottom)
                 {
                     startv = -ytop * (my - bottom - 100)/100;
                 } 
                 drawback();
                 cG.drawImage(bI, 0, 0, this);
                 drawcart(startx, startv);
                 sG.drawImage(cI, 0, 0, this);
                 return true; 
             }
             if ((my > bottom) && (mx < 201))
             {
                 simulate();
             }
             return true;
       }

       public void simulate()
       {
             double t = 0;
             oldx = startx;
             oldv = startv;
             drawback();
             cG.drawImage(bI, 0, 0, this);
             drawcart(startx, startv);
             sG.drawImage(cI, 0, 0, this);
             for (int i = 0; i < 201; i = i + 1)
             {
                 bG.setColor(black);
                 qx = oldx;
                 qv = oldv;
                 for (int j = 0; j < n; j = j + 1)
                 {
                     newx = qx + h * qv;
                     newv = qv - h * (qx + friction * qv);
                     qx = newx;
                     qv = newv;
                 }
                 bG.drawLine(xscale(oldx), yscale(oldv),
                             xscale(newx), yscale(newv));
                 bG.drawLine(tscale(t), yscale(oldx),
                             tscale(t + n * h), yscale(newx));
                 bG.setColor(magenta);
                 bG.drawLine(tscale(t), yscale(oldv),
                             tscale(t + n * h), yscale(newv));
                 oldx = newx;
                 oldv = newv;
                 t = t + n * h;
                 cG.drawImage(bI, 0, 0, this);
                 drawcart(newx, newv);
                 sG.drawImage(cI, 0, 0, this);
             }

       }


}



Copyright c 1997 by Frank Wattenberg, Department of Mathematics, Montana State University, Bozeman, MT 59717