#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_H
class 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 BList
void 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交點 若有交點返回true
struct 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; //保存t
Point2 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表示調到B
int 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++;
}//endif
else 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; // 交點爲一個的情況
}//endelse
if (JumpA == 0) {
if (ittemp == AList.end())
ittemp = AList.begin();
}
else
{
if (ittemp == BList.end())
ittemp = BList.begin();
}
} //endwhile
Num.push_back(NPoint);
NPoint = 0; //重新計數
}//endif
ita++;
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; //向量b
Point2 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();
}
運行結果