美文网首页
OpenGL:直线扫描转换

OpenGL:直线扫描转换

作者: MachinePlay | 来源:发表于2019-06-07 19:03 被阅读0次

直线扫描转换

在显示器上用最逼近直线的像素点来表示直线

1.DDA画线法

思想:
即数值微分法,Digitical Differential Analyzer
x_{i+1}=x_{i}+1\\y_{i+1}=y_{i}+k
实现:
plot(x,int(y))

#include <gl/glut.h>
#include <stdio.h>
#include <math.h>
int xs,ys,xe,ye;
//x0和y0为起始坐标,x1和y1为终止坐标

void DDALine(int x0, int y0, int x1, int y1){
int dy=y1-y0;
int dx=x1-x0;
float k=dy[表情];
int y=y0;
if(k<1){
    for (int x=x0;x<=x0;x++){
    glVertex2i(x,int(y+0.5));
    y+=k;
    }

}
else{
    int x=x0;
    for (;y<=y1;y++){
        glVertex2i(int(x+.5),y);
        x+=1/k;
    }
}
}



void lineSegment(){
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0,0.0,0.0);
    glBegin(GL_POINTS);
    DDALine(xs,ys,xe,ye);
    glEnd();
    glFlush();
}

void main(int argc, char *argv[]){
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    printf("输出线段起始和终止坐标(范围为0-500, 0-500):");
    scanf("%d,%d,%d,%d",&xs,&ys,&xe,&ye);
    glutInitWindowPosition(50,100);
    glutInitWindowSize(500,500);
    glutCreateWindow("中点画线算法");
    glClearColor(1.0,1.0,1.0,0.0);
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(0.0,500.0,0.0,500.0);
    glutDisplayFunc(lineSegment);
    glutMainLoop();
}
  • 采用微分思想
  • 计算y使用浮点数、除法
  • 迭代算法
  • |k|>1将导致隔行显示,故|k|>1时采用y=y+1,x=x+1/k

2.中点画线法

思想:
|K|<1时,
y=y+1,d<0\\ y=y,d>=0
d=F(x+1,\frac{y_{i}+y_{i+1}}{2})
其中d又满足迭代(带入直线标准式推得)
d>=0,d=d+a\\d<0,d=d+a+b
实现:

    1. a=y_0-y_1,b=x_1-x_0,c=x_0*y_1-x_1*y_0,d=2*a+b, x=x0,y=y0, d1=2*a, d2=2*(a+b)
    1. plot(x,y)
  • 3.x=x+1,y=y+1,d=d+d2,d<0 \\x=x+1,y=y,d=d+d1,d>=0
    1. 重复2-3,直到绘制完成
#include <gl/glut.h>
#include <stdio.h>
#include <math.h>
int xs,ys,xe,ye;
//x0和y0为起始坐标,x1和y1为终止坐标

void MidPoint(int x0, int y0, int x1, int y1){
    int a=y0-y1;
    int b=x1-x0;
    int c=x0*y1-x1*y0;
    int d=2*a+b;
    int d1=2*a;
    int d2=2*(a+b);
    //斜率小于1时
        int y=y0;
        for (int x=x0;x<=x1;x++){
            if (d<0){
                y+=1;
                glVertex2i(x,y);
                d+=d2;
            }
            else{
                y=y;
                glVertex2i(x,y);
                d+=d1;
            }
        }

}



void lineSegment(){
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0,0.0,0.0);
    glBegin(GL_POINTS);
    MidPoint(xs,ys,xe,ye);
    glEnd();
    glFlush();
}

void main(int argc, char *argv[]){
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    printf("输出线段起始和终止坐标(范围为0-500, 0-500):");
    scanf("%d,%d,%d,%d",&xs,&ys,&xe,&ye);
    glutInitWindowPosition(50,100);
    glutInitWindowSize(500,500);
    glutCreateWindow("中点画线算法");
    glClearColor(1.0,1.0,1.0,0.0);
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(0.0,500.0,0.0,500.0);
    glutDisplayFunc(lineSegment);
    glutMainLoop();
}

特点:

  • 不必算斜率 ,无除法
  • 无浮点数,只有整数
  • 只有加法和乘2运算

3.Breshnham画线法

image.png

d初始化为0,每次加K,但y每加1,d需要减1,d高于中点取上面的像素,否则取下面的像素
x_i=x_{i+1}\\{y_i=y_{i+1},d>0.5,d=d-1\\y_i=y_i,d<0.5\\ d=d+k}
有浮点数、慢
改进1:
d与浮点数0.5比较太慢了,令e=d-0.5
x_i=x_{i+1}\\{y_i=y_{i+1},e>0,e=e-1\\y_i=y_i,e<=0\\ e=e+k}
只判断e的符号即可

终结版:
e的初值依然是浮点数,而且还要算k,不如令e=2e*dx(dx=x1-x0,dy=y1-y0,原先算斜率用的),就可以抵消分母,并把自带的0.5取整
算法:

    1. 输入(x0,y0),(x1,y1)
    1. dx=x1-x0, dy=y1-y0,e=-dx,x=x0,y=y0
    1. plot(x,y)
    1. e=e+2dy if e>0 (x,y)更新为(x+1,y+1)e=e-2dy ,else (x,y)更新为(x+1,y)
  • 5.重复3-4直到画完
#include <gl/glut.h>
#include <stdio.h>
#include <math.h>
int xs, ys, xe, ye;
//x0和y0为起始坐标,x1和y1为终止坐标

void BreshnhamLine(int x0, int y0, int x1, int y1) {
    int dy = y1 - y0;
    int dx = x1 - x0;
    if (dx == 0) {
        printf("error");
    }float k = dy / dx;
    float d = 0;
    int x = x0, y = y0;
    int e = -dx;
    for (x; x <= x1; x++) {
        glVertex2i(x, y);
        e += 2 * dy;
        if (e) {
            y += 1;
            e -= 2 * dx;
        }
    }
}



void lineSegment() {
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0, 0.0, 0.0);
    glBegin(GL_POINTS);
    BreshnhamLine(xs, ys, xe, ye);
    glEnd();
    glFlush();
}

void main(int argc, char *argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    printf("输出线段起始和终止坐标(范围为0-500, 0-500):");
    scanf("%d,%d,%d,%d", &xs, &ys, &xe, &ye);
    glutInitWindowPosition(50, 100);
    glutInitWindowSize(500, 500);
    glutCreateWindow("中点画线算法");
    glClearColor(1.0, 1.0, 1.0, 0.0);
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(0.0, 500.0, 0.0, 500.0);
    glutDisplayFunc(lineSegment);
    glutMainLoop();
}

特点:只有加法和乘法运算,全是整数运算,乘法也只是乘2,可以用移位位实现,便于硬件实现

小结

画线主要还是要简化步骤,尽量避免浮点数和除法,尽量多用加法,少用乘法
上述算法主要讨论了K<1的情况,k>1时将x,y互换即可

相关文章

网友评论

      本文标题:OpenGL:直线扫描转换

      本文链接:https://www.haomeiwen.com/subject/cqxvxctx.html