案例 3 DDA 画线算法 知识点 .第一个八分象限的DDA 算法。 .直线的主位移方向。 .增量算法。 一、案例需求 1. 案例描述 在窗口客户区内自定义二维坐标系。基于第一个八分象限的DDA 算法,绘制起点为 P0(0,0)、终点为P1(300,100)的一段直线。 2. 功能说明 (1)自定义二维屏幕坐标系,原点位于客户区中心, x 轴水平向右为正, y 轴垂直向上 为正。直线的起点和终点基于自定义坐标系定义。 (2)绘制一段黑色直线,包括起点,不包括终点。 3. 案例效果图 绘制一段第一个八分象限内的直线,效果如图3-1所示。 图3-1 第一个八分象限内直线的效果图 二、案例分析 1. 设计目的 学习用离散点表示理想直线的思想。光栅扫描显示器是画点设备,因此不能直接从一 点到另一点绘制一段直线。直线扫描转换的结果是一组在几何上距离理想直线最近的离散 像素点集。 ·23· 2.直线的主位移方向 扫描转换算法中,常根据直线在 x 轴和 y 轴上的投影长度确定主位移方向。在主位移 方向上执行的是±1操作,另一个方向上可以±1或0。如果dx >dy,则取 x 方向为主位 移方向,如图3-2(a)所示;如果dx=dy,取 x 方向为主位移方向或取 y 方向为主位移方向 皆可,如图3-2(b)所示;如果dx SetMapMode(MM_ANISOTROPIC); //自定义二维坐标系 pDC->SetWindowExt(rect.Width(), rect.Height()); //设置窗口范围 pDC->SetViewportExt(rect.Width(), -rect.Height()); //设置视区范围 pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2); //设置二维坐标系原点 rect.OffsetRect(-rect.Width()/2, -rect.Height()/2); //rect 矩形与客户区重合 CPoint P0(0, 0), P1(300, 100); //确定直线的起点和终点 DDALine(pDC, P0, P1); //调用DDA 算法 } ·25· 程序说明:在自定义坐标系内绘制起点位于原点,终点位于第一个八分象限内的直线。 4.DDA 算法 void CTestView::DDALine(CDC*pDC, CPoint P0, CPoint P1) { int dx=P1.x-P0.x; //直线水平方向位移 int dy=P1.y-P0.y; //直线垂直方向位移 double k=double(dy)/dx; //直线斜率 int x; double y=P0.y; COLORREF crColor=RGB(0, 0, 0); for (x=P0.x; xSetPixelV(x, ROUND(y), crColor); // 绘 制离散像素点 y+=k; } } 程序说明:SetPixelV()函数不需要返回值,绘图速度要快于SetPixel()函数。 五、案例小结 (1)DDA 算法计算一个像素点时,需要做除法运算,因此计算时采用了浮点数。 (2)DDA 算法需要对计算结果进行圆整处理,不适合硬件实现。 六、案例拓展 给定直线的起点坐标为P0(x0,y0)、终点坐标为P1(x1,y1),容易计算出直线的斜率 k。当k ≤1时,DDA 算法的递推公式为 xi+1 =xi ±1 yi+1 =yi ±k;当k ≥1时,DDA 算法的递推 公式为 xi+1 =xi ±1k yi+1 =yi ±1 ì . í .. .. 。假定直线的间隔角度是5°,试编程绘制图3-3所示的图形。 图3-3 放射直线 ·26·