说明


该博文参考 弱花3kou 的文章 [OpenGL] 绘制并且判断凹凸多边形、自相交多边形

分析


  • 凸多边形

在这里插入图片描述

  • 凹多边形

在这里插入图片描述

  • 自相交

在这里插入图片描述

代码


#include <iostream>
#include <ctime>
#include <math.h>
#include <vector>

using namespace std;

// 定义点
struct Pos {
    int x;
    int y;
};

// 定义边
struct Edge {
    int x1, x2;
    int y1, y2;
    int vx;
    int vy;
    int a, b, c;
};

// 定义多边形
struct Poly {
    // 点集
    int xx[100];
    int yy[100];

    // 边集
    Edge Edges[100];

    int plotNums = 0; //点数量
    int edgeNums = 0; //边数量

    // 记录凹点
    int conv = 0;
};

Poly poly;


// 求交点坐标,这里的A、B、C是直线方程 Ax + By + C = 0 的参数,求交点是利用向量叉乘计算得到的
// 具体可查看博客:用叉积求二维直线交点
// https://www.jianshu.com/p/3468c9967fc7
Pos CrossPos(int p1, int p2) {
    Pos res;
    int A1 = poly.Edges[p1].a;
    int B1 = poly.Edges[p1].b;
    int A2 = poly.Edges[p2].a;
    int B2 = poly.Edges[p2].b;
    int C1 = poly.Edges[p1].c;
    int C2 = poly.Edges[p2].c;

    int m = A1 * B2 - A2 * B1;
    if (m == 0)
        cout << "第" << p1 << "边和第" << p2 << "边" << "无交点" << endl;
    else {
        res.x = (C2 * B1 - C1 * B2) / m;
        res.y = (C1 * A2 - C2 * A1) / m;
    }
    return res;

}

// 判断点是否在线段内,意思就是判断点是否在矩形框内
bool JudgeInLine(Pos pos, Edge edge) {
    int maxX = edge.x1 >= edge.x2 ? edge.x1 : edge.x2;
    int minX = edge.x1 <= edge.x2 ? edge.x1 : edge.x2;
    int maxY = edge.y1 >= edge.y2 ? edge.y1 : edge.y2;
    int minY = edge.y1 <= edge.y2 ? edge.y1 : edge.y2;
    if (pos.x <= maxX && pos.x >= minX && pos.y <= maxY && pos.y >= minY) {
        return true;
    }
    return false;
}

// 求叉积 返回正负值
int CrossProduct(int n) {
    n = n % poly.edgeNums;
    int np = (n + 1) % poly.edgeNums;
    return (poly.Edges[n].vx * poly.Edges[np].vy - poly.Edges[np].vx * poly.Edges[n].vy) >= 0 ? 1 : -1;
}


// 判断是什么多边形
bool Judge() {
    /*输出边信息*/
    for (int i = 0; i < poly.edgeNums; i++) {
        cout << "Vx:" << poly.Edges[i].vx << "  " << "Vy:" << poly.Edges[i].vy << "  " << "A:" << poly.Edges[i].a << "  " << "B:" << poly.Edges[i].b << "  " << "C:" << poly.Edges[i].c << endl;
    }

    /*判断自交*/
    Pos interPos;
    if (poly.edgeNums > 3)
        for (int i = 0; i < poly.edgeNums; i++) {
            interPos = CrossPos(i, (i + 2) % poly.edgeNums);
            if (JudgeInLine(interPos, poly.Edges[i]) && JudgeInLine(interPos, poly.Edges[(i + 2) % poly.edgeNums])) {
                cout << "该多边形为自相交多边形" << endl;
                return false;
            }
        }

    /*判断凹凸*/
    // 判断向量叉积 是否为同一正负
    int judge;
    if (CrossProduct(0) >= 0)
        judge = 1;
    else
        judge = -1;
    //判断每一个角,两边向量乘积是否同符号
    for (int i = 1; i <= poly.edgeNums; i++) {
        if (judge * CrossProduct(i) < 0) {
            poly.conv = i;
            ChangePoly();
            cout << "该多边形为凹多边形" << endl;
            return false;
        }
    }
    cout << "该多边形为凸多边形" << endl;
    return true;
}

关于自相交的理解


  • 在原博客中,自相交判断利用的是 点与线段的位置关系,也就是 线段与 X 和 Y 轴形成的区域 是否有交集来进行判断

  • 原博客中,它是先求两条直线的交点,然后判断 该交点是否同时位于两个线段所构成的矩形内

值得注意的是,这里是对 与其不相邻的所有边进行比较,也就是说,假如一个复杂凸多边形一共有 N 条边,且当前边为 i,那么其要与 [0, i - 2] ∪ [i + 2, N] 的边进行比较判断

看图说话


基于此,我绘制了以下两个图来说明情况

例1: 在下图中,对于左侧图形来讲(局部),对于红色边,因为其不与相邻边判断,所以不和绿色边判断,但是需要和蓝色边判断,通过直线求交可以得到玫红色的交点,可以看出,玫红色的交点没有落在红色和蓝色区域,那么就 不是自相交

在这里插入图片描述

例2: 再换一个图形,此时玫红色的交点只落在蓝色区域,没有落在红色区域,同样也 不是自相交

在这里插入图片描述

例3: 但是对于下图,玫红色交点同时落在红色和蓝色区域,那么就形成了自相交

在这里插入图片描述

现在你应当对自相交的判断有了一定解,如果你还不了解,你品,你细品,你细细品 …

上面 3 个例子描述的是局部情况,下面我们看一个完整的例子

原图如下:

在这里插入图片描述

  • 我们从红边开始,按照顺时针方向进行判断,红色边只和蓝色、黄色、紫色边判断
    在这里插入图片描述

  • 再判断绿色边,绿色边只和黄色、紫色、灰色边判断
    ...

  • 再判断蓝色边,蓝色边只和紫色、灰色、红色边判断
    在这里插入图片描述

over

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