实验:直线段的裁剪
姓名:龙泽学号:20141090068 指导教师:吴昊
实验内容:采用Liang-Barsky算法对直线段进行裁剪。
实验设计:本次实验采用的是Liang-Barsky算法,根据这个算法需先定义直线段的起点坐标(x1,y1),终点坐标(x2,y2),以及裁剪框(矩形)的左边界(wxl),右边界(wxr),上边界(wyt),下边界(wyb),如void Line_Clipping(float x1, float y1, float x2, float y2,float Wxl,float Wxr,float Wyt,float Wyb),再结合鼠标mouse函数,实现点击鼠标左键显示矩形框和待裁剪的直线段,点击鼠标右键进行裁剪并显示裁剪过后的直线段,最终显示出来。
由于在Line_Clipping函数下用到了line函数,所以我在上面定义了个line 函数来绘制直线段(绘制直线段所采用的算法为Bresenham算法)。
程序代码:
#include <windows.h>
#include <GL/glut.h>
//初始化OpenGL场景
void myinit (void)
{
glClearColor (1, 1,1, 0); //将背景置成白色
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0,500,0,500); //设置投影变换,使用正交投影
}
void setPixel(int x, int y)//在指定位置(x,y)绘制点图元
{
glBegin (GL_POINTS);
glVertex2i(x,y);//绘制点的坐标
glEnd ( );
}
// 绘制直线的方法
void line (int x1,int y1,int x2,int y2)//输入线段的两个端点坐标和画线颜色
{
int x,y,dx,dy,s1,s2,p,temp,interchange,i;
x=x1;
y=y1;//设置象素坐标初值
dx=abs(x2-x1);
dy=abs(y2-y1);//分别计算之间的差值
if(x2>x1)
s1=1;
else
s1=-1;
if(y2>y1)
s2=1;
else
s2=-1; //判断起点和终点的位置,以确定是该加一个单位还是该减一个单位
if(dy>dx)//y方向增长快,将总步数设为y2-y1,每一步的y值为:y=y+1
{
temp=dx;
dx=dy;
dy=temp;
interchange=1;
}
else
interchange=0;//x方向增长快,将总步数设为x2-x1,每一步的x值为:x=x+1
p=2*dy-dx; //设置初始误差判别值
for(i=1;i<=dx;i++)
{
setPixel(x,y);
if(p>=0)
{
if(interchange==0)
y=y+s2;
else
x=x+1;
p=p-2*dx;
}
if(interchange==0)
x=x+s1;
else
y=y+s2;
p=p+2*dy;
}
}
//Liang-Barsky算法
int Clip_Top(float p,float q,float &umax,float &umin)
{ float r=0.0;
if(p<0.0) //线段从裁剪窗口外部延伸到内部,取最大值r并更新umax
{ r=q/p;
if (r>umin) return 0; //umin>umax的情况,弃之
else if (r>umax) umax=r;
}
else if(p>0.0) //线段从裁剪窗口内部延伸到外部,取最小值r并更新umin
{ r=q/p;
if (r<umax) return 0; //umin>umax的情况,弃之
else if(r<umin) umin=r;
}
else //p=0时,线段平行于裁剪窗口
if(q<0.0) return 0;
return 1;
}
void Line_Clipping(float x1, float y1, float x2, float y2,float Wxl,float Wxr,float Wyt,float Wyb)//定义线段的坐标和矩形的四条边界
{
float dx=x2-x1,dy=y2-y1,umax=0.0,umin=1.0;
//比较左、右边界,获得最大的umax
if (Clip_Top(-dx,x1-Wxl,umax,umin)) //左边界
if (Clip_Top(dx,Wxr-x1, umax,umin))//右边界
//比较下、上边界,获得最小的umin
if (Clip_Top(-dy,y1-Wyb, umax,umin))//下边界
if (Clip_Top(dy,Wyt-y1, umax,umin))//上边界
line((int)(x1+umax*dx),(int)(y1+umax*dy),(int)(x1+umin*dx),
(int)(y1+umin*dy));
}
void display(void)//需要点击鼠标显示,所以这里的display函数下为空
{
}
//鼠标响应函数,控制当鼠标接收到不同的用户操作时将要执行的后续命令。
void mouse(int button, int state, int x, int y)
{
Float x1=70,y1=480,x2=480,y2=80, Wxl=100,Wxr=400,Wyt=400,Wyb=200;//给定直线和矩形的各项参数数值
switch (button)
{
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)//如果按下鼠标左键,则显示矩形和待裁剪的直线段
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除缓存
glColor3f(0,0,0); //给定矩形线条的颜色
line(Wxl,Wyt,Wxr,Wyt); //定义矩形的上边界
line(Wxl,Wyb,Wxr,Wyb); //定义矩形的下边界
line(Wxr,Wyb,Wxr,Wyt); //定义矩形的右边界
line(Wxl,Wyb,Wxl,Wyt); //定义矩形的左边界
glColor3f(0,0,255); //给定直线的颜色
line (x1,y1,x2,y2); //给定直线的起点坐标和终点坐标
glFlush (); //绘图结束
break;
case GLUT_MIDDLE_BUTTON:
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN)//如果按下鼠标右键,则显示裁剪过后的直线段
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除缓存
glColor3f(0,0,0); //给定剪裁后的矩形的颜色
line(Wxl,Wyt,Wxr,Wyt);
line(Wxl,Wyb,Wxr,Wyb);
line(Wxr,Wyb,Wxr,Wyt);
line(Wxl,Wyb,Wxl,Wyt); //分别给定矩形的四条边的坐标 glColor3f(255,0,0); //给定剪裁后的直线的颜色
Line_Clipping(x1,y1,x2,y2,Wxl,Wxr,Wyt,Wyb); //调用上面的Line_Clipping函数进行裁剪
glFlush (); //绘图结束
default:
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv); //初始化glut
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); //初始化显示模式,采用单缓存,RGB彩色系统
glutInitWindowSize (500, 500); //初始化窗口大小
glutInitWindowPosition (100, 100); // 初始化窗口位置
glutCreateWindow ("直线的裁剪"); //创建窗口
myinit (); //自定义初始化
glutDisplayFunc(display); //注册显示函数
glutMouseFunc(mouse);
glutMainLoop(); //进入OpenGL的主循环。
开始工作
return 0;
}
实验结果:
经过大量的调试以后,运行的结果如下:
点击鼠标左键如图:
点击鼠标右键如图:。