简体   繁体   English

2个向量之间的角度是否反射? (C#)

[英]Is angle between 2 vectors reflex? (C#)

I need to be able to check whether the angle between three points (A, B and C) which make up part of a shape is reflex (> PI radians), as in the diagram below (sorry for poor paint skills!): 我需要能够检查构成形状一部分的三个点(A,B和C)之间的角度是否是反射性的(> PI弧度),如下图所示(抱歉,绘画技巧很差!):

角度ABC

My points should always be anti-clockwise, and I always want to measure the angle on the inside of the shape. 我的点应该始终是逆时针方向,并且我总是想测量形状内部的角度。

I am currently doing this using the following code: 我目前正在使用以下代码执行此操作:

//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;

This has worked in all the cases I have tried up until now, but with these co-ords it does not work: 到目前为止,这在我尝试过的所有情况下都有效,但是在这些配合下它不起作用: 在此处输入图片说明

(Where B=(2,3) ) (其中B =(2,3))

The angle I get back is ~-0.5, whereas I would expect ~+0.5. 我返回的角度是〜-0.5,而我期望的是〜+ 0.5。 Any ideas why this is wrong? 任何想法为什么这是错误的?

UPDATE 更新

I've attempted to implement Nico's solution, and while I understand it in theory I'm getting a real headache trying to implement it. 我已经尝试实施Nico的解决方案,尽管从理论上理解它,但尝试实施它确实令人头疼。 Here is the code so far: 这是到目前为止的代码:

//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;

I'm not sure how toB in your code is defined, and also I'm not familar with PointF . 我不确定代码中的toB是如何定义的,而且我也不熟悉PointF

Anyway you should use the cosine rule c^2 = a^2 + b^2 - 2ab cos(C) (where a,b,c are the lengths of the sides of the triangle, and C is the angle subtending c ): 无论如何,您应该使用余弦规则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);
}

In the following, I assume that the x-axis points to the right and the y-axis points upwards. 在下文中,我假设x轴指向右侧,而y轴指向上方。 If this is not the case in your scenario, you might need to switch some signs. 如果情况并非如此,则可能需要切换一些信号。

If you have the line segment (x1, y1) - (x2, y2) and points are sorted counter-clockwise, you know that the shape is left of the line segment. 如果您具有线段(x1, y1) - (x2, y2)并且点是逆时针排序的,则您知道形状在该线段的左侧。 The orthogonal direction vector that points to the line segment's left is: 指向线段左侧的正交方向向量为:

leftDir = (y1 - y2, x2 - x1)

Together with the line segment, this direction defines a half space. 该方向与线段一起定义了半个空格。 If the following angle is convex, the third point must lie in this half space. 如果跟随角度是凸角,则第三个点必须位于该半空间中。 If that's not the case, the angle is concave (which you apparently call reflex): 如果不是这种情况,则该角度为凹形(您显然将其称为反射):

You can determine if the point lies in the same half space with the dot product: 您可以确定该点是否与点积位于相同的半空间中:

isConcave = dot(p3 - p2, leftDir) < 0

In code: 在代码中:

float dx = x3 - x2;
float dy = y3 - y2;
float dot = dx * leftDir.x + dy * leftDir.y
return dot < 0;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM