/* pendule.java 27/06/97 Jean-Paul Quelen
 * double buffering-jdl 1.2-29/09/99
 * nouvelle version le 20/02/09
 * modifié le 18/12/17 pour un fonctionnement autonome
 * modification 03/02/21
 */
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

public class pendule extends JPanel implements Runnable {
  static final long serialVersionUID = 210203L;
  commandes cmd;
  dessin d;
  courbe c;
  Thread trace;
  int w, h;

  public pendule (int w, int h) {
	this.w = w;
	this.h = h;
	Font f = new Font ("Arial", Font.PLAIN, 10);
  	setFont (f);
    setLayout (new BorderLayout());
    cmd = new commandes ();
    d = new dessin (cmd);
	if (w == 0 || h == 0) {
		w = getSize().width;
		h = getSize().height;
	}
    c = new courbe (cmd, w, h);
    add (cmd, BorderLayout.NORTH);
    add (d, BorderLayout.CENTER);
    add (c, BorderLayout.SOUTH);
    trace = new Thread (this);
    trace.start();
  }

  public void run(){
    while (true) {
	  d.repaint();
      c.repaint();
      if (! d.deplace) {
		cmd.as = - cmd.gsl * Math.sin (cmd.a) - cmd.amortsl * cmd.ap;
        cmd.ap = cmd.ap + cmd.as * cmd.dt;
        cmd.a = cmd.a + cmd.ap * cmd.dt;
      }
      try {
	    Thread.sleep (cmd.tempo);
	  }
      catch (InterruptedException e) {}
    }
  }
////////////////////////////////////////////////////////////////////////////////
protected class commandes extends Panel implements ActionListener {
	static final long serialVersionUID = 210203L;
  double amort, as, ap, a, gsl, dt, amortsl, l;
  int tempo;
  TextField tfdt, tl, tfamort, ttempo;
  Button ok;

  private void ajoutlbl (String s)
  { Label lbl = new Label (s);
    lbl.setBackground (Color.lightGray);
    add (lbl);
  } 

  private TextField ajouttf (String s)
  { TextField tf = new TextField (s, 5);
    add (tf);
    return tf;
  }

  public commandes ()
  { setBackground (Color.lightGray);
    ajoutlbl ("amort. =");
    tfamort = ajouttf ("0.2");
    amort = 0.2;
    ajoutlbl ("l = ");
    tl = ajouttf ("1.0");
    l = 1.0;
    ajoutlbl ("dt = ");
    tfdt = ajouttf ("0.014");
    dt = 0.014;
    ajoutlbl ("tempo = ");
    ttempo = ajouttf ("10");
    ok = new Button ("Ok");
    ok.addActionListener (this);
    add (ok);
    tempo = 10;
    gsl = 9.81 / l;
//    a = ap = 0.0;
    amortsl = amort / l;
  }

  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)
    { l = Math.abs (sd (tl.getText (), l));
      tl.setText (Double.toString (l));
      amort = Math.abs (sd (tfamort.getText (), amort));
      tfamort.setText (Double.toString (amort));
      amortsl = amort / l; gsl = 9.81 / l;
      dt = Math.abs (sd (tfdt.getText (), dt));
      tfdt.setText (Double.toString (dt));
      tempo = Math.abs (si (ttempo.getText (), tempo));
      ttempo.setText (Integer.toString (tempo));
      d.L = (int) (l * 200.0);
    }
  }

}
////////////////////////////////////////////////////////////////////////////////
protected class dessin extends Canvas implements MouseListener, MouseMotionListener {
	static final long serialVersionUID = 210203L;
  commandes cmd;
  Image img;
  Graphics g;
  boolean deplace;
  int XMAX, YMAX, X0, Y0, L, X, Y;

  public dessin (commandes cmd)
  { this.cmd = cmd;
    addMouseMotionListener (this);
    addMouseListener (this);

  }

  public void update (Graphics g) {
    paint (g);
  }

