文章目录
判断点是否在凸多边形内
1,原理
假设凸多边形顶点,按照顺时针顺序构成顶点数组verts:Point[],依次取两个顶点构成线段序列。
若点落在凸多边形内,则必有:该点在所有的线段序列的右侧或者左侧。
2、右手坐标系
让右手拇指指向x轴的正方向,食指指向y轴的正方向,如果中指能指向z轴的正方向,则称这个坐标系为右手直角坐标系。反之则是左手直角坐标系。
3、向量叉积
补充知识:
向量叉积,向量P = (x1, y1); Q = (x2, y2); P×Q = (x1y2 - x2y1);
叉积的一个非常重要性质是可以通过它的符号判断两矢量相互之间的顺逆时针关系:
若 P × Q > 0 , 则P在Q的顺时针方向。
若 P × Q < 0 , 则P在Q的逆时针方向。
若 P × Q = 0 , 则P与Q共线,但可能同向也可能反向。
叉积的方向与进行叉积的两个向量都垂直,所以叉积向量即为这两个向量构成平面的法向量。
可以理解利用向量的叉积,很容易判定一个多边形的凹凸性。也可以判定点是否在多边形的内部。
- 判定多边形的凹凸性
即:依次顺时针遍历多边形的定点,如果是凸多边形,向量的叉积会保持一致,反之就是凹多边形了。
代码如下:
实现叉乘:
double cross(Point& p1, Point& p2, Point& p0)
{
//取P0P1向量,P0P2向量,进行叉乘
//如果结果为正,P1点位于向量P0P2的顺时针方向
//反之在逆时针方向
return (p1.x - p0.x) * (p2.y - p0.y)*1.0 - (p1.y - p0.y) * (p2.x - p0.x)*1.0;
}
//假定多变形的定点按顺时针已排序。
bool isConvexPolygon(QVector<Point> Polygon)
{
int len = Polygon.size();
int s = 0, e = len;
if(e == 2)
{
return true;
}
while (s <= e-3) {
if (cross(Polygon[s+1], Polygon[s+2],Polygon[s]) < 0) {
s ++;
} else {
return false;
}
}
return true;
}
假设凸多边形各个定点坐标按照逆时针方向存储于一个数组中,
首先,确定点目标点M于某两个相邻的顶点Pn,Pn+1构成的向量之间,
然后,确定M点是否在向量(Pn,Pn+1)的逆时针方向,如果是顺时针方向则不在凸多边形内。
代码如下:
bool inConvexPolygon(QVector<Point> Polygon, Point target)
{
int len = Polygon.size();
if (cross(target, Polygon[1], Polygon[0]) > 0 && cross(target, Polygon[len - 1], Polygon[0]) < 0) {
return false;
}
int s = 1, e = len -1;
int line = -1;
while (s <= e) {
int m = s + ((e-s) >> 1); //二分法查找
if (cross(target, Polygon[m], Polygon[0]) > 0) { // target在m顺时针方向
line = m; // line保存的是m逆时针方向后的第一个点
e = m -1;
} else { // target在m逆时针方向
s = m + 1;
}
}
return cross(Polygon[line], target, Polygon[line -1]) > 0;
}
思考:如果假设凸多边形各个定点坐标按照顺时针方向存储于一个数组中呢?
改写如下:
bool inConvexPolygon2(QVector<Point> Polygon, Point target)
{
int len = Polygon.size();
if (cross(target, Polygon[1], Polygon[0]) < 0 && cross(target, Polygon[len - 1], Polygon[0]) > 0) {
qDebug()<<"dot here";
return false;
}
int s = 1, e = len -1;
int line = -1;
while (s <= e) {
int m = s + ((e-s) >> 1);
if (cross(target, Polygon[m], Polygon[0]) < 0) { // target在逆时针方向
line = m; // line保存的是m顺时针方向后的第一个点
e = m -1;
} else { // target在m顺时针方向
s = m + 1;
}
}
return cross(Polygon[line-1], target, Polygon[line]) > 0;
}