オイラー角でよく使うけど忘れがちな計算のまとめ。
0~360°に正規化する
480°→120°
-10°→350°
負数にも対応しており、例えば-10の場合は戻り値は350となる。
// 指定された角度を 0 ~ 2π の間の値に狭める(単位:ラジアン)
function float RepeatAngle(float angle;)
{
float result = angle % (PI * 2);
if(result < 0) result += PI * 2;
return result;
}
float angle = -10;
angle = RepeatAngle(radians(angle));
printf('angle:' + sprintf('%g', degrees(angle)) + '\n');
// 350
-180~180°に正規化する
190°→-170°
-320°→40°
360°をまたいだ角度の引き算をする場合に有効。たとえば、30°から350°を引く場合に答えを-320°ではなく、40°に正規化したい。
// 指定された角度を π ~ -π の間の値に狭める(単位:ラジアン)
function float WrapAngle(float angle;)
{
float result = (angle + PI) % (PI * 2);
if(result < 0) result += PI * 2;
result -= PI;
return result;
}
float angle = WrapAngle(radians(30 - 350));
printf('angle:' + sprintf('%g', degrees(angle)) + '\n');
// 40
180°で折り返しながら360°で循環させるため、180°足してから0~360°の範囲に収め、再度180°を引いて元の角度に戻している。
ベクトルの成す角を0~360°に正規化する
XZ平面にてベクトル同士の成す角度を内積とアークコサインで計算すると、0~180°に収まるが、これを0~360°にしたい場合、外積の符号を使う。ポイントを時計回りの順でソートしたい場合などに便利。


X軸方向のベクトル(1,0,0)に対する各ポイントの角度。
//
// XZ平面で0~360°に正規化する
// Run Over: Detail
//
float crossY(vector v0; vector v1;)
{
return(v0.z * v1.x - v1.z * v0.x);
}
for(int i = 0; i < npoints(0); i++)
{
vector pos = point(0, "P", i);
float angle = acos(dot(normalize(pos), set(1,0,0)));
// 外積のY成分で比較
float y = crossY(normalize(pos), set(1,0,0));
// 負の場合は補角を取る
if(y < 0)
angle = 2*PI - angle;
setpointattrib(0, "__angle", i, degrees(angle));
}