两个向量之间的角度是否反射? (C#)
Is angle between 2 vectors reflex? (C#)
我需要能够检查构成形状的一部分的三点(A、B 和 C)之间的角度是否为反射角(> PI 弧度),如下图所示(抱歉画得不好技能!):
我的点应该总是逆时针的,我总是想测量形状内侧的角度。
我目前正在使用以下代码执行此操作:
//triangle[] is an array of the three points I am testing, corresponding
// to [A, B, C] on the diagram above
//Vectors from B to A and C
PointF toA = PointFVectorTools.difference(triangle[0], triangle[1]);
PointF toC = PointFVectorTools.difference(triangle[2], triangle[1]);
double angle = Math.Atan2(toB.Y, toB.X) - Math.Atan2(toA.Y, toA.X);
//Put angle in range 0 to 2 PI
if (angle < 0) angle += 2 * Math.PI;
return angle > Math.PI;
到目前为止,这在我尝试过的所有情况下都有效,但是对于这些协调它不起作用:
(其中 B=(2,3) )
我得到的角度是 ~-0.5,而我期望是 ~+0.5。知道为什么这是错误的吗?
更新
我已经尝试实施 Nico 的解决方案,虽然我在理论上理解它,但在尝试实施它时却感到非常头疼。这是到目前为止的代码:
//Vector A -> B
float dx = triangle[1].X - triangle[0].X;
float dy = triangle[1].Y - triangle[0].Y;
//Left normal = (y, -x)
PointF leftDir = new PointF(dy, -dx);
//Vector B -> C
dx = triangle[2].X - triangle[1].X;
dy = triangle[2].Y - triangle[1].Y;
//Dot product of B->C and Left normal
float dot = dx * leftDir.X + dy * leftDir.Y;
return dot < 0;
我不确定你代码中的 toB
是如何定义的,而且我也不熟悉 PointF
。
无论如何你应该使用余弦规则 c^2 = a^2 + b^2 - 2ab cos(C)
(其中 a,b,c
是三角形边的长度,C
是对着 c
的角度) :
public bool IsReflex(... triangle)
{
var a = GetVectorLength(triangle[0].x, triangle[0].y, triangle[1].x, triangle[1].y);
var b = GetVectorLength(triangle[1].x, triangle[1].y, triangle[2].x, triangle[2].y);
var c = GetVectorLength(triangle[2].x, triangle[2].y, triangle[0].x, triangle[0].y);
var cosC = (c*c - a*a - b*b) / (2*a*b);
var C = Math.Acos(cosC); // this returns a value between 0 and pi
return Math.Abs(C) > (Math.PI/2);
}
private double GetVectorLength(double x0, double y0, double x1, double y1)
{
// using Pythagoras
var sideX = x0 - x1;
var sideY = y0 - y1;
return Math.Sqrt(sideX*sideX + sideY*sideY);
}
下面我假设x轴指向右边,y轴指向上方。如果您的情况并非如此,您可能需要切换一些标志。
如果你有线段(x1, y1) - (x2, y2)
并且点是逆时针排序的,你就知道形状在线段的左边。指向线段左侧的正交方向向量为:
leftDir = (y1 - y2, x2 - x1)
连同线段,这个方向定义了一半space。如果后面的角是凸角,则第三个点一定在这一半space内。如果不是这种情况,则角度是凹的(你显然称之为反射):
你可以判断点是否与点积在同一半space:
isConcave = dot(p3 - p2, leftDir) < 0
在代码中:
float dx = x3 - x2;
float dy = y3 - y2;
float dot = dx * leftDir.x + dy * leftDir.y
return dot < 0;
我需要能够检查构成形状的一部分的三点(A、B 和 C)之间的角度是否为反射角(> PI 弧度),如下图所示(抱歉画得不好技能!):
我的点应该总是逆时针的,我总是想测量形状内侧的角度。
我目前正在使用以下代码执行此操作:
//triangle[] is an array of the three points I am testing, corresponding
// to [A, B, C] on the diagram above
//Vectors from B to A and C
PointF toA = PointFVectorTools.difference(triangle[0], triangle[1]);
PointF toC = PointFVectorTools.difference(triangle[2], triangle[1]);
double angle = Math.Atan2(toB.Y, toB.X) - Math.Atan2(toA.Y, toA.X);
//Put angle in range 0 to 2 PI
if (angle < 0) angle += 2 * Math.PI;
return angle > Math.PI;
到目前为止,这在我尝试过的所有情况下都有效,但是对于这些协调它不起作用:
(其中 B=(2,3) )
我得到的角度是 ~-0.5,而我期望是 ~+0.5。知道为什么这是错误的吗?
更新
我已经尝试实施 Nico 的解决方案,虽然我在理论上理解它,但在尝试实施它时却感到非常头疼。这是到目前为止的代码:
//Vector A -> B
float dx = triangle[1].X - triangle[0].X;
float dy = triangle[1].Y - triangle[0].Y;
//Left normal = (y, -x)
PointF leftDir = new PointF(dy, -dx);
//Vector B -> C
dx = triangle[2].X - triangle[1].X;
dy = triangle[2].Y - triangle[1].Y;
//Dot product of B->C and Left normal
float dot = dx * leftDir.X + dy * leftDir.Y;
return dot < 0;
我不确定你代码中的 toB
是如何定义的,而且我也不熟悉 PointF
。
无论如何你应该使用余弦规则 c^2 = a^2 + b^2 - 2ab cos(C)
(其中 a,b,c
是三角形边的长度,C
是对着 c
的角度) :
public bool IsReflex(... triangle)
{
var a = GetVectorLength(triangle[0].x, triangle[0].y, triangle[1].x, triangle[1].y);
var b = GetVectorLength(triangle[1].x, triangle[1].y, triangle[2].x, triangle[2].y);
var c = GetVectorLength(triangle[2].x, triangle[2].y, triangle[0].x, triangle[0].y);
var cosC = (c*c - a*a - b*b) / (2*a*b);
var C = Math.Acos(cosC); // this returns a value between 0 and pi
return Math.Abs(C) > (Math.PI/2);
}
private double GetVectorLength(double x0, double y0, double x1, double y1)
{
// using Pythagoras
var sideX = x0 - x1;
var sideY = y0 - y1;
return Math.Sqrt(sideX*sideX + sideY*sideY);
}
下面我假设x轴指向右边,y轴指向上方。如果您的情况并非如此,您可能需要切换一些标志。
如果你有线段(x1, y1) - (x2, y2)
并且点是逆时针排序的,你就知道形状在线段的左边。指向线段左侧的正交方向向量为:
leftDir = (y1 - y2, x2 - x1)
连同线段,这个方向定义了一半space。如果后面的角是凸角,则第三个点一定在这一半space内。如果不是这种情况,则角度是凹的(你显然称之为反射):
你可以判断点是否与点积在同一半space:
isConcave = dot(p3 - p2, leftDir) < 0
在代码中:
float dx = x3 - x2;
float dy = y3 - y2;
float dot = dx * leftDir.x + dy * leftDir.y
return dot < 0;