基于Weiler-Atherton剪裁布尔运算openGL实现-2D

来源:互联网 发布:js怎么定义二维数组 编辑:程序博客网 时间:2024/05/01 11:40
#pragma once#ifndef LINE_H#define LINE_H#include "Point2.h"class Line{public:Line() {};~Line() {};Line(Point2 A, Point2 B):First(A), Second(B){};Point2 First, Second;};#endif

#pragma once#ifndef POINT2_H#define POINT2_Hclass Point2 {public:Point2() {};~Point2() {};Point2(double x1, double y1):x(x1), y(y1){};void set(double x1, double y1){x = x1;y = y1;}double x, y;Point2 operator - (const Point2 v) const{return Point2(x - v.x, y - v.y);}Point2 operator + (const Point2 v) const{return Point2(x + v.x, y + v.y);}Point2 operator * (const double k) const{return Point2(x * k, y * k);}double dot(const Point2 v) const{return x*v.x + y*v.y;}Point2 Vertical() const{return Point2(y, -x);}};#endif // !POINT2_H

声明
/** 实现二维平面的布尔运算* Union 并集 intersection 交集 Subtract 减*/#pragma once#ifndef BOOLEAN_H#define BOOLEAN_H#include #include #include #include   #include #include "Point2.h"#include "Line.h"using namespace std;class Boolean{public:Boolean();~Boolean();void SetPLane(list A, list B); //输入list数据后 先计算出所有交点 并保存在AList BListvoid BoolIntersection(list &PointInter, list &Num);  //输出交集的坐标 PointInter表示交集坐标 Num的值表示交集面的坐标个数 Num的size表示交集面的个数void Display();private:bool IsInsect(const Point2 A, const Point2 B, const Point2 C,const Point2 D,Point2 &Insect, double &t);  //  求直线AB与线段CD交点 若有交点返回truestruct InPoint{Point2 Point;int IsIn; //1 为交点 0 为端点};list AList, BList;};#endif // !BOOLEAN_H

实现
#include"Boolean.h"Boolean::Boolean(){}Boolean::~Boolean(){}void Boolean::SetPLane(list A, list B){list::iterator ita, itb;vector t; //保存tPoint2 tempP2;double tempt;for (ita = A.begin(); ita != A.end(); ita++){for (itb = B.begin(); itb != B.end(); itb++){if (IsInsect(ita->First, ita->Second, itb->First, itb->Second, tempP2, tempt)){t.push_back(tempt);}}sort(t.begin(), t.end());InPoint tempInp;//tempInp.Point = ita->First;//tempInp.IsIn = 0;//AList.push_back(tempInp);int Nt = 0;int Nt_In = 0;for (int i = 0; i < t.size(); i++){Nt_In++;// 判断交点是出去还是进入 被2整除出 余1进if (t[i] <= 1) Nt++; //统计小于1的个数 用于判断B点是否在内部 被2整除不在 余1在if (t[i] > 0 && t[i] < 1){tempInp.Point = ita->First + (ita->Second - ita->First) * t[i];if(Nt_In % 2 == 0) tempInp.IsIn = 2; // 交点else tempInp.IsIn = 1; // 交点AList.push_back(tempInp);}}tempInp.Point = ita->Second;if(Nt % 2 == 0) tempInp.IsIn = 0;else tempInp.IsIn = 1;AList.push_back(tempInp);t.clear();}for (itb = B.begin(); itb != B.end(); itb++){for (ita = A.begin(); ita != A.end(); ita++){if (IsInsect(itb->First, itb->Second, ita->First, ita->Second, tempP2, tempt)){t.push_back(tempt);}}sort(t.begin(), t.end());InPoint tempInp;int Nt = 0;int Nt_In = 0;for (int i = 0; i < t.size(); i++){Nt_In++;if (t[i] <= 1) Nt++; //统计小于1的个数 用于判断B点是否在内部 被2整除不在 余1在if (t[i] > 0 && t[i] < 1){tempInp.Point = itb->First + (itb->Second - itb->First) * t[i];if (Nt_In % 2 == 0) tempInp.IsIn = 2; // 交点else tempInp.IsIn = 1; // 交点BList.push_back(tempInp);}}tempInp.Point = itb->Second;if (Nt % 2 == 0) tempInp.IsIn = 0;else tempInp.IsIn = 1;BList.push_back(tempInp);t.clear();}}void Boolean::BoolIntersection(list &PointInter, list &Num){list::iterator ita;list::iterator itb;list::iterator ittemp_back;list::iterator itb_back;list::iterator ittemp;int JumpA = 1 ; // 跳转 1表示跳到A  0表示调到Bint State = 0;  // 0表示在遍历 A ita = AList.begin();//先遍历AList 然后遍历BList while(1){if (ita->IsIn == 1){int NPoint = 0;PointInter.push_back(ita->Point);NPoint++;double a = ita->Point.x;double b = ita->Point.y;ittemp_back = ita;ita++;ittemp = ita;if (JumpA == 0) JumpA = 1;else JumpA = 0;while(abs(a - ittemp->Point.x) > 0.001 || abs(b -ittemp->Point.y) > 0.001){if (ittemp->IsIn == 1){PointInter.push_back(ittemp->Point);ittemp->IsIn = 3; // 标记已经pick的点NPoint++;ittemp_back = ittemp;ittemp++;}//endifelse if (ittemp->IsIn == 2)//跳转{PointInter.push_back(ittemp->Point);ittemp->IsIn = 3; // 标记已经pick的点NPoint++;ittemp_back = ittemp;if (JumpA == 0) {ittemp = BList.begin();JumpA = 1;}else{ittemp = AList.begin();JumpA = 0;}while (abs(ittemp->Point.x - ittemp_back->Point.x) > 0.001 || abs(ittemp->Point.y -ittemp_back->Point.y) > 0.001){ittemp++;}ittemp->IsIn = 3; // 标记已经pick的点ittemp++;if (ittemp->IsIn == 0)break; // 交点为一个的情况}//endelseif (JumpA == 0) {if (ittemp == AList.end())ittemp = AList.begin();}else{if (ittemp == BList.end())ittemp = BList.begin();}} //endwhileNum.push_back(NPoint);NPoint = 0; //重新计数}//endifita++;if (State == 0){if (ita == AList.end()){ita = BList.begin();JumpA = 1;State = 1;}}else{if (ita == BList.end())break;}}//endwhile}void Boolean::Display(){list::iterator it;for (it = AList.begin(); it != AList.end(); it++){cout << it->Point.x << " " << it->Point.y << " " << it->IsIn << "\n";}cout << "\n";list::iterator itb;for (itb = BList.begin(); itb != BList.end(); itb++){cout << itb->Point.x << " " << itb->Point.y << " " << itb->IsIn << "\n";}}bool Boolean::IsInsect(const Point2 A, const Point2 B, const Point2 C, const Point2 D, Point2 &Insect, double &t){Point2 b = B - A; //向量bPoint2 d = D - C;Point2 c = C - A;Point2 d_V = d.Vertical(); //d的垂线if (b.dot(d_V) == 0)return false;else{t = c.dot(d_V) / b.dot(d_V);Point2 b_V = b.Vertical();double u = c.dot(b_V) / b.dot(d_V);if (u < 0 || u > 1)return false;else{Insect = A + b * t;return true;}}}