  public void paint (Graphics g1) {
	if (img == null || YMAX != getSize().height - 1 || XMAX != getSize().width - 1) {
	  img = createImage (getSize().width, getSize().height);
      g = img.getGraphics ();
      YMAX = getSize().height - 1;
      XMAX = getSize().width - 1;
      X0 = XMAX / 2;
      Y0 = 10;
      L = (int) (cmd.l * 200.0);
      X = (int) (L * Math.sin (cmd.a) + X0);
      Y = (int) (L * Math.cos (cmd.a) + Y0);
    }
    g.setColor (Color.white);
    g.fillRect (0,0,XMAX, YMAX);
    if (cmd.a > Math.PI) cmd.a -= 2.0 * Math.PI;
    if (cmd.a < - Math.PI) cmd.a += 2.0 * Math.PI;

    X = (int) (Math.sin (cmd.a) * L + X0);
    Y = (int) (Math.cos (cmd.a) * L + Y0);

    g.setColor (Color.blue);
    g.fillRect (X0 - 2, Y0 - 2, 5, 5);
    g.drawOval (X - 10, Y - 10, 20, 20);

    g.setColor (Color.green);
    g.drawLine (X0, Y0, X, Y);

    g.setColor (Color.black);
    g.drawRect (0, 0, XMAX, YMAX);

    g1.drawImage (img, 0, 0, this);
  }

  public void mousePressed (MouseEvent e)
  { e.consume ();
    deplace = (e.getX () >=  X - 20) && (e.getX () <= X + 20)
              && (e.getY () >= Y - 20) && (e.getY () <= Y + 20);
  }

  public void mouseDragged (MouseEvent e)
  { e.consume ();
    if (deplace)
    { if (e.getY () != Y0)
      { cmd.a = e.getX () - X0;
        cmd.a /= (e.getY () - Y0);
        cmd.a = Math.atan (cmd.a);
      }
      else
      { cmd.a = Math.PI / 2;
        if (e.getX () < X0) cmd.a = - cmd.a;
      }
      if (e.getY () < Y0) cmd.a += Math.PI;
      cmd.ap = 0.0;
    }
  }

  public void mouseReleased (MouseEvent e)
  { e.consume ();
    deplace = false;
    L = (int) (cmd.l * 200.0);
    X = (int) (L * Math.sin (cmd.a) + X0);
    Y = (int) (L * Math.cos (cmd.a) + Y0);
  }

  public void mouseMoved (MouseEvent e) { }
  public void mouseClicked (MouseEvent e) { }
  public void mouseEntered (MouseEvent e) { }
  public void mouseExited (MouseEvent e) { }

}
////////////////////////////////////////////////////////////////////////////////
protected class courbe extends Canvas {
  static final long serialVersionUID = 210203L;
  commandes cmd;
  int XMAX, YMAX, Y0, T;

  public courbe (commandes cmd, int W, int H) {
	this.cmd = cmd;
    setSize (W, H / 3);
    T = -1;
    repaint();
  }

  public void update (Graphics g) {
    paint (g);
  }

  public void paint (Graphics g) {
    if (T == -1 || XMAX != getSize().width - 1 || YMAX != getSize().height - 1) {
	  XMAX = getSize().width - 1;
      YMAX = getSize().height - 1;
      T = XMAX;
      Y0 = YMAX / 2;
    }
    if (T == XMAX) {
	  T = 0;
      g.setColor (Color.lightGray);
      g.fillRect (0, 0, XMAX, YMAX);
      g.setColor (Color.red);
      g.drawLine (0, Y0, XMAX, Y0);
    }
    g.fillRect (T ++, Y0 - (int)(cmd.a * YMAX / Math.PI) , 1, 1);
  }
}

////////////////////////////////////////////////////////////////////////////////

  public static void main (String [] args) {
	int w = 500;
	int h = 500;

	pendule p = new pendule(w, h);

	JFrame f = new JFrame ("Mouvement du pendule");
	f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
	f.add (p);
	f.setSize (w, h);
	f.setVisible (true);
  }

}
