今回からしばらくは描画用の計算サブルーチンを書いて行きます。
角度でソートする場合など、角度を決まった範囲内に収めたい場合があります。例えば 0°〜360° や -180°〜+180° に収まるようにです。具体的には角度が下限より小さければ360を足し、上限以上なら360を引きます。
(* -------- 角度を指定した範囲に収める -------- *)
function NormalAngle360(ang, minAng: real): real; { 角度を指定した範囲内の角度にして返す。 }
{ 角度範囲は miniAng〜miniAng+360である。
miniAng <= ang < maxAng となるようにangを調整する。 }
Const
dA = 360;
var
result, maxAng :real;
begin
maxAng:= minAng + dA;
if ang < minAng then
result:= ang + dA * (Trunc((miniAng - ang) / dA) + 1)
else if maxAng <= ang then
result:= ang - dA * (Trunc((maxAng - ang) / dA) + 1)
else
result:= ang;
NormalAngle360:= result;
end;{NormalAngle360}
(2022/09/30:修正 )
直線の角度は始点と終点の順番によって180度変わるので、角度を180度の範囲に収めたい場合があります。例えば 0°〜180° や -90°〜+90° に収まるようにです。NormalAngle360との違いは定数dAの値だけです。
function NormalAngle180(ang, minAng: real): real; { 角度を指定した範囲内の角度にして返す。 }
{ 角度範囲はminiAng〜miniAng+180である。
Tan(ang)を変えずに miniAng <= ang < maxAng となるようにangを調整する。 }
Const
dA = 180;
var
result, maxAng :real;
begin
maxAng:= minAng + dA;
if ang < minAng then
result:= ang + dA * (Trunc((miniAng - ang) / dA) + 1)
else if maxAng <= ang then
result:= ang - dA * (Trunc((maxAng - ang) / dA) + 1)
else
result:= ang;
NormalAngle180:= result;
end;{NormalAngle180}
(2022/09/30:修正 )
ベクトル計算の組込みサブルーチンでは角度の単位は度なので、三角関数もラジアンでなく度のほうが都合が良いです。Sin(角度 * Pi / 180) や Sin(Deg2Rad(角度)) と書くのは面倒なので専用の関数を作りました。
関数名は、結局は元の関数の名前の最後にDegreeのDを付けましたが、Ang2SinやSin2Angが最初の候補でした。新しく作ったサブルーチンの名前との整合性を取るか、元の関数からの類推のしやすさを取るかで悩みました。両方作ってしまうという最終手段がありますが、とりあえずはこれで我慢しておきます。
(* -------- 度を角度単位とした三角関数 -------- *)
function SinD(ang :real); { Sinを度で計算して返す }
begin
SinD:= Sin(ang * Pi / 180);
end;
function CosD(ang :real); { Cosを度で計算して返す }
begin
CosD:= Cos(ang * Pi / 180);
end;
function TanD(ang :real); { Tanを度で計算して返す }
begin
TanD:= Tan(ang * Pi / 180);
end;
function ArcSinD(sinA :real); { ArcSinを度で計算して返す }
begin
ArcSinD:= ArcSin(sinA) * 180 / Pi;
end;
function ArcCosD(cosA :real); { ArcCosを度で計算して返す }
begin
ArcCosD:= ArcCos(cosA) * 180 / Pi;
end;
function ArcTanD(tanA :real); { ArcTanを度で計算して返す }
begin
ArcTanD:= ArcTan(tanA) * 180 / Pi;
end;
一度にSinとCosの値が欲しいことが良くあるので手続きにしました。
procedure Ang2SinCos(ang :real; var sinA, cosA :real);
{ Sin(ang)とCos(ang)を返す(角度の単位は度) }
var
v ;real;
begin
v:= Ang2Vec(ang, 1);
cosA:= v.x; sinA:= v.y;
end;
ArcTan関数では垂直の角度は得られません。 組込み関数だけだと、
v.x:= dx;
v.y:= dy;
ang:= Vec2Ang(v);
のように書かなくてはなりません。以前に書いたベクトル変数の関数を使えば、
ang:= Vec2Ang(XY2Vec(dx, dy));
のようにひとつの文に出来ますが、もっと簡単に、
ang:= XY2Ang(dx, dy);
と書けるように新しい関数を作りました。
(* -------- dx, dy から角度(度)/長さを返す。 -------- *)
function XY2Ang(dx, dy :real): real; { dx, dy から角度(度)を返す。 }
var
v :vector;
begin
v.x:= dx; v.y:= dy; v.z:= 0;
XY2Ang:= Vec2Ang(v);
end;
そういえば、手計算やExcelではTangentをいますが、プログラムではあまり使いませんね。±90度で答えが無限大になってエラーが出るので、条件分けの必要があって面倒です。
dXとdYから長さを求めたいことは多いのですが、ピタゴラスの定理( dist:= Sqrt(dx * dx + dy * dy); )やベクトルに変換しての計算( dist:= Vec2Dist(XY2Dist(dx, dy); )をいちいち書くのは面倒なので関数にしました。
function XY2Dist(dx, dy :real): real; { dx, dy から長さを返す。 }
begin
XY2Dist:= Sqrt(dx * dx + dy * dy);
end;