梁友棟-Barskey裁剪算法
直接上代碼吧:
// ConsoleApplication2.cpp: 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include<gl/GLUT.H>
#include<cmath>
#include<iostream>
#include"node.h"
using namespace std;
void Initial(void)//初始化函數
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//白色背景,前3個是RGB,最後是Alpha值,用來控制透明,1.0表示完全不透明
glMatrixMode(GL_MODELVIEW);//OpenGL按照三維方式來處理圖像,所以需要一個投影變換將三維圖形投影到顯示器的二維空間中
glLoadIdentity();
gluOrtho2D(0.0, 400, 0.0, 400.0);//指定使用正投影將一個x座標在0~200,y座標0~150範圍內的矩形座標區域投影到顯示器窗口
}
bool ClipT(float p, float q, float *u1, float *u2)
{
float r;
if (p < 0)
{
r = q / p;
if (r > *u2)
return false;
if (r > *u1)
* u1 = r;
}
else if (p > 0)
{
r = q / p;
if (r < *u1)
return false;
if (r < *u2)
*u2 = r;
}
else
return (q >= 0);
return true;
}
void LB_LineClip(float x1, float y1, float x2, float y2, float XL, float XR, float YB, float YT)
{
float dx, dy, u1, u2;
u1 = 0, u2 = 1;
dx = x2 - x1;
dy = y2 - y1;
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0);
glViewport(0, 0, 400, 400);
glBegin(GL_LINES);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glEnd();
//glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色
//glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glViewport(0, 0, 400, 400);
glBegin(GL_LINES);
glVertex2f(XL,YB);
glVertex2f(XL,YT);
glVertex2f(XL,YT);
glVertex2f(XR,YT);
glVertex2f(XR, YT);
glVertex2f(XR, YB);
glVertex2f(XL, YB);
glVertex2f(XR, YB);
if (ClipT(-dx, x1 - XL, &u1, &u2))
if (ClipT(dx, XR - x1, &u1, &u2))
if (ClipT(-dy, y1 - YB, &u1, &u2))
if (ClipT(dy, YT - y1, &u1, &u2))
{
glVertex2f(x1 + u1 * dx, y1 + u1 * dy);
glVertex2f(x1 + u2 * dx, y1 + u2 * dy);
}
glEnd();
glFlush();
}
node* Sutherland(node *m1, node *m2, side ClipBoundary, int Inlength, int &Outlength)
{
node S, P, ip;
int j;
Outlength = 0;
S = m1[Inlength - 1];
for (j = 0; j < Inlength; j++)
{
P = m1[j];
if (Inside(P, ClipBoundary))
{
if (Inside(S, ClipBoundary))
Output(P, Outlength, m2);
else
{
Intersect(S, P, ClipBoundary, ip);
Output(ip, Outlength, m2);
Output(P, Outlength, m2);
}
}
else if (Inside(S, ClipBoundary))
{
Intersect(S, P, ClipBoundary, ip);
Output(ip, Outlength, m2);
}
S = P;
}
return m2;
}
void drawFront(node m1[],node m2[],int length1,int length2)
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 0.0);
glViewport(0, 0, 400, 400);
glBegin(GL_LINES);
for (int i = 0; i < length1 - 1; i++)
{
glVertex2d(m1[i].x, m1[i].y);
glVertex2d(m1[i+1].x, m1[i+1].y);
}
glVertex2d(m1[length1-1].x, m1[length1-1].y);
glVertex2d(m1[0].x, m1[0].y);
glEnd();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINES);
for (int i = 0; i < length2 - 1; i++)
{
glVertex2d(m2[i].x, m2[i].y);
glVertex2d(m2[i + 1].x, m2[i + 1].y);
}
glVertex2d(m2[length2 - 1].x, m2[length2 - 1].y);
glVertex2d(m2[0].x, m2[0].y);
glEnd();
glFlush();
}
void drawBack()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 0.0);
glViewport(0, 0, 400, 400);
glBegin(GL_LINES);
node *m1=new node[100],*m2=new node[100],*r1=new node[100],*r2=new node[100],*r3=new node[100],*r4=new node[100];
node n1(100, 100), n2(100, 200), n3(200, 200), n4(200, 100), n5(50, 150), n6(150, 220),n7(150,150);
node ploy[3] = { n5,n6,n7};
side s1(n2, n1), s2(n1, n4), s3(n4, n3), s4(n3, n2);
m1 = &ploy[0];
int nodeNum = 0;
r1=Sutherland(m1,m2,s1,3,nodeNum);//用第一條邊裁剪剩下的圖形
m2 = new node();
r2 = Sutherland(r1, m2, s2, nodeNum, nodeNum);//用第二條邊裁剪剩下的圖形
m2 = new node();
r3 = Sutherland(r2, m2, s3, nodeNum, nodeNum); //用第三條邊裁剪剩下的
m2 = new node();
r4 = Sutherland(r3, m2, s4, nodeNum, nodeNum);//最後一條邊裁剪後剩下的
//r1 = r2 = r3 = m1=r4=NULL;
//delete r1, r2, r3, m1,r4;
for (int i = 0; i < nodeNum - 1; i++)//畫出被裁減後的圖形
{
glVertex2d(m2[i].x, m2[i].y);
glVertex2d(m2[i + 1].x, m2[i + 1].y);
}
glVertex2d(m2[nodeNum - 1].x, m2[nodeNum - 1].y);
glVertex2d(m2[0].x, m2[0].y);
//glVertex2d(100, 200);
//glVertex2d(200, 300);
//cout << m2[0].x << " " << m2[0].y;
glEnd();
glFlush();
}
node *nn = new node[100];
int nodeNumber = 0;
void draw()
{
node n1(100, 100), n2(100, 200), n3(200, 200), n4(200, 100), n5(50, 150), n6(150, 220), n7(150, 150);
node ploy[3] = { n5,n6,n7 };
node ploy2[4] = { n1,n2,n3,n4 };
drawFront(ploy,ploy2,3,4);
/*result=Bezier(nodeNumber,&nn[0]);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 0.0);
glViewport(0, 0, 400, 400);
glBegin(GL_POINTS);
for (int i = 0; i < 100; i++)
{
glVertex2f(result[i].x, result[i].y);
//cout <<result[i].x<<" "<<result[i].y<<"\n";
}
//result = NULL;
//delete result;
glEnd();
glColor3f(0.0, 1.0, 1.0);
glViewport(0, 0, 400, 400);
glBegin(GL_LINES);
for (int i = 0; i < nodeNumber-1; i++)
{
glVertex2f(nn[i].x, nn[i].y);
glVertex2f(nn[i+1].x, nn[i+1].y);
}
glEnd();
glFlush();*/
}
//鼠標響應函數
void mouseClick(int btn, int state, int x, int y)
{
if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
node temp(x, 400-y);
nn[nodeNumber] = temp;
nodeNumber++;
glColor3f(0.0, 1.0, 1.0);
glViewport(0, 0, 400, 400);
glBegin(GL_POINTS);
glVertex2d(x,400-y);
glEnd();
glFlush();
}
if (btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
node *result = new node[1000];
//drawFront(ploy,ploy2,3,4);
result = Bezier(nodeNumber, nn);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色
//glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 0.0);
glViewport(0, 0, 400, 400);
glBegin(GL_POINTS);
for (int i = 0; i < 1000; i++)
{
glVertex2f(result[i].x, result[i].y);
//cout <<result[i].x<<" "<<result[i].y<<"\n";
}
//result = NULL;
//delete result;
glEnd();
glColor3f(0.0, 1.0, 1.0);
glViewport(0, 0, 400, 400);
glBegin(GL_LINES);
for (int i = 0; i < nodeNumber - 1; i++)
{
glVertex2f(nn[i].x, nn[i].y);
glVertex2f(nn[i + 1].x, nn[i + 1].y);
}
//result = NULL;
nn = NULL;
nn = new node[100];
nodeNumber = 0;
glEnd();
glFlush();
}
}
//鼠標移動函數
void display()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色
//glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 0.0);
glViewport(0, 0, 400, 400);
LB_LineClip(50, 150, 200, 250, 100, 300, 20, 200);
}
int main(int argc, char * argv[])//這是使用glut庫函數進行窗口管理
{
glutInit(&argc, argv);//使用glut庫需要進行初始化
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);//設定窗口顯示模式,顏色模型和緩存,這裏是RGB顏色模型和單緩存
glutInitWindowPosition(100, 100);//設定窗口的初始位置,屏幕左上角爲原點,單位爲像素
glutInitWindowSize(400, 400);//設定窗口的大小
glutCreateWindow("裁剪線段圖形");//創建一個窗口,參數是窗口標題名
Initial();
glutDisplayFunc(&display);//將myDisplay指定爲當前窗口的顯示內容函數*/
glutCreateWindow("初始圖形");//創建一個窗口,參數是窗口標題名
Initial();
glutDisplayFunc(&draw);//將myDisplay指定爲當前窗口的顯示內容函數*/
glutCreateWindow("裁剪後的圖");//創建一個窗口,參數是窗口標題名
Initial();
glutDisplayFunc(&drawBack);//將myDisplay指定爲當前窗口的顯示內容函數
glutMainLoop();//使窗口框架運行起來,使顯示回調函數開始工作
return 0;
}
加個有關函數的頭文件:
#pragma once
#pragma once
struct node//點結構
{
double x;
double y;
node()
{
x = 0.0;
y = 0.0;
}
node(double xx, double yy)
{
x = xx;
y = yy;
}
/*node & operator=(const node& a)
{
node m;
m.x = a.x;
m.y = a.y;
return m;
}*/
};
struct side//邊結構
{
node a;
node b;
side(node aa, node bb)
{
a.x = aa.x;
a.y = aa.y;
b.y = bb.y;
b.x = bb.x;
}
side(int n)
{
a.x = 0;
a.y = 0;
b.x = 0;
b.y = 0;
}
side()
{
a.x = 0;
a.y = 0;
b.x = 0;
b.y = 0;
}
};
double sideYmax(side mside)
{
if (mside.a.y < mside.b.y)
return mside.b.y;
else
return mside.a.y;
}
bool Inside(node &TestPt, side ClipBoundray)
{
if (ClipBoundray.b.x > ClipBoundray.a.x)//裁剪邊爲窗口下邊
{
if (TestPt.y >= ClipBoundray.a.y)
return TRUE;
}
else if (ClipBoundray.b.x < ClipBoundray.a.x)//裁剪邊爲窗口下邊
{
if (TestPt.y <= ClipBoundray.a.y)
return TRUE;
}
else if (ClipBoundray.b.y > ClipBoundray.a.y)
{
if (TestPt.x <= ClipBoundray.a.x)
return TRUE;
}
else if (ClipBoundray.b.y < ClipBoundray.a.y)
{
if (TestPt.x >= ClipBoundray.a.x)
return TRUE;
}
return FALSE;
}
void Intersect(node &S,node &P,side ClipBoundary,node &IntersectPt)//求兩條邊的交點
{
if (ClipBoundary.a.y == ClipBoundary.b.y)
{
IntersectPt.y = ClipBoundary.a.y;
IntersectPt.x = S.x + (ClipBoundary.a.y - S.y)*(P.x - S.x) / (P.y - S.y);
}
else
{
IntersectPt.x = ClipBoundary.a.x;
IntersectPt.y = S.y + (ClipBoundary.a.x - S.x)*(P.y - S.y) / (P.x - S.x);
}
}
void Output(node P, int &Outlength, node *m2)
{
m2[Outlength] = P;
Outlength++;
}
node *Bnode(float t, int nodeNumber,node *n)//求出點集第幾次後的在t分段上的點
{
node *temp=new node[nodeNumber-1];
for (int i = 0; i < nodeNumber-1; i++)
{
temp[i].x = (1 - t)*n[i].x + t * n[i + 1].x;
temp[i].y = (1 - t)*n[i].y + t * n[i + 1].y;
}
if (nodeNumber == 2)
return temp;
else
return Bnode(t,nodeNumber-1,temp);
}
node * Bezier(int nodeNumber,node * n)
{
float t = 0.0; int i = 0;
node *result = new node[1000];
for (t; t < 1; t = t + 0.001)
{
result[i].x = Bnode(t, nodeNumber, n)[0].x;
result[i].y = Bnode(t, nodeNumber, n)[0].y;
//result[i] = Bnode(t, nodeNumber, n)[0];
i++;
//cout << result[i].x << " " << result[i].y<<"\n";
}
return result;
}