/*
  2003/10/30  小松 研吾
*/

import java.applet.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.*;

public class TrappedParticlesAppletM extends Applet implements ActionListener {
    // 変数宣言
    public Vector datax = new Vector();
    public Vector datay = new Vector();
    public static double h = 0.01;      // 座標規格化定数

    public static double pi = Math.PI;  // 円周率 π
    public static double dt;            // 時間刻み幅
    public static double r_eq;          // 赤道面上での粒子の距離
    public static double l;             // L 値
    public static double alpha_eq;      // 赤道面でのピッチ角
    public static double sinA_eq;       // sin(alpha_eq)^2
    public static double bp;            // 赤道面上惑星表面での磁場の強さ
    public static double v;             // 全速度

    // 変数宣言
    double x;             // x 座標
    double y;             // y 座標
    double t;             // 経過時間
    double alpha;         // ピッチ角
    double lamda;         // 粒子位置の緯度
    double v_pala;        // 磁力線方向の速度
    double r;             // 粒子の距離
    double sinA;          // sin(alpha)^2
    double b;             // 磁場の強さ
    double bx;            // x 方向の磁場の強さ
    double by;            // y 方向の磁場の強さ
    double bm;            // ミラーポイントでの磁場の強さ
    double cosLamda;      // cos(lamda)
    double sinLamda;      // sin(lamda)

    String text1, text2;
    int check = 0;
    Button bt1, bt2;
    TextField tf1, tf2;
    public static int width;            // ウィンドウ幅
    public static int height;           // ウィンドウ高さ

    public void init() {
        // Layoutを無効にする。
        setLayout(null);

        // ボタンを配置
        tf1 = new TextField("");
        add(tf1);
        tf1.setBounds(65, 5, 50, 20);
        tf1.addActionListener(this);

        tf2 = new TextField("");
        add(tf2);
        tf2.setBounds(160, 5, 50, 20);
        tf2.addActionListener(this);

        bt1 = new Button("計算");
        add(bt1);
        bt1.setBounds(215, 5, 50, 20);
        bt1.addActionListener(this);

        bt2 = new Button("clear");
        add(bt2);
        bt2.setBounds(270, 5, 50, 20);
        bt2.addActionListener(this);
    }

    public void start() {
        // 初期化
        dt       = 0.0;
        r_eq     = 0.0;
        l        = 0.0;
        alpha_eq = 0.0;
        sinA_eq  = 0.0;
        bp       = 0.0;
        v        = 0.0;

        x        = 0.0;
        y        = 0.0;
        t        = 0.0;
        alpha    = 0.0;
        lamda    = 0.0;
        v_pala   = 0.0;
        r        = 0.0;
        sinA     = 0.0;
        b        = 0.0;
        bx       = 0.0;
        by       = 0.0;
        bm       = 0.0;
        cosLamda = 0.0;
        sinLamda = 0.0;


        // 刻み幅
        dt = 0.001;

        // 初期状態
        l = 3.0;
        tf2.setText(String.valueOf(l));          // TextField にデフォルト値を入れる
        alpha_eq = (pi/6.0) * 360.0 / (2*pi);
        tf1.setText(String.valueOf(alpha_eq));   // TextField にデフォルト値を入れる

        repaint();
    }


    public void actionPerformed(ActionEvent ev) {
        // どのオブジェクトに関するイベントかを取得する。
        Object obj = ev.getSource();
        if(obj == bt1) {
            check = 1;

            // TextField から L 値を取得
            l = Double.valueOf(tf2.getText()).doubleValue();
            // TextField からピッチ角を取得
            alpha_eq = 2*pi*Double.valueOf(tf1.getText()).doubleValue()
                / 360.0;

            r_eq = l;               // 惑星半径が 1 になるようにする
            sinA_eq = sin(alpha_eq) * sin(alpha_eq);   // (sin(alpha_eq))^2 の値 sinA_eq
            bp = -1.0;              // 地球の場合 3.11x10^-5 T 。
                                    // 負号は双極子モーメントの向きが南向きであることを示す。
            v = 10.0;               // 1 keV の電子の速度は 1.87x10^7 m/s
            sinA = sinA_eq;         // 赤道面での (sin(alpha))^2
            v_pala = v_pala(sinA);  // 速度の磁力線方向成分
            x = l;                  // 赤道面での x
            y = 0.0;                // 赤道面での y
            alpha = alpha_eq;       // 赤道面でのピッチ角
            lamda = 0.0;            // 赤道面での λ
            r = r_eq;               // 赤道面での r
            cosLamda = 1.0;
            sinLamda = 0.0;

            // ミラーポイントでの磁場の強さ bm
            //        bm = b(x, y, r);
            while(v_pala >= 0.001) {
                // 現在の位置の距離
                r = r(x, y);
                // 現在の位置での磁場の強さ
                b = b(x, y, r);
                bx = bx(x, y, r);
                by = by(x, y, r);
                // (sin(alpha))^2 の値 sinA_eq
                sinA = sinA(b);
                // v_pala の値
                v_pala = v_pala(sinA);
                // x, y の更新
                x += v_pala * dt * bx/b;
                y += v_pala * dt * by/b;
                // 時間 t の更新
                t += dt;
                // λを求める
                cosLamda = x / r;
                sinLamda = y / r;

                // ベクトルオブジェクトに x, y の値を代入
                datax.addElement(Double.toString(x));
                datay.addElement(Double.toString(y));
            }
            repaint();

        } else if(obj == bt2) {
            check = 0;
            repaint();
        }
    }

