版权声明:本文为CSDN博主「SixDayCoder」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sixdaycoder/article/details/79791389
问题描述:判断二维平面上一个点P是在三角形ABC的内部还是外部。
如图,点P在三角形ABC内部,可以通过以下三个条件判断:
- 点P和点C在直线AB同侧
- 点P和点B在直线AC同侧
- 点P和点A在直线BC同侧
如果给定一条线段AB和点C,能否判断出来C和AB的位置关系呢?
这里的位置关系是指C是在线段AB上,还是在AB的左边,又或者是在AB的右边呢?
也许我们对左边还是右边的定义不明确,给一个图体会一下:
这里的C就是我们说的在AB的左边,就是你用你的右手四指指向AB的朝向,然后大拇指那边就是“左边”了。
那么我们如何判断C和AB的位置关系呢?
先给出代码,然后给予解释:
判断点是否在线段AB的左侧
typedef struct
{
float x;
float y;
}Point;
//input : 直线s->e,点p
//return :
//> 0 p is left of the line
//= 0 p is on the line
//< 0 p is right of the line
bool IsLeftPoint(Point s, Point e, Point p)
{
return ((e.x - s.x) * (p.y - s.y)) > ((p.x - s.x) * (e.y - s.y));
}
让我们解释一下上述代码。
这个函数很短,这个形式有点奇怪,为什么这样就能判断呢?
我们把return的那行重写一下:
((e.x - s.x) * (p.y - s.y)) - ((p.x - s.x) * (e.y - s.y)) > 0 //等价
而这个式子的样子,和叉乘意外的有点相似。
我们接触叉乘的时候都是在三维空间,那么这个二维空间的形似叉乘的式子是怎么来的?
其实你可以把二维向量看做是第三维为0的三维向量,这样你套叉乘的公式,可以得到:
(x1,y1,0) X (x2,y2,0) = (0, 0, x1y2 – y1x2)
但是我们一般取的是这个向量的最后一维x1y2 - y1x2,这样看起来好像就是叉乘的结果是一个数量而非向量了。
再回到我们的IsLeftPoint函数,实际上我们就是根据三个点构造了两个向量然后做了一次叉乘的运算,我们是用的向量se叉乘向量sp
其实,这个x1y2 - y1x2还有一个比较神奇的特点:
如果x1y2 - y1x2的结果为负,那么说明sep三个点必定是按照逆时针顺序排列的
判断点是否在三角形外
我们已经知道了如何判断一个点是否在直线的左侧,那么如何利用这个来判断点是否在三角形外呢?
其实不难想到,如果我们把三角形的点顺序按照顺时针方向排列,也就是ABC的顺序:
如果三角形ABP、BCP、CAP都是按照逆时针的方向排列的,那么P必然在ABC的外部。
float IsInTriangle(float x, float y, float ax, float ay, float bx, float by, float cx, float cy)
{
return (bx - ax) * (y - ay) > (by - ay) * (x - ax) &&
(cx - bx) * (y - by) > (cy - by) * (x - bx) &&
(ax - cx) * (y - cy) > (ay - cy) * (x - cx) ? false : true;