测试程序按b后绘制新的折线绘制两组折线后点u调用Boolean交集运算,将交集绘制成红色
#include#include#include#include#include"Boolean.h"using namespace std;const int ScreenWidth = 640;const int ScreenHeight = 480;int N_Line = -1;unsigned char Key;const int Num = 20;std::list xList[Num];std::list yList[Num];void Init(void){glClearColor(1.0, 1.0, 1.0, 0.0);glColor3f(0.0f, 0.0f, 0.0f);glPointSize(2.0);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluOrtho2D(0.0, (GLdouble)ScreenWidth, 0.0, (GLdouble)ScreenHeight);}void myMouse(int button, int state, int x, int y) //绘制折线{if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN) && (Key == 'b')){//std::cout << "111" << "\n";xList[N_Line].push_back(x);yList[N_Line].push_back(ScreenHeight - y);glClear(GL_COLOR_BUFFER_BIT);std::list::iterator itx;std::list::iterator ity;for (int j = 0; j <= N_Line; j++){glBegin(GL_LINE_LOOP);itx = xList[j].begin();ity = yList[j].begin();for (itx = xList[j].begin(); itx != xList[j].end(); itx++){glVertex2i(*itx, *ity);ity++;}glEnd();}glFlush();}}void Uion(void){list AList;list BList;list::iterator itx;list::iterator ity;itx = xList[0].begin();ity = yList[0].begin();double xA = *itx;double yA = *ity;Point2 A(xA, yA), B;itx++;ity++;for (itx; itx != xList[0].end(); itx++){B.set(*itx, *ity);AList.push_back(Line(A, B));A.set(*itx, *ity);ity++;}B.set(xA, yA);AList.push_back(Line(A, B));itx = xList[1].begin();ity = yList[1].begin();xA = *itx;    yA = *ity;    A.set(xA, yA);itx++;ity++;for (itx; itx != xList[1].end(); itx++){//Point2 A(xA, yA);B.set(*itx, *ity);BList.push_back(Line(A, B));A.set(*itx, *ity);ity++;}B.set(xA, yA);BList.push_back(Line(A, B));list::iterator itL;for (itL = AList.begin(); itL != AList.end(); itL++){cout << itL->First.x << " " << itL->First.y << " " << itL->Second.x << " " << itL->Second.y << "\n";}for (itL = BList.begin(); itL != BList.end(); itL++){cout << itL->First.x << " " << itL->First.y << " " << itL->Second.x << " " << itL->Second.y << "\n";}Boolean bln;bln.SetPLane(AList, BList);bln.Display();list PointInter;list Num;bln.BoolIntersection(PointInter, Num);list::iterator it;list::iterator itN;glColor3f(1.0f, 0.0f, 0.0f);it = PointInter.begin();for (itN = Num.begin(); itN != Num.end(); itN++){glBegin(GL_LINE_LOOP);for (int i = 0; i < *itN; i++){glVertex2d(it->x, it->y);it++;}glEnd();}glFlush();}void myKeyboard(unsigned char theKey, int mouseX, int mouseY){GLint x = mouseX;GLint y = ScreenHeight - mouseY;//Key = theKey;switch (theKey){case 'b':Key = theKey;N_Line++;break;case 'u':Uion();break;default:break;}}void myDisplay(void){}void main(int argc, char * argv[]){glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 150);glutInitWindowSize(ScreenWidth, ScreenHeight);glutCreateWindow("First_GL!");Init();glutDisplayFunc(myDisplay);glutKeyboardFunc(myKeyboard);glutMouseFunc(myMouse);glutMainLoop();}

运行结果



0 0
原创粉丝点击