    public void paint(Graphics g) {
        // 変数宣言
        Dimension d = getSize();
        Color color = Color.red;

        // ウィンドウの幅と高さ
        width = d.width;
        height = d.height;

        // 背景色
        setBackground(Color.white);
        g.setColor(Color.black);
        // 
        g.drawString("ピッチ角=", 5, 18);
        g.drawString("°", 117, 18);
        g.drawString("L値=", 130, 18);

        text1 = tf1.getText();
        g.drawString(text1, 130, 50);
        text2 = tf2.getText();
        g.drawString(text2, 260, 50);


        // 表示域の周囲に四角形を描画
        g.drawRect(0, 0, width-1, height-1);
        // x, y軸を描画
        g.drawLine(0, height-20, width-1, height-20);
        g.drawLine(20, 30, 20, height-1);
        // 目盛りを描画 （単位：惑星半径）
        for(int i=0; i<=width; ++i)
            g.drawLine(Math.round(Math.round(r_eq/l/h))*i+20, height-20-2,
                       Math.round(Math.round(r_eq/l/h))*i+20, height-20+2);

        if(check == 1) {
            // データ値の曲線を描画する
            g.setColor(Color.blue);
            double oldpltx, oldplty, pltx, plty;
            int cnum = datax.size();
            for(int i=0; i<cnum; i++) {
                pltx = Double.parseDouble((String)datax.elementAt(i));
                plty = Double.parseDouble((String)datay.elementAt(i));
                if((i%20)==0)   // 20 ステップごとに描画
                    g.fillOval(convertx(pltx)-2, converty(plty)-2, 4, 4);
            }
        }
        else if(check == 0) {
            // ベクトルの要素を削除
            int cnum = datax.size();
            for(int i=0; i<cnum; i++) {
                datax.clear();
                datay.clear();
            }
        }
    }

    // sin(theta)
    private static double sin(double theta) {
        double value = 0;
        value = Math.sin(theta);
        return value;
    }

    // cos(theta)
    private static double cos(double theta) {
        double value = 0;
        value = Math.cos(theta);
        return value;
    }

    // (sin(alpha))^2 の値 sinA
    private static double sinA(double b) {
        double value = 0;
        value = sinA_eq * l*l*l * b / Math.abs(bp);
        return value;
    }

    // (x*x+y*y)^(1/2) の値 r
    private static double r(double x, double y) {
        double value = 0;
        value = Math.pow((x*x + y*y), 0.5);
        return value;
    }

    // 磁場の強さ b
    private static double b(double x, double y, double r) {
        double value = 0;
        value = Math.abs(bp) * Math.pow(r_eq, 3) * Math.pow((4.0*y*y + x*x), 0.5)
            / (l*l*l * Math.pow(r, 4));
        return value;
    }

    // 磁場の x 方向の強さ bx
    private static double bx(double x, double y, double r) {
        double value = 0;
        value = bp * Math.pow(r_eq, 3) * 3.0*x*y / (l*l*l * Math.pow(r, 5));
        return value;
    }

    // 磁場の y 方向の強さ by
    private static double by(double x, double y, double r) {
        double value = 0;
        value = bp * Math.pow(r_eq, 3) * (2.0*y*y - x*x) / (l*l*l * Math.pow(r, 5));
        return value;
    }

    // 磁場に平行な速度 v_pala
    private static double v_pala(double sinA) {
        double value = 0;
        value = Math.pow(1.0-sinA, 0.5) * v;
        return value;
    }

    // x座標をアプレット上の座標に変換
    // h で規格化し、ウィンドウの左から 20 ピクセル左へ移動
    private static int convertx(double x) {
        int pltx;
        pltx = Math.round(Math.round(x/h)) + 20;
        return pltx;
    }

    // y座標をアプレット上の座標に変換
    // h で規格化し、上下反転
    private static int converty(double y) {
        int plty;
        plty = height - Math.round(Math.round(y/h)) - 20;
        return plty;
    }

}
