多边形凹凸性的判断、自相交判断
说明该博文转载自 弱花3kou 的文章 [OpenGL] 绘制并且判断凹凸多边形、自相交多边形分析凸多边形凹多边形自相交代码#include <iostream>#include <ctime>#include <math.h>#include <vector>using namespace std;// 定义点struct Pos {int x;i
说明
该博文参考 弱花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
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)