一、多边形分割成三角形
这里我们直接使用第三方库:
- Efficient Polygon Triangulation,进入复制源代码即可使用。
- GPC – General Polygon Clipper library,很遗憾这个项目在20年8月停止了支持,还是很专业的一个图形分割项目,可以自行查找是否还有可以源码。
EPT方法:
函数按顺时针取3个点判断是否为凸角(同时其他点不得在其内),如果条件满足则去掉这三点中的中间点,切除出一个三角形,剩下多边形继续切割直到完成。
- rea函数:计算多边形面积。如果计算的多边形面积是负的则说明是逆时针取点。
- InsideTriangle函数:判断P是否在ABC三角形内(用的向量差积法,其实也是面积法)。
- Snip函数:判断三点条件。
- Process切割函数,当snip满足时,去除一个点,给多边形重新编号,取点向后移2位。
二、实验要求
(1)使用鼠标在屏幕客户区绘制任意点数的多边形。要求使用橡皮筋技术 动态绘制每条边;鼠标移动过程中按下 Shi 键时可绘制垂直边或水平边;将多 边形的终点移动到多边形的起点时自动封闭多边形;在绘制多边形的过程中,状 态栏动态显示鼠标光标的位置坐标。
(2)当开始绘制多边形时,更改鼠标光标为十字光标,多边形绘制完毕后 恢复为箭头光标。
(3)多边形闭合后自动调用有效边表算法填充多边形内部区域。
三、源码(使用EPT完成)
#include <iostream> #include <GL/glut.h> #include <glm/glm.hpp> #include <vector> #include "triangulate.h" /*---常量---*/ const int HEIGHT(800); const int WIDTH(800); /*---全局变量---*/ glm::vec2 StartPoint{ 0, 0 }; glm::vec2 EndPoint{ 0, 0 }; //绘线变量 std::vector<glm::vec2> VertexArray; //顶点数组 /*---函数---*/ void Display(); //mian中显示子程序 void Reshape(int, int); //投影变换函数 void MouseMove(int, int); //鼠标移动事件 void MouseClick(int, int, int, int); //鼠标点击事件 void DrawLine(int, int); //绘制直线 void DrawEdge(); //绘制多边形的边 void DrawPolygon(); //绘制多边形 Vector2dVector PolygonToTriangle(); //剪裁多边形 int main(int argc, char** argv) { glutInit(&argc, argv); //GLUT初始化 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //双缓存模式 glutInitWindowSize(WIDTH, HEIGHT); glutInitWindowPosition(50, 100); //窗口初始化 glClearColor(0, 0, 0, 1); //窗口颜色 glutCreateWindow("Draw and Filled Ploygon"); glutDisplayFunc(Display); glutMouseFunc(MouseClick); glutReshapeFunc(Reshape); glutMainLoop(); } void Display() { glClear(GL_COLOR_BUFFER_BIT); } void Reshape(int w, int h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, WIDTH, 0, HEIGHT); } void MouseMove(int x, int y) { std::cout << "(" << x << ", " << y << ")" << std::endl; int slope = ((y - StartPoint.y) / (x - StartPoint.x)); //斜率 int Shift = glutGetModifiers(); //获取特殊按键 glm::vec2 GoalPoint{ 0,0 }; if (GLUT_ACTIVE_SHIFT == Shift) { if (slope == 1) //斜率为1, 绘制 45°斜线 { GoalPoint.x = x; GoalPoint.y = (HEIGHT - x); } else if (slope == -1) //斜率为-1, 绘制 -45°斜线 { GoalPoint.x = x; GoalPoint.y = x; } else if ((slope > -1) && (slope < 1)) //斜率在-1到1之间, 绘制 x 方向平行线 { GoalPoint.x = x; GoalPoint.y = StartPoint.y; } else if ((slope < -1) || (slope > 1)) //斜率小于-1 或 大于1, 绘制 y 方向平行线 { GoalPoint.x = StartPoint.x; GoalPoint.y = (HEIGHT - y); } } else if (GLUT_ACTIVE_SHIFT != Shift) { GoalPoint.x = x; GoalPoint.y = (HEIGHT - y); } DrawLine(GoalPoint.x, GoalPoint.y); } void MouseClick(int button, int state, int x, int y) { if (GLUT_DOWN == state && GLUT_LEFT_BUTTON == button) { //左键按下:动态画线 if (VertexArray.empty()) { StartPoint.x = x; StartPoint.y = (HEIGHT - y); VertexArray.push_back(StartPoint); } //数组空:新建顶点存入数组,否则直接以多边形最后一个点作为顶点 StartPoint.x = VertexArray.back().x; StartPoint.y = VertexArray.back().y; glutMotionFunc(MouseMove); } else if (GLUT_UP == state && GLUT_LEFT_BUTTON == button) { int Shift = glutGetModifiers(); int slope = ((y - StartPoint.y) / (x - StartPoint.x)); if (GLUT_ACTIVE_SHIFT == Shift) { if (slope == 1) //斜率为1, 绘制 45°斜线 { EndPoint.x = x; EndPoint.y = (HEIGHT - x); } else if (slope == -1) //斜率为-1, 绘制 -45°斜线 { EndPoint.x = x; EndPoint.y = x; } else if ((slope > -1) && (slope < 1)) //斜率在-1到1之间, 绘制 x 方向平行线 { EndPoint.x = x; EndPoint.y = StartPoint.y; } else if ((slope < -1) || (slope > 1)) //斜率小于-1 或 大于1, 绘制 y 方向平行线 { EndPoint.x = StartPoint.x; EndPoint.y = (HEIGHT - y); } } else if (GLUT_ACTIVE_SHIFT != Shift) { EndPoint.x = x; EndPoint.y = (HEIGHT - y); } VertexArray.push_back(EndPoint); //终点存入 StartPoint = glm::vec2{ 0,0 }; EndPoint = glm::vec2{ 0,0 }; //Clear DrawEdge(); } else if (GLUT_DOWN == state && GLUT_RIGHT_BUTTON == button) { //右键把线段转换为多边形 DrawPolygon(); } } void DrawLine(int x, int y) { DrawEdge(); glColor3f(0, 1.0, 1.0); //颜色选择cyan glClear(GL_COLOR_BUFFER_BIT); //刷新缓冲区 glLineWidth(1); //线条宽度:1个像素 glBegin(GL_LINES); glVertex2i(StartPoint.x, StartPoint.y); glVertex2i(x, y); glEnd(); //画线 glutSwapBuffers(); } void DrawEdge() { glColor3f(0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glLineWidth(1); //基本设置同上 glBegin(GL_LINE_STRIP); for (auto i : VertexArray) { glVertex2i(i.x, i.y); } glEnd(); //画图 glutSwapBuffers(); } void DrawPolygon() { glColor3f(0, 0.5, 1.0); glClear(GL_COLOR_BUFFER_BIT); glLineWidth(1); //基本设置同上 Vector2dVector TriangleVertexArray = PolygonToTriangle(); glBegin(GL_TRIANGLES); for (auto i : TriangleVertexArray) { glVertex2i(i.GetX(), i.GetY()); } glEnd(); //画图 glutSwapBuffers(); } Vector2dVector PolygonToTriangle() { Vector2dVector PolygonVertexArray; Vector2dVector TriangleVertexArray; for (auto i : VertexArray) { Vector2d TheVertex(i.x, i.y); PolygonVertexArray.push_back(TheVertex); } Triangulate::Process(PolygonVertexArray, TriangleVertexArray); return TriangleVertexArray; }
Comments | NOTHING