/* version 2 - 07/03/09
 * JPQ
 * modifié le 18/12/17 ajout de main()
 * modification 03/02/21
 */

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

public class respend extends JPanel implements Runnable {
  static final long serialVersionUID = 210203L;
  commandes cmd;
  dessin d;
  Thread trace;

  TextField tfdt, tfk, tm, tamortl, tamorta, ttempo;
  int XMAX, YMAX, X0, Y0, ECH, XC, YC, XCp, YCp;
  double g, k, dt, ksm, lr, l0, m, l, lp, ls, limit, amortl, amorta, a, ap, as, sina, cosa;
  int [] XR, YR, XRp, YRp;
  int tempo;

  public void init ()
  { XR = new int [11];
  	YR = new int [11];
  	XRp = new int [11];
  	YRp = new int [11];
  	Font f = new Font ("Arial", Font.PLAIN, 10);
  	setFont (f);
    setLayout (new BorderLayout ());
    cmd = new commandes ();
    d = new dessin (cmd);
    add (cmd, BorderLayout.NORTH);
    add (d, BorderLayout.CENTER);
    trace = new Thread (this);
    trace.start ();
  }

  private void ressort (double l, double a) {
	double cosa = Math.cos (a); double sina = Math.sin (a);
    double L = l * ECH;
    XR [0] = X0;
    YR [0] = Y0;
    XR [1] = X0 + (int)(sina * 10.0);
    YR [1] = Y0 + (int)(cosa * 10.0);
    XR [2] = X0 + (int)((-cosa + sina) * 10.0);
    YR [2] = Y0 + (int)((sina + cosa) * 10.0);
    XR [3] = X0 + (int)((cosa + sina) * 10.0);
    YR [3] = Y0 + (int)((-sina + cosa) * 10.0);
    XR [4] = X0 + (int)(cosa * 10.0 + sina * (10.0 + L));
    YR [4] = Y0 + (int)(-sina * 10.0 + cosa * (10.0 + L));
    XR [5] = X0 + (int)(sina * (10.0 + L));
    YR [5] = Y0 + (int)(cosa * (10.0 + L));
    XR [6] = X0 + (int)(sina * (20.0 + L));
    YR [6] = Y0 + (int)(cosa * (20.0 + L));
    XR [7] = X0 + (int)(sina * (10.0 + L));
    YR [7] = Y0 + (int)(cosa * (10.0 + L));
    XR [8] = X0 + (int)(- cosa * 10.0 + sina * (10.0 + L));
    YR [8] = Y0 + (int)(sina * 10.0 + cosa * (10.0 + L));
    XR [9] = X0 + (int)((-cosa + sina) * 10.0);
    YR [9] = Y0 + (int)((sina + cosa) * 10.0);
    XR [10] = X0 + (int)(sina * 10.0);
    YR [10] = Y0 + (int)(cosa * 10.0);

    XC = X0 + (int)(sina * (40.0 + L));
    YC = Y0 + (int)(cosa * (40.0 + L));
}

  public void run() {
	while (true) {
	  d.repaint ();
      if (! d.deplace) {
		if (l < limit) {
		  l = limit;
      	  lp = 0.0;
      	}
        ls = g * Math.cos (a) + ksm * (l0-l) + l * ap * ap - amortl * lp;
        as = -(g * Math.sin (a) + 2 * lp * ap) / l - amorta * ap;
        lp = lp + ls * dt; l = l + lp * dt;
        ap = ap + as * dt; a = a + ap * dt;
      }
      try {
	    Thread.sleep (tempo);
	  }
      catch (InterruptedException e) {}
    }
  }
////////////////////////////////////////////////////////////////////////////////
protected class commandes extends Panel implements ActionListener {
	static final long serialVersionUID = 210203L;
	Button ok;

  public commandes ()
  { setBackground (Color.lightGray);
  	add (new Label ("k ="));
    tfk = new TextField ("20.0", 5);
    add (tfk);
    k = Math.abs (sd (tfk.getText(), k));
    add (new Label ("dt ="));
    tfdt = new TextField ("0.015", 5);
    add (tfdt);
    dt = Math.abs (sd (tfdt.getText(), dt));
    add (new Label ("m ="));
    tm = new TextField ("1.0", 5);
    add (tm);
    m = Math.abs (sd (tm.getText(), m));
    add (new Label ("amort. (l) ="));
    tamortl = new TextField ("0.2", 5);
    add (tamortl);
    amortl = Math.abs (sd (tamortl.getText(), amortl));
    add (new Label ("amort. (a) ="));
    tamorta = new TextField ("0.2", 5);
    add (tamorta);
	amorta = Math.abs (sd (tamorta.getText(), amorta));
	add (new Label ("tempo ="));
	ttempo = new TextField ("10", 5);
	add (ttempo);
    ok = new Button ("Ok");
    ok.addActionListener (this);
    add (ok);
    tempo = 10;
    g = 9.81; ksm = k / m;
    l0 = 1.0; limit = 0.1; l = l0 + g / ksm; lp = 0.0;
    a = ap = 0.0;
  }

