• 光栅图形学(一):直线段的扫描转换算法


    前言


      在数学上,理想的直线是没有宽度的,它是由无数个点构成的集合。对直线进行光栅化时,只能在显示器说给定的有限个像素组成的矩阵中,确定最佳逼近于该直线的一组像素,并且按扫描线顺序。

      本节介绍绘制线宽为一个像素的直线的三个常用算法:数值微分中点画线Bresenham算法

    数值微分法


      已知过端点 P0(x0, y0),P1(x1, y1) 的直线段 L(P0, P1);直线斜率为 k = (y1 - y0) / (x1 - x0)。

      于是 yi+1 = kxi+1 + b。

      于是,x每增加1,y就增加k。画点的时候还需要判断 int(y+0.5) 向下取整。

     1 // 数值微分法,伪代码
     2 void DDAline(int x0, int y0, int x1, int y1) {
     3     int dx, dy, x=x0, y=y0;
     4     double k;
     5     dx = x0 - x1; dy = y0 - y1;
     6     k = dy / dx;
     7     draw(x, y)
     8     while (x <= x1) {
     9         x += 1;
    10         y += k;
    11         draw(x, int(y+0.5));
    12     }
    13 }

      效果图如下(0,1)(5, 4):

      

    中点画线法


      假设线段 F(M) = ax + by + c = 0。(a=y0-y1; b=x1-x0; c=x0y1-x1y0)。

      中点画线法的思想就是对于点(xp,yp)的下一个点 M(xp+1,y+0.5),拿这个中点和实际点比较,如果实际点在中点上方(F(M) < 0),则取(xp+1,yp+1)为下一个点。如果实际点在中点下方(即中点代入直线方程的值大于0,F(M) >= 0),则取(xp+1, yp)。

      为了加速计算,我们通常采用增量的方法。

      假设从(xp,yp)开始画线,d的初值d0 = F(x0+1, y0+0.5)= F(x0,y0)+a+0.5。(d = a+0.5b)

    1. 若 d>=0 , 即中点代入原直线方程中的值大于0,即中点在目标直线上方,我们应该取下面的点(xp+1, yp)。判断下一个像素的位置时,应计算 d = F(xp+2,yp+0.5) = d + a,增量为 a。
    2. 若 d < 0,即中点在目标直线的下方,即取中点上面的点(xp+1,yp+1)。判断下一个像素的位置时,应计算 d = F(xp+2, yp+1.5) = d + a + b,增量为 a+b。

      因为我们只需要知道d的正负,所以可以调整 d‘ = 2a + b。

     1 void Midpoint(int x0, int y0, int x1, int y1) {
     2     int a, b, d1, d2, d, x, y;
     3     a = y0 - y1;
     4     b = x1 - x0;
     5     d = 2*a + b;
     6     d1 = 2*a, d2 = 2 * (a+b);
     7     x = x0, y = y0;
     8     draw(x, y);
     9     while (x < x1) {
    10         if (d < 0)
    11             {x++, y++, d+=d2;}
    12         else
    13             {x++; d+=d1;}
    14         draw(x, y);
    15     }
    16 }

       效果如下图(0,1)(5, 4):

      

    Bresenham算法


      Bresenham算法也是采用增量的方法,y每次累加k,超过0.5的中点位置就取上面的点,然后增量减一。如果我们增量的起始值设置为 d-0.5。就可以直接和0比较。

      每次和0.5比较都比较麻烦,所以假设一个格子的宽度为2dx,高为2dx,那么一个 k 就是2dy。

      所以如果我们设置起始增量为 -dx(-0.5*2dx)。每次移动单位为1的长度,增量就增加2dy,然后拿着这个增量和 0 比较,如果大于0,取上面的点,然后增量要减少 2dx。

     1 void IntegerBresenham(int x0, int y0, int x1, int y1) {
     2     int x, y, dx, dy;
     3     dx = x0-x1, dy = y0 - y1, e = -dx;
     4     x = x0, y = y0;
     5     for(i=0; i<=dx; ++i) {
     6         draw(x, y);
     7         x++, e=e+2*dy;
     8         if (e >= 0) {y++; e = e-2*dx;}
     9     }
    10 }

      下面是效果图:
      

      

     完整代码


     1 import matplotlib.pyplot as plt 
     2 from matplotlib.ticker import MultipleLocator
     3 
     4 # 数值微分法
     5 def DDA(x0, y0, x1, y1):
     6     dy = y0 - y1
     7     dx = x0 - x1
     8     k = dy / dx
     9     x = x0
    10     y = y0
    11 
    12     a = []
    13     b = []
    14     while (x <= x1):
    15         a.append(x)
    16         x += 1
    17         b.append(int(y+0.5))
    18         y = y+k
    19     plt.scatter(a, b, color='r')
    20 
    21 # 中点画线法
    22 def midpoint(x0, y0, x1, y1):
    23     a = y0 - y1
    24     b = x1 - x0
    25     d = 2 * a + b
    26     d1 = 2 * a
    27     d2 = 2 * (a + b)
    28     print(a, b, d1, d2, d)
    29     x = x0
    30     y = y0
    31 
    32     a = [x0]
    33     b = [y0]
    34     while x < x1:
    35         if d < 0:
    36             x += 1
    37             y += 1
    38             d += d2
    39         else:
    40             x += 1
    41             d += d1
    42         a.append(x)
    43         b.append(y)
    44     plt.scatter(a, b, color='r')
    45 
    46 def Bresenham(x0, y0, x1, y1):
    47     dx = x1 - x0
    48     dy = y1 - y0
    49     e = -dx
    50     x = x0
    51     y = y0
    52 
    53     a = []
    54     b = []
    55     while (x <= x1):
    56         a.append(x)
    57         b.append(y)
    58         x += 1
    59         e = e + 2 * dy
    60         if e >= 0:
    61             y += 1
    62             e = e - 2 * dx
    63     plt.scatter(a, b, color='r')
    64 
    65 x_target = [0, 5]
    66 y_target = [1, 4]
    67 
    68 ax = plt.subplot(111);
    69 plt.plot(x_target, y_target)
    70 ax.xaxis.grid(True, which='major')
    71 ax.yaxis.grid(True, which='major')
    72 ax.xaxis.set_major_locator(MultipleLocator(1))
    73 ax.yaxis.set_major_locator(MultipleLocator(1))
    74 
    75 # DDA(0, 1, 5, 4)
    76 # midpoint(0, 1, 5, 4)
    77 Bresenham(0, 1, 5, 4)
    78 plt.show()
  • 相关阅读:
    $(this)的意思
    Springmvc框架文件上传单文件上传
    保险业务知识价税分离
    SpringMVC框架,json
    使用springmvc框架实现多文件上传
    oracle数据库中的绑定变量
    使用Springmvc框架实现多文件上传(二)
    Springmvc框架json对象的处理
    Springmvc框架json数据传递处理,解决方案2
    [算法] 6 种排序的重写,很熟练!
  • 原文地址:https://www.cnblogs.com/mangoyuan/p/6576145.html
Copyright © 2020-2023  润新知