Delphi 两个向量之间的角度
所以,我试图得到Delphi中两个t点之间的角度,结果比我预期的要难。我得到的结果无法解释(似乎是“到度”部分有问题),或者ArcTan2没有以我预期的形式返回一个总和。 -Delpi-v7:Delphi 两个向量之间的角度,delphi,math,Delphi,Math,所以,我试图得到Delphi中两个t点之间的角度,结果比我预期的要难。我得到的结果无法解释(似乎是“到度”部分有问题),或者ArcTan2没有以我预期的形式返回一个总和。 -Delpi-v7: function Modulo(x,y:Extended): Extended; var d: Extended; begin d := x / y; Result := (d - floor(d)) * y; end; function Degrees(Rads: Extended): Ext
function Modulo(x,y:Extended): Extended;
var d: Extended;
begin
d := x / y;
Result := (d - floor(d)) * y;
end;
function Degrees(Rads: Extended): Extended;
begin
Result := Rads*(180/Pi);
end;
function GetPointAngle(P1, P2: TPoint): Extended;
begin
Result := Modulo(Degrees(ArcTan2(-(P1.Y - P2.Y), P1.X - P2.X)) - 90, 360);
end;
然而,当我将代码移植到Python,或者在另一个Pascal变体中测试它时,上面的工作起来了。但是现在,它似乎返回了一个静态的总和(如果我“移动”第二个TPoint,则不会改变)
如果你想知道,我创建“模”函数只是因为“模”运算符中使用的除法运算符舍入为0,而不是向下(所以负数不起作用)
编辑:我注意到当p
远离另一点c
(反之亦然)时,从GetPointAngle()
返回的值(角度)会增加,即使TPoint(p
)沿着第二个TPoint(c
)的X轴拖动
编辑:
你们已经超越了自己,我已经看过了大部分的答案,似乎很难选择最好的答案!既然你们写的每件事都如此详细,我将用同样的细节来处理每件事:-)
另外:在我的第一篇文章中,我没有分享的是,我的函数被导出为一个DLL,可以从另一个pascal解释器(与delphi兼容)访问
最终解决方案(已更改):
GetPointAngle(P1,P2:TPoint)
To:GetPointAngle(const P1,P2:TPoint)
^我不明白声明常数的必要性…我想你要找的是两个向量之间的角度。也就是这个图中的θ: 代数点积可以几何表示为=| v1 | | v2 | cosθ。这可以重新排列以找到θ=cos-1/(|v1 | | v2 |) 返回以弧度为单位的角度。您可以使用
Math
单元中的RadToDeg()
将其转换为度
现在,另一种解释问题的方法是,取两点,然后在两点之间形成一条线。然后找出那条线和水平线之间的角度,比如说。如图所示:
仍然可以表示为两个向量之间的角度。第一个矢量是p2-p1,另一个是水平方向上的矢量(0,1)。将这两个输入到变换器之间的角度,你就有了答案。如果你想测量垂直的角度,那么你可以使用同样的想法
希望这里有足够的空间来解决这个问题,不管它实际上是什么。我假设你想要计算相对于这两个点之间形成的线的X轴的角度 对于这种情况,以下公式适用:
Tan(a) = (P2.Y - P1.Y) / (P2.X - P1.X)
也就是说:
a = ArcTan((P2.Y - P1.Y) / (P2.X - P1.X))
当两个点具有相同的X坐标时,这显然会导致EDivByZero
异常,因此您必须自己处理。此外,ArcTan
导致角度在0°…90°(即0..π/2)范围内,因此忽略正确的象限,而ArcTan 2
导致角度在-180°…180°范围内。向结果添加360°以将负角度转换为正角度:
function AngleOfLine(const P1, P2: TPoint): Double;
begin
if P2.X = P1.X then
if P2.Y > P1.Y then
Result := 90
else
Result := 270
else
Result := RadToDeg(ArcTan2(P2.Y - P1.Y, P2.X - P1.X));
if Result < 0 then
Result := Result + 360;
end;
现在,这是相对于默认情况下正Y轴指向上的世界坐标系。如果要将结果转换为正Y轴指向下方的设备坐标系,则从360°中减去结果:
Result := 360 - Result;
更新:
似乎ArcTan2
dóes负责零除法(即使在文档中是D7),因此例程变得简单得多:
function AngleOfLine(const P1, P2: TPoint): Double;
begin
Result := RadToDeg(ArcTan2((P2.Y - P1.Y),(P2.X - P1.X)));
if Result < 0 then
Result := Result + 360;
end;
直线的函数角度(常数P1,P2:TPoint):双精度;
开始
结果:=RadToDeg(ArcTan2((P2.Y-P1.Y),(P2.X-P1.X));
如果结果<0,则
结果:=结果+360;
结束;
编辑:
我注意到当p
距离另一点c
越远时,从GetPointAngle()
返回的值越大(反之亦然)
那要看情况。查看上图,如果第二个点沿x轴进一步移动,则角度减小。如果第二个点沿y轴进一步移动,则角度会增加。当然,这取决于两点所在的象限
此外,您的代码对
ArcTan2
的第一个参数求反,并从结果中再减去90°。我不知道你说的是什么意思,也不知道这是否是故意的,但这可能是意外结果的来源。下面的代码返回了与Delphi 7和FPC 2.7.1相同的结果,而且似乎是正确的。所以主要的问题是:我们期待什么,我们拥有什么
program Project2;
{$APPTYPE CONSOLE}
uses
Math;
{.$define speed}
function CalcAngle(const lx, ly: extended): extended; {$ifdef speed} inline; {$endif}
begin
Result := RadToDeg(ArcTan2(ly, lx));
end;
function Modulo(x, y: extended): extended; {$ifdef speed} inline; {$endif}
var
d: extended;
begin
d := x / y;
Result := (d - floor(d)) * y;
end;
function Degrees(Rads: Extended): Extended;
begin
Result := Rads*(180/Pi);
end;
function Modulo2(x: extended): extended; {$ifdef speed} inline; {$endif}
begin
if x < 0 then
Result := 360 + x
else
Result := x;
end;
function GetPointAngle(const lx, ly: integer): Extended;
begin
Result := Modulo(Degrees(ArcTan2(ly, lx)) - 90, 360);
end;
procedure OutTest(const lx, ly: extended);
var
a: extended;
begin
a := CalcAngle(lx, ly);
Writeln(
a: 10: 4,
Modulo(a - 90, 360):10:4,
GetPointAngle(round(lx), round(ly)):10:4);
end;
begin
OutTest(2, 0);
OutTest(0, 2);
OutTest(-2, 2);
OutTest(-2, -2);
OutTest(2, 3);
OutTest(100, 2);
Readln;
end.
程序项目2;
{$APPTYPE控制台}
使用
数学;
{.$define speed}
函数CalcAngle(const lx,ly:extended):extended;{$ifdef speed}内联;{$endif}
开始
结果:=RadToDeg(ArcTan2(ly,lx));
结束;
函数模(x,y:扩展):扩展;{$ifdef speed}内联;{$endif}
变量
d:扩展;
开始
d:=x/y;
结果:=(d-楼层(d))*y;
结束;
功能度(Rads:扩展):扩展;
开始
结果:=Rads*(180/Pi);
结束;
功能模块2(x:扩展):扩展;{$ifdef speed}内联;{$endif}
开始
如果x<0,则
结果:=360+x
其他的
结果:=x;
结束;
函数GetPointAngle(const lx,ly:integer):扩展;
开始
结果:=模(度数(ArcTan2(ly,lx))-90360;
结束;
程序输出测试(常数lx,ly:扩展);
变量
a:延长;
开始
a:=CalcAngle(lx,ly);
写(
a:10:4,,
模(a-90360):10:4,
GetPointAngle(圆形(lx)、圆形(ly)):10:4);
结束;
开始
超出测试(2,0);
超出测试(0,2);
超出测试(-2,2);
超出测试(-2,-2);
超出测试(2,3);
超出测试(100,2);
Readln;
结束。
你所说的“两点之间的角度”是什么意思?你是说两个向量之间的角度吗?没有这样的角度
function AngleOfLine(const P1, P2: TPoint): Double;
begin
Result := RadToDeg(ArcTan2((P2.Y - P1.Y),(P2.X - P1.X)));
if Result < 0 then
Result := Result + 360;
end;
program Project2;
{$APPTYPE CONSOLE}
uses
Math;
{.$define speed}
function CalcAngle(const lx, ly: extended): extended; {$ifdef speed} inline; {$endif}
begin
Result := RadToDeg(ArcTan2(ly, lx));
end;
function Modulo(x, y: extended): extended; {$ifdef speed} inline; {$endif}
var
d: extended;
begin
d := x / y;
Result := (d - floor(d)) * y;
end;
function Degrees(Rads: Extended): Extended;
begin
Result := Rads*(180/Pi);
end;
function Modulo2(x: extended): extended; {$ifdef speed} inline; {$endif}
begin
if x < 0 then
Result := 360 + x
else
Result := x;
end;
function GetPointAngle(const lx, ly: integer): Extended;
begin
Result := Modulo(Degrees(ArcTan2(ly, lx)) - 90, 360);
end;
procedure OutTest(const lx, ly: extended);
var
a: extended;
begin
a := CalcAngle(lx, ly);
Writeln(
a: 10: 4,
Modulo(a - 90, 360):10:4,
GetPointAngle(round(lx), round(ly)):10:4);
end;
begin
OutTest(2, 0);
OutTest(0, 2);
OutTest(-2, 2);
OutTest(-2, -2);
OutTest(2, 3);
OutTest(100, 2);
Readln;
end.