第二章 二维图元的生成 ( 第一部分: 直线段的扫描转换)

第二章 二维图元的生成

  • 掌握扫描转换直线段的DDA算法、中点算法

    • 及中点算法在哪些方面对DDA算法做了改进

  • 掌握扫描转换直线段的 Bresenham算法

  • 掌握圆弧的八对称性, 扫描转换圆弧的中点算法

  • 掌握生成圆弧的多边形迫近法

  • 了解正负法,掌握怎样利用正负法生成圆弧

  • 掌握扫描转换椭圆弧的中点算法

  • 了解线画图元的属性(线型、线宽)控制方法

图形的扫描转换 || 光栅化 || 图元的生成
  • 确定最佳逼近图形的象素集合,并用指定属性写象素的过程,即指完成从图元的参数表示形式转换成点阵表示形式的过程称为图形的扫描转换或光栅化

简单二维图形的显示流程

图元 -> 二维裁剪 -> 扫描转换 -> 显示

裁剪的顺序

  • 先裁剪再扫描转换

    • 常用,计算量小

  • 先扫描转换再裁剪

    • 算法简单,对有快速测试方法或硬件支持情形有利

直线段的扫描转换

基于假设

直线段的宽度为 1, 大于 1 的由线宽控制算法处理

直线段的斜率在 [-1, 1], 绝对值大于 1 的通过修改算法完成

  • 直线段由2个点坐标确定 P0 (x0, y0), P1(x1, y1)

直接求交

  1. 划分区间[x0, x1], 其中 x_{i+1}=x_i+1

  1. 计算纵坐标

  2. 纵坐标取整

复杂度

  • 乘法 + 加法 + 取整

DDA算法

由于 y_{i+1}=y_i+k

省略了乘法计算

void LineDDA(int x0, int y0, int x1,int y1, int color)
 /* 假定x0<x1,-1<=k<=1 */
{
    int x;
    float dx, dy, y, k;
    dx = x1 - x0;
    dy = y1 - y0;
    k = dy / dx;                                // 求斜率
    y = y0;
    for(x = x0; x <= x1; x++)                   // x从x1到xn
    {
        Putpixel(x, int(y + 0.5), color);      
        y += k;                                 //y每次增加一个斜率值
    }
}

中点算法
  • 消除DDA中的浮点运算

    • 使用隐式方程

F(x,y)=ax+by+c , 式中

a = y0 - y1,

b = x1 - x0

c = x0y1 - x1y0

由于下一个像素点只有两个选项 p1(x+1,y) 或者 p2(x+1, y+1)

M = (x+1, y+0.5)p1p2 中点, Q 为直线与 x = x+1 的交点, 若

  • MQ 下方, 则 di = F(M) < 0, 取 p2 为下一个像素, 则d(i+1) = F(x+1+1, y+0.5+1)

  • MQ 上方, 则 di = F(M) > 0, 取 p1 为下一个像素, 则d(i+1) = F(x+1+1, y+0.5)

  • MQ 上, 取 p1p2 皆可, 约定取 p1

由于 d 的增量是可以根据 d 的正负性预测的, 因此有, 因为(x0, y0) 在直线上, 有 d0=a+0.5*b

  • d >= 0, d 的增量为 d1 = a

  • d < 0, d 的增量为 d2 = a+b

为了消除浮点数计算, 全部改写成 2 倍形式, 即

d0 = a + a + b

d1 = a + a

d2 = a + a + b + b

Midpointline(int x0, int y0, int x1, int y1, int color)
{
    int a, b, d, d1, d2, x, y;
    a = y0 - y1; 
    b = x1 - x0;
    d = a + a + b;                  // 计算 a, b, d0
    d1 = a + a;
    d2 = a + a + b + b;             // 计算可能的增量
    x = x0;
    y = y0;
    PutPixel(x, y, color);          // 绘制初始像素点
    while (x < x1)
    {
        if (d < 0)
        {
            x++; 
            y++; 
            d += d2;                // 如果 d 为负,取右上角点 (y 加 1)
        }
        else
        {
            x++;
            d += d1;                // 如果 d 为正,取右边点
        }
        PutPixel(x, y, color);
    }
} 

Bresenham算法

Bresenham算法 是计算机图形学领域使用最广泛的直线扫描转换算法

  • 该方法类似于中点法,由误差项符号决定下一个象素取右边点还是右上点

算法原理

过各行各列象素中心构造一组虚拟网格线。按直线从起点到终点的顺序计算直线与各垂直网格线的交点,然后确定该列象素中与此交点最近的象素

该算法的巧妙之处在于采用增量计算,使得对于每一列,只要检查一个误差项的符号,就可以确定该列的所求象素。

算法步骤

d 为误差项, 由于直线起点在像素中心, d 的初值为 0

x 下标每增加 1,d 的值相应递增直线的斜率值 k,即 d=d+k

一旦 d >= 1,就把它减去 1,这样保证 d 在 0、1 之间

d >= 0.5 时,取 (xi+1,yi+1)

d < 0.5 时,取 (xi+1,yi)

为方便计算,令 e=d-0.5e 的初值为-0.5,增量为 k

e >= 0 时,取 (xi+1,yi+1)

e < 0 时,取 (xi+1,yi)

上述算法在计算直线斜率与误差项时用到小数与除法,可以改用整数以避免除法

改进后的算法称为Bresenham算法

由于算法中只用到误差项的符号,而且2dx为正,因此可作如下替换

e = e * 2dx

e0=-0.5 * (2dx) = -dx

增量为:k * (2dx) = 2dy

e > 0 时,减量为:1 * (2dx) = 2dx

于是有如下算法

void Bresenhamline(int x0, int y0, int x1, int y1, int color) 
{
    int x, y, dx, dy, e;
    dx = x1 - x0;
    dy = y1 - y0;
    e = -dx;                        // e 的初值为 -dx
    x = x0;
    y = y0;
​
    for (int i = 0; i <= dx; i++) 
    {
        Putpixel(x, y, color);
        x = x + 1;
        e = e + 2 * dy;             // e 每次的增量为 2 * dy
​
        if (e >= 0) 
        {
            y++;
            e = e - 2 * dx;         // 若 e >= 0,则 y 增 1,e - 2 * dx
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值