圖形學實驗四線段裁剪演算法
實驗四 線段裁剪演算法
實驗型別:設計型 實驗學時:2實驗要求:必修
一、實驗目的
瞭解二維圖形裁剪的原理(點的裁剪、直線的裁剪、多邊形的裁剪),利用VC+OpenGL實現直線的裁剪演算法。
二、實驗內容
1 理解直線裁剪的原理(編碼裁剪演算法、樑友棟演算法)
2 利用VC+OpenGL實現直線的編碼裁剪演算法,在螢幕上用一個封閉矩形裁剪任意一條直線。
3 互動實現直線段的裁剪。
三、實驗原理
編碼裁剪演算法中,為了快速判斷一條直線段與矩形視窗的位置關係,採用瞭如圖3所示的空間劃分和編碼方案。
圖3 直線裁剪分割槽編碼圖 基礎: |
升級1 |
按 c 裁剪,並且按 r 要恢復到原形狀
裁剪一條線段時,先求出兩端點所在的區號code1和code2,若code1 = 0且code2 = 0,則說明線段的兩個端點均在視窗內,那麼整條線段必在視窗內,應取之;若code1和code2經按位與運算的結果不為0,則說明兩個端點同在視窗的上方、下方、左方或右方。這種情況下,對線段的處理是棄之。如果上述兩種條件都不成立,則按第三種情況處理。求出線段與視窗某邊的交點,在交點處把線段一分為二,其中必有一段完全在視窗外,可棄之,對另一段則重複上述處理。
四、實驗示範程式碼(略)
五、實驗步驟
1 在Windows xp/win7操作環境下,啟動VC;
2 建立W32 Console Application 的應用工程;
3 建立源程式編輯環境,進行編輯源程式。
4 除錯執行程式,完成實驗。
六、實驗結果處理
演示結果並儲存相關檔案。
七、實驗注意事項
注意程式設計環境的配置,即在Windows環境下,OpenGL擴充套件庫相關檔案的配置,把標頭檔案“GL.H”、庫檔案“OPENGL32.LIB”和動態連結庫“OPENGL32.DLL”配置到相應的目錄下。
八、預習與思考題
預習:閱讀課本相關內容,仔細閱讀示範程式碼。
思考題:如何實現橫平豎直線段的裁剪。
九、實驗報告要求
1、實驗報告中應包括相關操作步驟和程式程式碼和執行效果截圖。
2.書寫實驗報告時要結構合理,層次分明,在分析描述的時候,需要注意語言的流暢。
基礎程式碼:
#include<stdio.h>
#include<stdlib.h>
#include<GL/glut.h>
#define LEFT_EDGE 1
#define RIGHT_EDGE 2
#define BOTTOM_EDGE 4
#define TOP_EDGE 8
int x0,y0,x1,y1;
void LineGL(int x0,int y0,int x1,int y1)
{
glBegin(GL_LINES);
glColor3f(1.0,0.0,0.0); glVertex2f(x0,y0);
glColor3f(0.0,1.0,0.0); glVertex2f(x1,y1);
glEnd();
}
struct Rectangle
{
float xmin,xmax,ymin,ymax;
};
Rectangle rect;
int CompCode(int x,int y,Rectangle rect)
{
int code = 0x00;
if(y < rect.ymin)
code = code|4;
if(y > rect.ymax)
code = code|8;
if(x >rect.xmax)
code = code|2;
if(x < rect.xmin)
code = code|1;
return code;
}
int cohensutherlandlineclip(Rectangle rect,int &x0,int &y0,int &x1,int &y1)//此處&不能刪除,否則導致錯誤
{
int accept,done;
float x,y;
done = 0;
int code0,code1,codeout;
code0 = CompCode(x0,y0,rect);
code1 = CompCode(x1,y1,rect);
do{
if(!(code0 | code1))
{
accept =1;
done=1;
}
else if(code0 &code1)
done =1;
else {
if(code0!=0)
codeout = code0;
else
codeout = code1;
if(codeout&LEFT_EDGE){
y=y0+(y1-y0)*(rect.xmin-x0)/(x1-x0);
x=(float)rect.xmin;
}
else if(codeout&RIGHT_EDGE){
y=y0+(y1-y0)*(rect.xmax-x0)/(x1-x0);
x=(float)rect.xmax;
}
else if(codeout&BOTTOM_EDGE){
x=x0+(x1-x0)*(rect.ymin-y0)/(y1-y0);
y=(float)rect.ymin;}
else if(codeout&TOP_EDGE){
x=x0+(x1-x0)*(rect.ymax-y0)/(y1-y0);
y=(float)rect.ymax;
}
if(codeout == code0 )
{
x0=x;
y0=y;
code0 = CompCode(x0,y0,rect);
}
else
{
x1 = x;
y1=y;
code1 = CompCode(x1,y1,rect);
}
}
}while(!done);
if(accept)
LineGL(x0,y0,x1,y1);
return accept;
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
glRectf(rect.xmin,rect.ymin,rect.xmax,rect.ymax);
LineGL(x0,y0,x1,y1);
glFlush();
}
void Init()
{
glClearColor(0.0,0.0,0.0,0.0);
glShadeModel(GL_FLAT);
rect.xmin=100;
rect.xmax=300;
rect.ymin=100;
rect.ymax=300;
x0=450,y0=0,x1=0,y1=450;
printf("Press key 'c' to Clip!\n");
printf("Press key 'r' to Restore!\n");
}
void Reshape(int w,int h)
{
glViewport(0,0,(GLsizei)w, (GLsizei)h );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h );
}
void keyboard(unsigned char key,int x,int y)
{
switch (key)
{
case 'c':
cohensutherlandlineclip(rect, x0,y0,x1,y1);
glutPostRedisplay();
break;
case 'r':
Init();
glutPostRedisplay();
break;
case 'x':
exit(0);
break;
default:
break;
}
}
int main(int argc,char *argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(640,480);
glutCreateWindow("Hello world!");
Init();
glutDisplayFunc(myDisplay);
glutReshapeFunc(Reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<GL/glut.h>
#define LEFT_EDGE 1
#define RIGHT_EDGE 2
#define BOTTOM_EDGE 4
#define TOP_EDGE 8
int x0,y0,x1,y1,x2,y2,x3,y3,x4,y4,x5,y5;
void LineGL(int x0,int y0,int x1,int y1)
{
glBegin(GL_LINES);
glVertex2f(x0,y0);
glVertex2f(x1,y1);
glEnd();
}
struct Rectangle
{
float xmin,xmax,ymin,ymax;
};
Rectangle rect;
int CompCode(int x,int y,Rectangle rect)
{
int code = 0x00;
if(y < rect.ymin)
code = code|4;
if(y > rect.ymax)
code = code|8;
if(x >rect.xmax)
code = code|2;
if(x < rect.xmin)
code = code|1;
return code;
}
int cohensutherlandlineclip(Rectangle rect,int &x0,int &y0,int &x1,int &y1)//此處&不能刪除,否則導致錯誤
{
int accept,done;
float x,y;
done = 0;
int code0,code1,codeout;
code0 = CompCode(x0,y0,rect);
code1 = CompCode(x1,y1,rect);
do{
if(!(code0 | code1))
{
accept =1;
done=1;
}
else if(code0 &code1)
done =1;
else {
if(code0!=0)
codeout = code0;
else
codeout = code1;
if(codeout&LEFT_EDGE){
y=y0+(y1-y0)*(rect.xmin-x0)/(x1-x0);
x=(float)rect.xmin;
}
else if(codeout&RIGHT_EDGE){
y=y0+(y1-y0)*(rect.xmax-x0)/(x1-x0);
x=(float)rect.xmax;
}
else if(codeout&BOTTOM_EDGE){
x=x0+(x1-x0)*(rect.ymin-y0)/(y1-y0);
y=(float)rect.ymin;}
else if(codeout&TOP_EDGE){
x=x0+(x1-x0)*(rect.ymax-y0)/(y1-y0);
y=(float)rect.ymax;
}
if(codeout == code0 )
{
x0=x;
y0=y;
code0 = CompCode(x0,y0,rect);
}
else
{
x1 = x;
y1=y;
code1 = CompCode(x1,y1,rect);
}
}
}while(!done);
if(accept)
LineGL(x0,y0,x1,y1);
return accept;
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
glBegin(GL_LINE_LOOP);
glVertex2f(rect.xmin,rect.ymax);
glVertex2f(rect.xmax,rect.ymax);
glVertex2f(rect.xmax,rect.ymin);
glVertex2f(rect.xmin,rect.ymin);
glEnd();
glColor3f(0.0,1.0,0.0);LineGL(x0,y0,x1,y1);
glColor3f(1.0,0.0,1.0);LineGL(x2,y2,x3,y3);
glColor3f(1.0,1.0,1.0);LineGL(x4,y4,x5,y5);
glFlush();
}
void Init()
{
glClearColor(0.0,0.0,0.0,0.0);
glShadeModel(GL_FLAT);
rect.xmin=100;
rect.xmax=300;
rect.ymin=100;
rect.ymax=300;
x0=450,y0=0,x1=0,y1=450,x2=0,y2=200,x3=450,y3=200,x4=200,y4=400,x5=200,y5=10;
printf("Press key 'c' to Clip!\n");
printf("Press key 'r' to Restore!\n");
}
void Reshape(int w,int h)
{
glViewport(0,0,(GLsizei)w, (GLsizei)h );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h );
}
void keyboard(unsigned char key,int x,int y)
{
switch (key)
{
case 'c':
cohensutherlandlineclip(rect, x0,y0,x1,y1);
cohensutherlandlineclip(rect, x2,y2,x3,y3);
cohensutherlandlineclip(rect, x4,y4,x5,y5);
glutPostRedisplay();
break;
case 'r':
Init();
glutPostRedisplay();
break;
case 'x':
exit(0);
break;
default:
break;
}
}
int main(int argc,char *argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(640,480);
glutCreateWindow("Hello world!");
Init();
glutDisplayFunc(myDisplay);
glutReshapeFunc(Reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
結果即為實驗要求!
不在展示。