C-9 多边形
多边形的定义
-
由一组连续存放的点定义多边形,依次连接点并且起始点与结束点相连。围成的图形就是多边形
-
//定义了一个正方形 pair<int,int> polygon[4] ={{0,0},{100,0},{100,100},{0,100}}
判断一个点是否在多边形内部
- 根据该点引出的射线与多边形边的交点个数的奇偶来判断。如果一个点引出的射线,与多边形的交点是偶数,那么就在多边形外部,是奇数就在多边形内部。注意是射线与多边形边的交点,与多边形顶点的交点不算在内部。
计算多边形的面积
- 将多边形进行三角剖分,分成一个个的三角形,计算每个三角形的面积并累加就是多边形的面积了。
- 关于三角剖分的方法在之后会介绍
两个多边形是否相交
- 遍历其中一个多边形的每一条边判断是否与另一个多边形的边相交
多边形的剪裁(多边形求交)
- GitHub上的开源项目clipper2就解决了这一问题
- 绿色部分就是淡红色和淡蓝色这两个多边形的交集,当然也是一个多边形
求多边形的包围线
-
如下图(圆可看成离散化的多边形),给定一个多边形如何求出环绕着这个多边形的包围线呢?这里我回答了上一篇一笔带过的问题。
-
这个问题在绘制PCB电路里有应用,用kicad等等之类的工具绘制的线段都是带有一定宽度的,当然不止在绘制PCB电路里应用,可能还有一些其他的绘制场景里也用到了该方法。
-
在思想上可以这么思考。对于求给定的线宽r,将一个可以以r为半径的圆的圆心放置在多边形或者链条(没有闭合的多边形)的轨道上,将该圆沿着多边形(链条)进行平移,圆留下的轨迹就是我们需要的包围线。也看成多边形相交和拐角处理的问题。
-
在kicad中,是用clipper这一函数库进行处理的,对于pcb电路的轨迹,输入一条线段,kicad就提供方法,将这一条没有宽度的线段进行求包围线,输出为一条有宽度的线段,最终呈现在屏幕上。
-
-
-
截取项目里的一些代码,来展示如何使用clipper2来获得输入链条的包围线,非常方便,效率也不错。
-
当然clipper2的网址也有相关说明
-
void myGeometry::createLine(const char* path) { outline.createOutLine(path); int mark = 100; for (int i = 0; i < outline.OutLinePoints.size(); i++) { Clipper2Lib::Path64 clipper_polygon; for (int j = 0; j < outline.OutLinePoints[i].size(); j++) { int x = outline.OutLinePoints[i][j].X() * mark; int y = outline.OutLinePoints[i][j].Y() * mark; clipper_polygon.push_back(Clipper2Lib::Point64(x, y)); } Clipper2Lib::ClipperOffset offset; offset.AddPath(clipper_polygon, Clipper2Lib::JoinType::Miter, Clipper2Lib::EndType::Joined); Clipper2Lib::Paths64 solution; //进行包围线的输出!!! offset.Execute(13 * mark, solution); std::vector<std::vector<std::array<LONG64, 2>>> temp_polygon; for (int j = 0; j < solution.size(); j++) { auto path = solution[j]; std::vector<std::array<LONG64, 2>> trace; for (int k = 0; k < solution[j].size(); k++) { std::array<LONG64, 2> p = { path[k].x, path[k].y }; trace.push_back(p); } temp_polygon.push_back(trace); createSideMesh(trace,100*mark); } Polygons.push_back(temp_polygon); } }
参考资料
- clipper2: https://github.com/AngusJohnson/Clipper2