Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 两个向量之间的角度_Delphi_Math - Fatal编程技术网

Delphi 两个向量之间的角度

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

所以,我试图得到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): 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.