判断点是否在凸多边形内

判断点是否在凸多边形内

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;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值