编程之美:第四章 数字之趣 4.4点是否在三角形内

/*
点是否在三角形内:
如果一个二维坐标系中,已知三角形顶点的坐标,那么对于坐标系中的任意一点,如何判断该点是否在三角形内(点在三角形边线上也可)?
假设三角形顶点的坐标为ABC(逆时针),需要判断点D是否在该三角形内。

分析:
利用垂涎的交点可以判断。如果点D在三角形内,所有的垂线交点都在三角形的边线之内。如果点D在三角形之外,则垂线的交点就会在三角形边线的延长线上。
但是钝角三角形是不可取的,此方法错误。

解法1:
研究点与线段之间的关系,考虑把点D和其他的三个点连接起来。将问题转化为比较三角形ABC的面积 与 三角形ABD BCD CAD的面积之和
如果Sabc = Sabd + Sbcd + Scad,那么点D在三角形ABC的内部或者边上,如果 Sabc < Sabd + Sbcd + Scad ,则点D在三角形外部。

计算三角形面积用海伦公式
计算出三边的边长分别为a,b,c,
p = (a + b + c)/2;
S = 根号下(p-a)*(p-b)*(p-c)*p


解法2:
因为三角形是凸的,所以如果有一个D在三角形ABC内,那么沿着三角形的边界逆时针走,点D一定保持在边界的左边,也就是说点D在边AB,BC,CA的左边。
判断一个点P3是否在射线P1,P2的左边,可以通过P1P2,P1P3两个向量叉积的正负判断
如果叉积为正,则P3在P1P2的左边
          负,            右
		  0,             射线上

输入:
3 2(输入测试点的坐标)
1 1(输入三角形三个顶点的坐标)
5 1
3 3

2 3
1 1
5 1
3 3
输出:
Yes
No

*/

/*
关键:
1 if(dSabd + dSbcd + dScda > dSabc)//如果三个小三角形的面积大于原三角形面积,那么说明测试点不再原三角形内
2 return sqrt( (dP - dA) * (dP - dB) * (dP - dC) * dP);//计算面积采用海伦公式,计算出三边的边长分别为a,b,c,p = (a + b + c)/2;S = 根号下(p-a)*(p-b)*(p-c)*p
3 bool isInRectangle_vector(const Point& testPoint,Point* recPoint)//通过向量来判断测试点是否在另外两点所形成射线的左边,需要计算
	//BD*BC >0 ,CD * CA > 0,AD * AB > 0
4 	doubleT dRet = (point2._iX - point3._iX) * (point1._iX - point3._iX) + (point2._iY - point3._iY) * (point1._iY - point3._iY);
	//我们以第三个点为主点,判断一个点P3是否在射线P1,P2的左边,可以通过P1P2,P1P3两个向量叉积的正负判断,如果叉积为正,则P3在P1P2的左边
 
*/

#include <stdio.h>
#include <math.h>

typedef float doubleT;

typedef struct Point
{
	doubleT _iX;
	doubleT _iY;
}Point;

doubleT distance(const Point& point1,const Point& point2)
{
	return sqrt( (point1._iX - point2._iX) * (point1._iX - point2._iX) + (point1._iY - point2._iY) * (point1._iY - point2._iY) );
}

doubleT area(const Point& point1,const Point& point2,const Point& point3)
{
	doubleT dA = distance(point1,point2);
	doubleT dB = distance(point1,point3);
	doubleT dC = distance(point2,point3);
	doubleT dP = (dA + dB + dC)/2.0;
	return sqrt( (dP - dA) * (dP - dB) * (dP - dC) * dP);//计算面积采用海伦公式,计算出三边的边长分别为a,b,c,p = (a + b + c)/2;S = 根号下(p-a)*(p-b)*(p-c)*p
}


bool isInRectangle(const Point& testPoint,Point* recPoint)
{
	doubleT dSabd = area(testPoint,recPoint[0],recPoint[1]);
	doubleT dSbcd = area(testPoint,recPoint[1],recPoint[2]);
	doubleT dScda = area(testPoint,recPoint[2],recPoint[0]);
	doubleT dSabc = area(recPoint[0],recPoint[1],recPoint[2]);
	if(dSabd + dSbcd + dScda > dSabc)//如果三个小三角形的面积大于原三角形面积,那么说明测试点不再原三角形内
	{
		return false;
	}
	else
	{
		return true;
	}
}



bool product(const Point& point1,const Point& point2,const Point& point3)
{
	doubleT dRet = (point2._iX - point3._iX) * (point1._iX - point3._iX) + (point2._iY - point3._iY) * (point1._iY - point3._iY);
	//我们以第三个点为主点,判断一个点P3是否在射线P1,P2的左边,可以通过P1P2,P1P3两个向量叉积的正负判断,如果叉积为正,则P3在P1P2的左边
	return dRet > 0.0 ? true : false;
}

bool isInRectangle_vector(const Point& testPoint,Point* recPoint)//通过向量来判断测试点是否在另外两点所形成射线的左边,需要计算
	//BD*BC >0 ,CD * CA > 0,AD * AB > 0
{
	bool bRet1 = product(testPoint,recPoint[0],recPoint[1]);
	bool bRet2 = product(testPoint,recPoint[1],recPoint[2]);
	bool bRet3 = product(testPoint,recPoint[2],recPoint[0]);
	return bRet1 && bRet2 && bRet3; 
}


void process()
{
	Point testPoint;
	Point rectanglePoint[3];
	while(EOF != scanf("%f %f",&testPoint._iX,&testPoint._iY))
	{
		for(int i = 0 ; i < 3 ; i++)
		{
			scanf("%f %f",&rectanglePoint[i]._iX,&rectanglePoint[i]._iY);
		}
		//if(isInRectangle(testPoint,rectanglePoint))
		if(isInRectangle_vector(testPoint,rectanglePoint))
		{
			printf("Yes\n");
		}
		else
		{
			printf("No\n");
		}
	}
}

int main(int argc,char* argv[])
{
	process();
	getchar();
	return 0;
}

    原文作者:天地一扁舟
    原文地址: https://blog.csdn.net/qingyuanluofeng/article/details/47187873
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