CERN ROOT (C++) グラフ作成 (4-2) 2体問題シミュレーション 改良版　(TMarkerによる)

# 概要

`TMarker`を覚えたので、[CERN ROOT (C++) グラフ作成 (4) 2体問題シミュレーション　アニメーション](https://qiita.com/h6591/items/c7c5ca9e7c66b7d136b5)を`TMarker`を使ってアニメーションにしました。`TMarker`のほうが`TGraph`より簡単でした。
ここでは`TMarker`のサンプルコードと２体問題のコードのみ掲載し、詳しい説明は省きました。

# TMarkerのサンプル

```c++:marker_test.C
{
    TCanvas *canvas = new TCanvas ("canvas");
    auto frame = canvas->DrawFrame(-0.1, -1.1, 5.1, 1.1);
    for (int i = 0; i < 99; i++) {
        double x = i * 0.05;
        double y = sin(3*x);
        int j = (i % 30) + 20;  //MarkerStyle
        auto m = new TMarker(x, y, j);
        m->SetMarkerSize(1);
        m->SetMarkerColor(i+1);
        m->Draw();
    }
}
```

x-y座標軸や範囲を設定するため、`DrawFrame`が必要です。引数はx-min, y-min, x-max, y-maxの順です。

```c++
root [0] .L marker_test.C
root [1] 
```

![marker_test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/41e91971-50c0-b93b-a643-26a40ce086da.png)


# TMarkerによる２体問題

```c++:n2body_anime2.C
void n2body_anime2() {
    //Sleep時間
    constexpr double timer = 1000/120.0; //ミリ秒 1秒間に約120回描画
    //実行時間
    constexpr int exec_time = 10;  //秒
    //実行ステップ回数
    constexpr int repeat_count = (int)1000 * exec_time / timer; //ミリ秒
    //time step
    constexpr double dt =  0.01;
    constexpr double dt_half =  dt / 2.0;
    //万有引力定数
    constexpr double G = 6.67430e-11;    
    //body1の質量
    constexpr double body1_m = 1.0e+11;
    //body2の質量
    constexpr double body2_m = 2.0e+11;

    constexpr double body1_init_vel_y = 1.1;
    //body1とbody2の運動量の和が0になるように決める
    constexpr double body2_init_vel_y = -body1_init_vel_y * body1_m / body2_m;

    //body1の位置
    ROOT::Math::XYVector body1_pos(-1.5, 0.0);
    //body1の速度
    ROOT::Math::XYVector body1_vel(0.0, body1_init_vel_y);
    //body2の位置
    ROOT::Math::XYVector body2_pos(1.0, 0.0);
    //body2の速度
    ROOT::Math::XYVector body2_vel(0.0, body2_init_vel_y);
    
    auto canvas = new TCanvas("canvas");
    auto height = canvas->GetWindowHeight();
    auto width = canvas->GetWindowWidth();
    constexpr double x_range = 2.0;
    auto y_range = x_range * height / width; 
    auto frame  = canvas->DrawFrame(-x_range, -y_range, x_range, y_range);

    auto body1 = new TMarker(body1_pos.x(), body1_pos.y(), 20);
    body1->SetMarkerColor(kRed);
    body1->SetMarkerSize(2);
    body1->Draw();

    auto body2 = new TMarker(body2_pos.x(), body2_pos.y(), 20);
    body2->SetMarkerColor(kGreen);
    body2->SetMarkerSize(4);
    body2->Draw();

    canvas->ModifiedUpdate();

    auto r_vec = body1_pos - body2_pos;  //rベクトル
    auto r3  = pow(r_vec.mag2(),1.5);    //r^3
    auto force1_vec = -G * body2_m / r3 * r_vec; //body1に作用する力
    auto force2_vec =  G * body1_m / r3 * r_vec; //body2に作用する力
   
    for(int i = 0; i < repeat_count && !gSystem->ProcessEvents(); i++) {
        gSystem->Sleep(timer);

        auto body1_vel_half =  body1_vel + dt_half * force1_vec;
        auto body2_vel_half =  body2_vel + dt_half * force2_vec;
        body1_pos +=  dt * body1_vel_half;
        body2_pos +=  dt * body2_vel_half;

        r_vec = body1_pos - body2_pos;    
        r3  = pow(r_vec.mag2(),1.5);      
        force1_vec = -G * body2_m / r3 * r_vec; 
        force2_vec =  G * body1_m / r3 * r_vec;
        
        body1_vel = body1_vel_half + force1_vec * dt_half; 
        body2_vel = body2_vel_half + force2_vec * dt_half; 

        body1->SetX(body1_pos.x());
        body1->SetY(body1_pos.y());
        body2->SetX(body2_pos.x());
        body2->SetY(body2_pos.y());
        
        canvas->ModifiedUpdate();
    }
}
```
毎回x,yの軸のスケールを設定が不要なのでその分簡単になった。
gifファイルの出力はカットしました。
スクショは`TGraph`をほぼ同じなので省略します。