• [math]判断一个点是否在多边形内的方法



    多边形的内角是由两条相邻边形成边界之内的角;如果一个多边形的所有内角均小于180°,则该多边形为凸(convex)多边形;否则为凹(concave)多边形:

    • 凸多边形的任意两个顶点间的连线位于多边形内部或边上;
    • 按顺序计算向量叉积:凸多边形均同号,凹多边形不同号。

    向量叉乘判别法

    向量叉乘法,只对非凹多边形有效,对于凹多边形需要切割为凸多边形。

    设多边形的顶点依次为A1, A2 … An,要判断的点为P,那么:

    • 分别计算向量PA1叉乘向量PA2,向量PA2叉乘向量PA3,…,向量PA(n-1)叉乘向量PAn,以及向量PAn叉乘向量PA1;
    • 若这些叉乘的结果都同向的话,那么这个点就在多边形的内部。

    面积和判别法

    判断目标点与多边形的每条边组成的三角形面积和,是否等于该多边形,相等则在多边形内部。

    设多边形的顶点依次为1,2,...,n,要判断的点为P。用P点连接多边形各顶点:

    • 若P点在多边形以内,则P与各顶点组成的三角形正好填充此多边形;反之,则不能。
    • 使用多边形面积计算公式,计算面积S(根据叉乘原理):
      S = 1 2 ∣ ∑ i = 1 n ( x i ∗ y i + 1 − x i + 1 y i ) ∣ S=\frac{1}{2}\left|\sum\limits_{i=1}^n(x_i*y_{i+1} - x_{i+1}y_i)\right| S=21 i=1n(xiyi+1xi+1yi)
      其中 x n + 1 = x 1 , y n + 1 = y 1 x_{n+1}=x1, y_{n+1}=y1 xn+1=x1,yn+1=y1
    • 使P点作为参考点,计算各三角形面积和,则有:
      S = 1 2 ∣ ∑ i = 1 n ( ( x i − x p ) ∗ ( y i + 1 − y p ) − ( x i + 1 − x p ) ∗ ( y i − y p ) ) ∣ S=\frac{1}{2}\left|\sum\limits_{i=1}^n( (x_i-x_p)*(y_{i+1}-y_p) - (x_{i+1}-x_p)*(y_i-y_p))\right| S=21 i=1n((xixp)(yi+1yp)(xi+1xp)(yiyp))
    • 若面积一致则在多边形以内,反之则不在多边形以内。

    夹角和判别法

    夹角和判别法,只对非凹多边形有效,对于凹多边形需要切割为凸多边形。

    判断目标点与所有边的夹角和是否为360度,为360度则在多边形内部。

    引射线法

    从目标点出发引一条射线,看这条射线和多边形所有边的交点数目:

    • 有奇数个交点,则说明在内部;
    • 有偶数个交点,则说明在外部。

    射线法就是做一条从P点出发的射线,当穿过区域边界的次数为偶数时该点在区域外,如果是奇数则在区域内:
    在这里插入图片描述

    一条射线穿过区域的边界只有两种情况,穿入和穿出:

    • 当点在区域外时,射线首次经过边界时一定是穿入,且每次穿入必对应一次穿出,所以最终的穿越次数一定是偶数;
    • 当点在区域内时,射线首次经过边界一定是穿出;若后续有穿入,必对应一次穿出;所以最终的穿越总数是奇数;

    一般为处理方便,都做水平方向的射线;以下几种情况需要特殊处理:

    • 点在边界上,根据实际需要做区域内或区域外处理;

    • 射线穿过交点:

      • 若两个线段的另外一个端点在射线的两侧,则算做穿越;如交点P2处的P1与P3;
      • 若端点在同侧,则不算穿越;如交点P5处的P4与P6;
        在这里插入图片描述
    • 射线穿过边(与边重合):与交点类似,可看做不穿越

    PNPoly算法

    W. Randolph Franklin提出的PNPoly可以非常方便地判断点是否在多边形内;假设多边形的坐标存放在一个数组里。

    先分别找出多边形顶点的X坐标和Y坐标的最小/最大值,然后判断目标坐标点是否在这个四边形之内:

    if (p.x < minX || p.x > maxX || p.y < minY || p.y > maxY) {
        // 这个测试都过不了。。。直接返回false;
    }
    
    • 1
    • 2
    • 3

    判断点是否在多边形内:

    // nSize:多边形中的顶点数
    // vert:包含多边形顶点的x和y坐标的数组。
    // test:需要判断的点位置
    int pnpoly (Point[] vert, int nSize, Point test) {
        int i, j, c = 0;
        for (i = 0, j = nSize-1; i < nSize; j = i++) {
            if ( ( (vert.y[i]>test.y) != (vert.y[j]>test.y) ) && (test.x < (vert.x[j]-vert.x[i]) * (test.y-vert.y[i]) / (vert.y[j]-vert.y[i]) + vert.x[i]) )
                c = !c;
        }
        return c;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    每次计算都涉及到相邻的两个点和待测试点

    • 被测试点的纵坐标test.y是否在本次测试的两个相邻点纵坐标范围之内:即vert.y[i]
    • 被测点test是否在i,j两点之间的连线之下(相交判断);

    在这里插入图片描述

    相交点c的坐标为:
    x 2 − x 1 y 2 − y 1 = x ′ − x 1 y − y 1 ⇒ x ′ = x 1 + ( x 2 − x 1 ) ( y − y 1 ) y 2 − y 1 \frac{x_2-x_1}{y_2-y_1}=\frac{x'-x_1}{y-y_1} \\ \Rightarrow x'=x_1 + \frac{(x_2-x_1)(y-y_1)}{y_2-y_1} y2y1x2x1=yy1xx1x=x1+y2y1(x2x1)(yy1)

  • 相关阅读:
    原型设计模式
    PyQt5 GUI编程(QMainWindow与QWidget模块结合使用)
    MySQL库操作
    【481. 神奇字符串】
    Spring Boot中解决跨域问题(CORS)
    Python使用turtle绘图:ht();st();isvisible()
    Tessent scan&ATPG(9) simulation mismatch(debug向量仿真问题)
    快速记住《计算机文化基础》海量题法
    XGBoost预测及调参过程(+变量重要性)--血友病计数数据
    有关在 Windows 上使用 Python 的常见问题解答
  • 原文地址:https://blog.csdn.net/alwaysrun/article/details/126563925