实验四 线段裁剪算法
实验类型:设计型 实验学时: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;
}
结果即为实验要求!
不在展示。