您的位置:首页 > 运维架构

基于Opengl的画直线—BresenhamLine算法

2016-12-15 20:21 387 查看
画直线基本思想:

假设直线的斜率0<k<1,直线在第一象限,Bresenham算法的过程如下:

1.画起点(x0, y0).

2.准备画下一个点,X坐标加1,判断如果达到终点,则完成。否则找下一个点,由图可知要画的点要么为当前点的右邻接点,要么是当前点的右上邻接点。

  2.1.如果线段ax+by+c=0与x=x1+1的交点y坐标大于(y+*y+1))/2则选右上那个点

  2.2.否则选右下那个点。

3.画点

4.跳回第2步

5.结束



具体的思路网上很多更详细的解释,在这里我主要提供的是基于鼠标操作的画直线程序:

详细可以参考:http://www.cnblogs.com/gamesky/archive/2012/08/21/2648623.html

 

代码如下:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<gl\glut.h>

using namespace std;
int m0,m1,n0,n1;//声明全局变量,起始坐标和终止坐标
int winwidth=1024,winheight=720;//窗口长宽
void DrawLine();
void MidpointLine(int,int,int,int);
void BresenhamLine(int ,int,int,int);
void DrawLine(){
// MidpointLine(m0,n0,m1,n1);//中心划线法
BresenhamLine(m0,n0,m1,n1);//BresenhamLine算法

}
/*中心画线法*/
void MidpointLine (int x0,int y0,int x1, int y1)
{
// glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容
int a, b, d1, d2, d, x, y;
a=y0-y1, b=x1-x0, d=2*a+b;
d1=2*a, d2=2* (a+b);
x=x0, y=y0;
glBegin(GL_POINTS);
glVertex2i(x, y);
while (x<x1)
{
if (d<0)
{
x++, y++, d+=d2;
}
else
{
x++, d+=d1;
}
glVertex2i (x, y);
}
glEnd();
glFlush();
}

//数据交换
void swap(GLint& a,GLint& b){GLint t=a;a=b;b=t;}

//在屏幕上画一个点
void setPixel(GLint x,GLint y)
{
glBegin(GL_POINTS);
glVertex2i(x,y);
glEnd();
}

/*BresenhamLine算法*/
void BresenhamLine(GLint x1,GLint y1,GLint x2,GLint y2)
{
glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容

if(x2<x1)
{
swap(x2,x1);
swap(y2,y1);
}
//画第一个点
int x,y;
x=x1;
y=y1;
setPixel(x,y);
//首先处理直线平行坐标轴
if(y1==y2)
{
//平行x轴
while(x<x2)
{
x++;
setPixel(x,y);
}
return ;
}
if(x1==x2)
{
//平行y轴
while (y<y2)
{
y++;
setPixel(x,y);
}
return ;
}
int dx=x2-x1,dy=y2-y1;
int p;
int twoDy=2*dy,twoMinusDx=2*(dy-dx),twoDx=2*dx,twoMinusDy=2*(dx-dy);
int twoSum=2*(dy+dx);
double k=(double)dy / (double)dx;

//0<k<1的情况
if(k<1.0&&k>0.0)
{
p=2*dy-dx;
while(x<x2)
{
x++;
if(p<0)
p+=twoDy;
else
{
y++;
p+=twoMinusDx;
}
setPixel(x,y);
}
}
//k>=1的情况
if(k>=1.0)
{
p=dy;
while(y<y2)
{
y++;
if(p<0)
p+=twoDx;
else
{
x++;
p+=twoMinusDy;
}
setPixel(x,y);
}
}
//0>k>-1的情况
if(k>-1&&k<0)
{
p=2*dy+dx;
while(x<x2)
{
x++;
if(p>=0)
p+=twoDy;
else
{
y--;
p+=twoSum;
}
setPixel(x,y);
}
}
//k<-1的情况
if(k<=-1)
{
p=2*dx-dy;
while(y>y2)
{
y--;
if(p>=0)
p-=twoDx;
else
{
x++;
p-=twoSum;
}
setPixel(x,y);
}
}
}
//鼠标拖动
void dragmouse(int x,int y){
m1=x;
n1=y;
printf("%d %d %d %d\n",m0,n0,m1,n1);//把两个坐标打印出来
DrawLine();//画线
glFlush();

}

//鼠标监听,画点
void mymouse(int button,int state,int x,int y){
if(button==GLUT_LEFT_BUTTON && state==GLUT_UP){
m1=x;
n1=y;
printf("%d %d %d %d\n",m0,n0,m1,n1);//把两个坐标打印出来
DrawLine();//画线
glFlush();

}
if(button==GLUT_LEFT_BUTTON && state==GLUT_DOWN){
m0=x;
n0=y;
}

}

void init(){
glClearColor(1,1,1,1);//设置绘制窗口颜色为白色
glClear(GL_COLOR_BUFFER_BIT);//清除窗口内容
glPointSize(5.0f);//设置点的大小
/*设置为投影类型模式和其他观察参数*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,winwidth,winheight,0);
glColor3f(0,1,0);//设置画点的颜色
}

int main(int argc,char** argv){
glutInit(&argc,argv);//初始化
// scanf("%d%d",&m0,&n0);
// m1=m0,n1=n0;//让起始点与目标点重合

glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//设置绘制模式
glutInitWindowPosition(500,300);//设置窗口出现的位置
glutInitWindowSize(winwidth,winheight);//设置窗口大小
glutCreateWindow("画直线");//创建窗口
init();

glutDisplayFunc(DrawLine);//绘制回调函数,glut机制,它觉得需要重新绘制的时候就会执行
glutMouseFunc(mymouse);//鼠标监听回调函数
glutMotionFunc(dragmouse);//鼠标拖动
glutMainLoop();

}


运行结果:



命令窗口的数字分别是x1,y1,x2,y2坐标。

 

鼠标移动的每一帧,我都读取它的坐标,然后重新绘制直线,顺便把之前绘制过的直线删除,最后的效果就是实现了画图上的直线功能。

 

在下一章我会提供画圆的鼠标操作的程序与思路。

 

(上述代码中,有一部分中心画线法的代码,这部分代码只在斜率为0<k<1中适用)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opengl 函数 图形学