Описание
Обратные тригонометрические функции одной переменной, такие, как арксинус, арккосинус, арктангенс и другие, имеют следующие недостатки:
- Значительное увеличение погрешности вблизи осей Ox или Oy
- При некоторых углах параметры стремятся к бесконечности
- Неполный охват возможных углов (Pi вместо 2 * Pi)
По этим причинам, когда нужно узнать угол по двум координатам, используют функцию «арктангенс двух переменных». Название не претендует на корректность. Более корректным является название «аргумент комплексного числа», но название ArcTan2 уже прижилось.
В самом простом случае (X = 0, Y = 0) любой результат будет верным, но вернуть надо что–то одно, поэтому 0. Далее вся плоскость разбивается по диагоналям между осями Ox и Oy, чтобы в каждом квадранте поделить меньшую по модулю координату на большую по модулю, вычислить арктангенс этого значения и сложением/вычитанием с Pi или Pi/2 привести полученный угол к углу относительно Ox. Левый квадрант, содержащий отрицательную часть оси Ox, дополнительно разбивается ею на два октанта с разрывом между -Pi и Pi.
Реализация
function ArcTan2(X, Y: Real): Real;
begin
if (X = 0.0) and (Y = 0.0) then
ArcTan2 := 0.0
else if X >= Y then
begin
if X >= -Y then
ArcTan2 := ArcTan(Y / X) { правый квадрант }
else
ArcTan2 := -Pi / 2 - ArcTan(X / Y) { нижний квадрант }
end
else
begin
if X >= -Y then
ArcTan2 := Pi / 2 - ArcTan(X / Y) { верхний квадрант }
else if Y >= 0.0 then
ArcTan2 := Pi + ArcTan(Y / X) { верхний октант в левом квадранте }
else
ArcTan2 := -Pi + ArcTan(Y / X) { нижний октант в левом квадранте }
end
end;
begin
WriteLn(ArcTan2(-1.0, -0.5):0:3, ' ', ArcTan2(-1.0, -1.0):0:3, ' ',
ArcTan2(-0.5, -1.0):0:3, ' ', ArcTan2(0.0, -1.0):0:3, ' ',
ArcTan2(0.5, -1.0):0:3, ' ', ArcTan2(1.0, -1.0):0:3, ' ',
ArcTan2(1.0, -0.5):0:3, ' ', ArcTan2(1.0, 0.0):0:3);
WriteLn(ArcTan2(1.0, 0.5):0:3, ' ', ArcTan2(1.0, 1.0):0:3, ' ',
ArcTan2(0.5, 1.0):0:3, ' ', ArcTan2(0.0, 1.0):0:3, ' ',
ArcTan2(-0.5, 1.0):0:3, ' ', ArcTan2(-1.0, 1.0):0:3, ' ',
ArcTan2(-1.0, 0.5):0:3, ' ', ArcTan2(-1.0, 0.0):0:3, ' ',
ArcTan2(0.0, 0.0):0:3);
{ -2.678 -2.356 -2.034 -1.571 -1.107 -0.785 -0.464 0.000 }
{ 0.464 0.785 1.107 1.571 2.034 2.356 2.678 3.142 0.000 }
end.