クロソイド曲線

クロソイド曲線とは

クロソイド曲線は道路や鉄道、ローラーコースター等で使われている曲線。人体への負担が軽減したり乗り心地が向上する。

直線から円にいきなり進入すると急にハンドルを切らないといけなくなるので徐々に切れるように緩和曲線を挟む。事故削減効果が顕著で、その後は積極的に使われるようになった。

公式と計算

クロソイド曲線は曲率を一定割合で変化させて描かれる曲線で、曲率半径と始点からの曲線長をそれぞれRとLとしたときに両者の積は一定となる。

クロソイドの公式
R*L=A^2
τ = L / (2*R)

R(円の半径)とL(クロソイド曲線長)が決まれば残りのA(クロソイドパラメータ)が決まる。AとLを先に決めればRが決まる。先に2つを決めて残りが決まる、という関係。

AとLから計算する

R(半径)はR=A^2/Lから求まる。
τ (接線角)はτ = L/2*Rで求まる。

τとRから計算する

A(クロソイドパラメータ)はA = R * √2τで求まる。
L(クロソイド曲線長)はL = A*A/Rで求まる。

AとRから計算する

L(クロソイド曲線長)はL = A*A/Rから求まり
τ (接線角)はτ = L / (2*R)で求まる。

交角Iはガイドカーブのベクトルが成す角なので内積とアークコサインで計算する。
円弧の角度theta = I – (τ1 + τ2)

クロソイドカーブの座標X,Yの計算式。
XとYを求めるには角度tauを0から任意の角度までを刻んで計算する。

曲線の描画

クロソイド曲線を描く一番シンプル方法は回転角度を加算してポイントを打っていくもの。

//
// クロソイド曲線の描画
// Run Over: Detail
//

// Step
int frame = 1000;   // フレーム数
float step = 0.01;  // フレームあたりで進む距離
float angAcc = 0.0001; // フレームあたりで曲げる角度

// Angle
float angle = 0;    // 角度(Angular Position)
float angVel = 0;   // 角速度(Angular Velocity)

// ポリライン生成
int prim = addprim(0, "polyline");
setprimattrib(0, "Cd", prim, set(0, 0.5, 1.0));

vector pos = set(0, 0, 0);
int pt = addpoint(0, pos);
addvertex(0, prim, pt);

for(int i = 0; i < frame; i++)
{
    // 毎フレーム角度を加算していく
    angVel += angAcc;
    angle += angVel;
    pos += set(cos(angle), sin(angle), 0) * step;
    pt = addpoint(0, pos);
    addvertex(0, prim, pt);
}

公式で描画する

半径Rが10、τが45°のクロソイド曲線を描画する。
A = R * √2τになり、L = A * A / Rで求まる。

// 
// クロソイド曲線の描画
// Run Over: Detail
//

// クロソイド曲線のX成分を求める関数(tauとAから)
function float clothoid_x(float tau; float A)
{
    return A / sqrt(2) * 2 * sqrt(tau) * (1 - (1 / 10.0 * pow(tau, 2) + (1 / 216.0 * pow(tau, 4)) - (1 / 9360.0 * pow(tau, 6))));
}

// クロソイド曲線のY成分を求める関数
function float clothoid_y(float tau; float A)
{
    return A / sqrt(2) * (2/3.0) * sqrt(tau) * tau * (1 - (pow(tau, 2) / (42.0 / 3.0)) + (pow(tau, 4) / (1320.0 / 3.0)) - (pow(tau, 6) / (75600.0 / 3.0)) );
}

float R = 10;
float tau = radians(45);

float A = R * sqrt(2*tau);
float L = A * A / R;

//
// 原点にクロソイド曲線を描画する
//
int prim = addprim(0, "polyline");
int num = 100;
for(int i = 0; i < num; i++)
{
    float t = tau / float(num-1) * i;
    
    float x = clothoid_x(t, A);
    float y = clothoid_y(t, A);
    
    vector pos = set(x, y, 0);
    
    int pt = addpoint(0, pos);
    addvertex(0, prim, pt);
}
タイトルとURLをコピーしました