  private double sd (String s, double d) {
	try {
	  d = Double.parseDouble (s);
	}
    catch (NumberFormatException nfe) {}
    return d;
  }

  private int si (String s, int i) {
	try {
	  i = Integer.parseInt (s);
	}
    catch (NumberFormatException nfe) {}
    return i;
  }


  public void actionPerformed (ActionEvent e) {
	if (e.getSource() == ok) {
	  k = Math.abs (sd (tfk.getText(), k));
      dt = Math.abs (sd (tfdt.getText(), dt));
      m = Math.abs (sd (tm.getText(), m));
      amortl = Math.abs (sd (tamortl.getText(), amortl));
      amorta = Math.abs (sd (tamorta.getText(), amorta));
      tempo = Math.abs (si (ttempo.getText(), tempo));
      ksm = k / m;
      tfk.setText (Double.toString (k));
      tfdt.setText (Double.toString (dt));
      tm.setText (Double.toString (m));
      tamortl.setText (Double.toString (amortl));
      tamorta.setText (Double.toString (amorta));
      ttempo.setText (Integer.toString (tempo));
    }
  }
}
////////////////////////////////////////////////////////////////////////////////
protected class dessin extends Canvas implements MouseListener, MouseMotionListener {
	static final long serialVersionUID = 210203L;
  commandes cmd;
  Image img;
  Graphics g;
  boolean deplace;

  public dessin (commandes cmd)
  { this.cmd = cmd;
    addMouseMotionListener (this);
    addMouseListener (this);
  }

  public void update (Graphics g1) {
    paint (g1);
  }

  public void paint (Graphics g1)
  { if (img == null || YMAX != getSize().height || XMAX != getSize().width)
    { img = createImage (getSize().width, getSize().height);
      g = img.getGraphics ();
      YMAX = getSize().height;
      XMAX = getSize().width;
      X0 = XMAX / 2;
      Y0 = 80;
      ECH = 100;
      g.setColor (Color.white);
      g.fillRect (0,0,XMAX, YMAX);
    }
    else
    { g.setColor (Color.white);
    	g.drawPolygon (XRp, YRp, 11);
    	g.drawOval (XCp - 20, YCp - 20, 40, 40);
    }
    sina = Math.sin (a); cosa = Math.cos (a);
    if (a > Math.PI) a = a - 2.0 * Math.PI;
    if (a < - Math.PI) a = a + 2.0 * Math.PI;
    ressort (l, a);
    g.setColor (Color.blue);
    g.fillRect (X0 - 2, Y0 - 2, 5, 5);
    g.drawOval (XC - 20, YC - 20, 40, 40);
    g.setColor (Color.green);
    g.drawPolygon (XR, YR, 11);
    g.setColor (Color.black);
    g.drawLine (XC, YC, XC, YC);
    XRp = XR;
    YRp = YR;
    XCp = XC;
    YCp = YC;

    g1.drawImage (img, 0, 0, this);
  }

  public void mousePressed (MouseEvent e) {
  	int X = e.getX ();
  	int Y = e.getY ();
    int L = (int)(l * ECH);
    deplace = (X >=  X0 - 30) && (X <= X0 + 30) && (Y >= Y0 + L) && (Y <= Y0 + L + 50);
  }

  public void mouseDragged (MouseEvent e) {
    if (deplace)
    { int X = e.getX ();
  	  int Y = e.getY ();
      if (Y != Y0)
      { a = X - X0; a = a / (Y - Y0); a = Math.atan (a);
      }
      else
      { a = Math.PI / 2; if (X < X0) a = - a;
      }
      if (Y < Y0) a = a + Math.PI;
      ap = 0.0;
      l = (double) (Y - Y0 - 40) / ECH; lp = 0.0;
      if (l < limit) l = limit;
    }
  }

  public void mouseReleased (MouseEvent e) {
  	deplace = false;
  }

  public void mouseMoved (MouseEvent e) {}
  public void mouseClicked (MouseEvent e) {}
  public void mouseEntered (MouseEvent e) {}
  public void mouseExited (MouseEvent e) {}

}

////////////////////////////////////////////////////////////////////////////////

  public static void main (String [] args) {
	int w = 800;
	int h = 400;

	respend r = new respend();
	r.init();

	JFrame f = new JFrame ("Mouvement du ressort pendulaire");
	f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
	f.add (r);
	f.setSize (w, h);
	f.setVisible (true);
  }

}
