导航:首页 > 源码编译 > 中点算法画直线

中点算法画直线

发布时间:2025-03-24 22:56:40

‘壹’ 图形学中的中点画线法与Bresenham算法画线的区别

在图形学中,中点画线法与Bresenham算法画线的主要区别在于决策参数的计算方式。Bresenham算法的核心在于决定下一个点是在(x0+1,y0)还是(x0+1,y0+1)处。计算过程中,假设我们从点(x0,y0)开始,需要计算点(x0+1,y0)和点(x0+1,y0+1)与直线的垂直距离,分别记为p1和p2。决策参数p定义为p2-p1,依据p的正负值决定下一个点的选择。

相比之下,中点画线法的决策参数是基于直线方程的。假设我们想要画的直线方程为y=kx+b,那么决策参数p可以通过中点坐标代入直线方程计算得出。具体来说,对于两个点(x0+1,y0)和(x0+1,y0+1),我们计算它们的中点(x0+1,y0+0.5)并代入直线方程,得到p的值。然后根据p的正负值判断中点是否在直线上或其一侧,从而决定绘制哪个点。

值得注意的是,中点画线法最初主要用于绘制圆,它通过计算中点与圆心的距离来决定点的选择,这使得中点画线法在绘制圆时表现得更为高效和精确。尽管中点画线法的原理与Bresenham算法类似,但具体实现上的差异在于决策参数的选择和计算方式的不同。

综上所述,中点画线法与Bresenham算法在决策参数的计算上有显着区别。Bresenham算法侧重于直线的垂直距离差,而中点画线法则基于直线方程的中点距离。这种差异使得它们在不同的应用场景中展现出各自的优劣。

‘贰’ 分别解释直线生成算法DDA法、中点画线法和Bresenham法的基本原理

DDA称为数值微分画线算法,是直线生成算法中最简单的一种。原理相当简单,就是最直观的根据斜率的偏移程度,决定是以x为步进方向还是以y为步进方向。然后在相应的步进方向上,步进变量每次增加一个像素,而另一个相关坐标变量则为Yk_1=Yk+m(以x为步进变量为例,m为斜率)
假定直线斜率k在0~1之间,当前象素点为(xp,yp),则下一个象素点有两种可选择点P1(xp+1,yp)或P2(xp+1,yp+1)。若P1与P2的中点(xp+1,yp+0.5)称为M,Q为理想直线与x=xp+1垂线的交点。当M在Q的下方时,则取P2应为下一个象素点;当M在Q的上方时,则取P1为下一个象素点。这就是中点画线法的基本原理

Bresenham:过各行、各列像素中心构造一组虚拟网格线,按直线从起点到终点的顺序计算直线各垂直网格线的交点,然后确定该列像素中与此交点最近的像素。该算法的优点在于可以采用增量计算,使得对于每一列,只要检查一个误差项的符号,就可以确定该列所求的像素。

大概就是这样,预知详细,可以参考图形学的书籍

‘叁’ 求计算机图形学中的直线绘制函数法、DDA算法、中点法和Bresenham算法的优缺点以及比较.

Bresenham算法的特点是:
1,不必计巧毁首算直线之斜率,因此不做除法;

2,不用浮点数,只用整数;
3,只做整数加孝数减法和乘2运算,而乘2运算可以用硬件移位实现.

Bresenham算法速度很快,并适余悄于用硬件实现.
DDA算法的特点:
浮点数运算
不易硬件实现
中点画线法特点:

只有整数运算,不含乘除法
可用硬件实现
因(X0,Y0)在直线上,所以F(X0,Y0)=0

‘肆’ 求中点画线算法的c++代码...

直线方程:a*x+b*y+c=0, p1(x1,y1), p2(x2,y2)==> a=y1-y2;b=x2-x1.

点到直线的距离:distance=|a*x0-b*y0+c|/sqrt(a*a + b*b)
设directionX,directionY分别为从(x1,y1)==>(x2,y2)的单位变化量(+/-1)

当直线偏向X轴时,当前象素为(xk, yk),下一个象素可能为:(xk+directionX, yk)或者(xk+directionX,yk+directionY)这两点到直线的距离分别为:

d1=|a*xk+b*yk+c+a*directionX|/sqrt(a*a + b*b);
d2=|a*xk+b*yk+c+a*directionX+b*directonY|/sqrt(a*a + b*b);
便于运算,定义:f(xk,yk)= d2 * d2 - d1 * d1 (将d1和d2的分母去掉了的)
= b*b + 2*b*directonY*(a*xk+b*yk+c+a*directionX) ;
当f(xk,yk)<0的时候,下拆陆敬一个点为(xk+directionX,yk+directionY):
f(xk+directionX,yk+directionY)=f(xk,yk) +2*b*b+2*a*b*directionX*directionY ;
当f(xk,yk)>=0的时候,下一个点为(xk+directionX, yk) :
f(xk+directionX, yk) = f(xk,yk) + 2*a*b*directionX*directionY ;

当直线偏向Y轴时,当前象素为(xk, yk),下一个象素可能为:(xk, yk+directionY)或者(xk+directionX,yk+directionY)这两点到直线的距离分别为:

d1=|a*xk+b*yk+c+b*directionY|/sqrt(a*a + b*b);
d2=|a*xk+b*yk+c+b*directionY+a*directonX|/sqrt(a*a + b*b);
便于运算,定义:f(xk,yk)= d2 * d2 - d1 * d1 (将d1和d2的分母去掉了的)
= a*a + 2*a*directonX*(a*xk+b*yk+c+b*directionY) ;
当f(xk,yk)<0的时候,下一个点旅慎为(xk+directionX,yk+directionY):
f(xk+directionX,yk+directionY)=f(xk,yk) +2*a*a+2*a*b*directionX*directionY ;
当f(xk,yk)>=0的时候,下一个点为(xk+directionX, yk) :
f(xk+directionX, yk) = f(xk,yk) + 2*a*b*directionX*directionY ;

/*
* 中点画线算法
*/
void LineMLDA(HDC& hdc, POINT ptSrc, POINT ptDec, COLORREF cr)
{
int a, b ;

a = ptSrc.y - ptDec.y ;
b = ptDec.x - ptSrc.x ;

int iDirectionX, iDirectionY ;

iDirectionX = iDirectionY = 1 ;
if(b<0)
iDirectionX = -1 ;
if(a>悉皮0)
iDirectionY = -1 ;

int iDistance,
iDeltaSmall, iDeltaBig ,
iCurrX, iCurrY ;

int iStep ;

iDeltaSmall = 2*a*b*iDirectionX*iDirectionY ;

iCurrX = ptSrc.x ;
iCurrY = ptSrc.y ;

if(abs(b) > abs(a))
{
iDeltaBig = 2*b*b + iDeltaSmall ;
iDistance = b*b + iDeltaSmall ;

iStep = abs(b) ;

while (iStep-- > 0)
{
SetPixel(hdc, iCurrX, iCurrY, cr) ;

iCurrX += iDirectionX ;
if(iDistance < 0)
{
iCurrY += iDirectionY ;

iDistance += iDeltaBig ;
}
else
{
iDistance += iDeltaSmall ;
}
}
}
else
{
iDeltaBig = 2*a*a + iDeltaSmall ;
iDistance = a*a + iDeltaSmall ;

iStep = abs(a) ;

while (iStep-- > 0)
{
SetPixel(hdc, iCurrX, iCurrY, cr) ;

iCurrY += iDirectionY ;
if(iDistance < 0)
{
iCurrX += iDirectionX ;

iDistance += iDeltaBig ;
}
else
{
iDistance += iDeltaSmall ;
}
}
}

SetPixel(hdc, ptDec.x, ptDec.y, cr) ;
}

‘伍’ 直线和圆的显示(在线等答案)

实验2 圆与椭圆
给出圆心坐标(xc, yc)和半径r,逐点画出一个圆周的公式有下列两种。
一 直角坐标法
直角坐标系的圆的方程为

由上式导出:

当x-xc从-r到r做加1递增时,就可以求出对应的圆周点的y坐标。但是这样求出的圆周上的点是不均匀的,| x-xc | 越大,对应生成圆周点之间的圆周距离也就越长。因此,所生成的圆不美观。
二 中点画圆法
如图1所示,函数为F(x, y)=x2+y2-R2的构造圆,圆上的点为F(x, y)=0,圆外的点F(x, y)>0,圆内的点F(x, y)<0,构造判别式:
d=F(M)=F(xp+1, yp-0.5)=(xp+1)2+(yp-0.5)2
若d<0,则应取P1为下一像素,而且下一像素的判别式为
d=F(xp+2, yp-0.5)= (xp+2)2+(yp-0.5)2-R2=d+2xp+3
若d≥0,则应取P2为下一像素,而且下一像素的判别式为
d=F(xp+2, yp-1.5)= (xp+2)2+(yp-1.5)2-R2=d+2(xp- yp)+5
我们讨论按顺时针方向生成第二个八分圆,则第一个像素是(0, R),判别式d的初始值为
d0=F(1, R-0.5)=1.25-R
三 圆的Bresenham算法
设圆的半径为r,先考虑圆心在(0, 0),从x=0、y=r开始的顺时针方向的1/8圆周的生成过程。在这种情况下,x每步增加1,从x=0开始,到x=y结束,即有xi+1 = xi + 1;相应的,yi+1则在两种可能中选择:yi+1=yi或者yi+1 = yi - 1。选择的原则是考察精确值y是靠近yi还是靠近yi-1(见图2),计算式为
y2= r2-(xi+1)2
d1 = yi2-y2 = yi2-r2+(xi+1)2
d2 = y2- (yi - 1)2 = r2-(xi+1)2-(yi - 1)2
令pi=d1-d2,并代入d1、d2,则有
pi = 2(xi+1)2 + yi2+ (yi - 1)2 -2r2 (1.6)
pi称为误差。如果pi<0,则yi+1=yi,否则yi+1=yi - 1。
pi的递归式为
pi+1 = pi + 4xi +6+2(yi2+1- yi2)-2(yi+1-yi) (1.7)
pi的初值由式(1.6)代入xi=0,yi=r,得
p1 = 3-2r (1.8)
根据上面的推导,圆周生成算法思想如下:
(1)求误差初值,p1=3-2r,i=1,画点(0, r)。
(2)求下一个光栅位置,其中xi+1=xi+1,如果pi<0则yi+1=yi,否则yi+1=yi - 1。
(3)画点(xi+1, yi+1)。
(4)计算下一个误差,如果pi<0则pi+1=pi+4xi+6,否则pi+1=pi+4(xi - yi)+10。
(5)i=i+1,如果x=y则结束,否则返回步骤(2)。
程序设计步骤如下。
(1)创建应用程序框架,以上面建立的单文档程序框架为基础。
(2)编辑菜单资源。
在工作区的ResourceView标签中,单击Menu项左边"+",然后双击其子项IDR_MAINFRAME,并根据表1中的定义添加编辑菜单资源。此时建好的菜单如图3所示。
表1 菜单资源表
菜单标题 菜单项标题 标示符ID
圆 中点画圆 ID_MIDPOINTCIRCLE
Bresenham画圆 ID_BRESENHAMCIRCLE
(3)添加消息处理函数。
利用ClassWizard(建立类向导)为应用程序添加与菜单项相关的消息处理函数,ClassName栏中选择CMyView,根据表2建立如下的消息映射函数,ClassWizard会自动完成有关的函数声明。
表2 菜单项的消息处理函数
菜单项ID 消 息 消息处理函数
ID_MIDPOINTCIRCLE CONMMAN OnMidpointcircle
ID_BRESENHAMCIRCLE CONMMAN OnBresenhamcircle
(4)程序结构代码,在CMyView.cpp文件中的相应位置添加如下代码。

void CMyView::OnMidpointcircle() //中点算法绘制圆,如图4所示
{
// TODO: Add your command handler code here
CDC* pDC=GetDC();
int xc=300, yc=300, r=50, c=0;
int x,y;
float d;
x=0; y=r; d=1.25-r;
pDC->SetPixel ((xc+x),(yc+y),c);
pDC->SetPixel ((xc-x),(yc+y),c);
pDC->SetPixel ((xc+x),(yc-y),c);
pDC->SetPixel ((xc-x),(yc-y),c);
pDC->SetPixel ((xc+y),(yc+x),c);
pDC->SetPixel ((xc-y),(yc+x),c);
pDC->SetPixel ((xc+y),(yc-x),c);
pDC->SetPixel ((xc-y),(yc-x),c);
while(x<=y)
{ if(d<0) d+=2*x+3;
else { d+=2*(x-y)+5; y--;}
x++;
pDC->SetPixel ((xc+x),(yc+y),c);
pDC->SetPixel ((xc-x),(yc+y),c);
pDC->SetPixel ((xc+x),(yc-y),c);
pDC->SetPixel ((xc-x),(yc-y),c);
pDC->SetPixel ((xc+y),(yc+x),c);
pDC->SetPixel ((xc-y),(yc+x),c);
pDC->SetPixel ((xc+y),(yc-x),c);
pDC->SetPixel ((xc-y),(yc-x),c);
}
}
void CMyView::OnBresenhamcircle() //// Bresenham算法绘制圆,如图5所示
{
CDC* pDC=GetDC();
int xc=100, yc=100, radius=50, c=0;
int x=0,y=radius,p=3-2*radius;
while(x<y)
{
pDC->SetPixel(xc+x, yc+y, c);
pDC->SetPixel(xc-x, yc+y, c);
pDC->SetPixel(xc+x, yc-y, c);
pDC->SetPixel(xc-x, yc-y, c);
pDC->SetPixel(xc+y, yc+x, c);
pDC->SetPixel(xc-y, yc+x, c);
pDC->SetPixel(xc+y, yc-x, c);
pDC->SetPixel(xc-y, yc-x, c);
if (p<0)
p=p+4*x+6;
else
{
p=p+4*(x-y)+10;
y-=1;
}
x+=1;
}
if(x==y)
pDC->SetPixel(xc+x, yc+y, c);
pDC->SetPixel(xc-x, yc+y, c);
pDC->SetPixel(xc+x, yc-y, c);
pDC->SetPixel(xc-x, yc-y, c);
pDC->SetPixel(xc+y, yc+x, c);
pDC->SetPixel(xc-y, yc+x, c);
pDC->SetPixel(xc+y, yc-x, c);
pDC->SetPixel(xc-y, yc-x, c);
}

四 椭圆扫描转换中点算法
下面讨论椭圆的扫描转换中点算法,设椭圆为中心在坐标原点的标准椭圆,其方 程为
F(x, y)=b2x2+a2y2-a2b2=0
(1)对于椭圆上的点,有F(x, y)=0;
(2)对于椭圆外的点,F(x, y)>0;
(3)对于椭圆内的点,F(x, y)<0。
以弧上斜率为-1的点作为分界将第一象限椭圆弧分为上下两部分(如图6所示)。
法向量:

而在下一个点,不等号改变方向,则说明椭圆弧从上部分转入下部分。
与中点绘制圆算法类似,一个像素确定后,在下面两个候选像素点的中点计算一个判别式的值,再根据判别式符号确定离椭圆最近的点。先看椭圆弧的上半部分,具体算法如下:
假设横坐标为xp的像素中与椭圆最近点为(xp, yp),下一对候选像素的中点应为(xp+1,yp-0.5),判别式为

,表明中点在椭圆内,应取正右方像素点,判别式变为

若 ,表明中点在椭圆外,应取右下方像素点,判别式变为

判别式 的初始条件确定。椭圆弧起点为(0, b),第一个中点为(1,b - 0.5),对应判别式为

在扫描转换椭圆的上半部分时,在每步迭代中需要比较法向量的两个分量来确定核实从上部分转到下半部分。在下半部分算法有些不同,要从正上方和右下方两个像素中选择下一个像素。在从上半部分转到下半部分时,还需要对下半部分的中点判别式进行初始化。即若上半部分所选择的最后一个像素点为(xp, yp),则下半部分中点判别式应在(xp+0.5, yp-1)的点上计算。其在正下方与右下方的增量计算同上半部分。具体算法的实现请参考下面的程序设计。
程序设计步骤如下。
(1)创建应用程序框架,以上面建立的单文档程序框架为基础。
(2)编辑菜单资源。
在工作区的ResourceView标签中,单击Menu项左边"+",然后双击其子项IDR_MAINFRAME,并根据表3中的定义添加编辑菜单资源。此时建好的菜单如图7所示。
表3 菜单资源表
菜单标题 菜单项标题 标示符ID
椭圆 中点画椭圆 ID_MIDPOINTELLISPE

图7 程序主菜单
(3)添加消息处理函数。
利用ClassWizard(建立类向导)为应用程序添加与菜单项相关的消息处理函数,ClassName栏中选择CMyView,根据表4建立如下的消息映射函数,ClassWizard会自动完成有关的函数声明。
表4 菜单项的消息处理函数
菜单项ID 消 息 消息处理函数
ID_MIDPOINTELLISPE CONMMAN OnMidpointellispe
(4)程序结构代码如下:

void CMyView:: OnMidpointellispe () //中点算法绘制椭圆,如图8所示
{
CDC* pDC=GetDC();
int a=200,b=100,xc=300,yc=200,c=0;
int x,y;
double d1,d2;
x=0;y=b;
d1=b*b+a*a*(-b+0.25);
pDC->SetPixel(x+300,y+200,c);
pDC->SetPixel(-x+300,y+200,c);
pDC->SetPixel(x+300,-y+200,c);
pDC->SetPixel(-x+300,-y+200,c);
while(b*b*(x+1)<a*a*(y-0.5))
{
if(d1<0){
d1+=b*b*(2*x+3);
x++;}
else
{d1+=b*b*(2*x+3)+a*a*(-2*y+2);
x++;y--;
}
pDC->SetPixel(x+xc,y+yc,c);
pDC->SetPixel(-x+xc,y+yc,c);
pDC->SetPixel(x+xc,-y+yc,c);
pDC->SetPixel(-x+xc,-y+yc,c);
}
d2=sqrt(b*(x+0.5))+a*(y-1)-a*b;
while(y>0)
{
if(d2<0){
d2+=b*b*(2*x+2)+a*a*(-2*y+3);
x++;y--;}
else
{d2+=a*a*(-2*y+3);
y--;}
pDC->SetPixel(x+xc,y+yc,c);
pDC->SetPixel(-x+xc,y+yc,c);
pDC->SetPixel(x+xc,-y+yc,c);
pDC->SetPixel(-x+xc,-y+yc,c);
}
}

实验一: 直 线
数学上,理想的直线是由无数个点构成的集合,没有宽度。计算机绘制直线是在显示器所给定的有限个像素组成的矩阵中,确定最佳逼近该直线的一组像素,并且按扫描线顺序,对这些像素进行写操作,实现显示器绘制直线,即通常所说的直线的扫描转换,或称直线光栅化。
由于一图形中可能包含成千上万条直线,所以要求绘制直线的算法应尽可能地快。本节介绍一个像素宽直线的常用算法:数值微分法(DDA)、中点画线法、Bresenham 算法。
一. DDA(数值微分)算法
DDA算法原理:如图1-1所示,已知过端点 的直线段 ;直线斜率为 ,从 的左端点 开始,向 右端点步进画线,步长=1(个像素),计算相应的 坐标 ;取像素点 [ , round(y)] 作为当前点的坐标。计算 ,当 ,即当x每递增1,y递增k(即直线斜率)。
注意:上述分析的算法仅适用于k1的情形。在这种情况下,x每增加1, y最多增加1。当 时,必须把x,y地位互换,y每增加1,x相应增加1/k(请参阅后面的Visual C++程序)。
二. 生成直线的中点画线法
中点画线法的基本原理如图1-2所示。在画直线段的过程中,当前像素点为P,下一个像素点有两种选择,点P1或P2。M为P1与P2中点,Q为理想直线与X=Xp+1垂线的交点。当M在Q的下方时,则P2应为下一个像素点;当M在Q的上方时,应取P1为下一点。
中点画线法的实现:令直线段为L[ p0(x0,y0), p1(x1, y1)],其方程式F(x, y)=ax+by+c=0。
其中,a=y0–y1, b=x1–x0, c=x0y1–x1y0;点与L的关系如下。
在直线上,F(x, y)=0;
在直线上方,F(x, y)>0;
在直线下方,F(x, y)<0。
把M代入F(x, y),判断F的符号,可知Q点在中点M的上方还是下方。为此构造判别式d=F(M)=F(xp+1, yp+0.5)=a(xp+1)+b(yp+0.5)+c。
当d < 0,L(Q点)在M上方,取P2为下一个像素。
当d > 0,L(Q点)在M下方,取P1为下一个像素。
当d=0,选P1或P2均可,取P1为下一个像素。
其中d是xp, yp的线性函数。
三. Bresenham算法
Bresenham算法是计算机图形学领域使用最广泛的直线扫描转换算法。由误差项符号决定下一个像素取右边点还是右上方点。
设直线从起点(x1, y1)到终点(x2, y2)。直线可表示为方程y = mx+b,其中b=y1–mx1, m = (y2–y1)/(x2–x1)=dy/dx;此处的讨论直线方向限于第一象限,如图1-3所示,当直线光栅化时,x每次都增加1个单元,设x像素为(xi,yi)。下一个像素的列坐标为xi+1,行坐标为yi或者递增1为yi+1,由y与yi及yi+1的距离d1及d2的大小而定。计算公式为
y = m(xi + 1) + b (1.1)
d1 = y – yi (1.2)
d2=yi+1–y (1.3)
如果d1–d2>0,则yi+1=yi+1,否则yi+1=yi。
式(1.1)、(1.2)、(1.3)代入d1–d2,再用dx乘等式两边,并以Pi=(d1–d2),dx代入上述等式,得
Pi = 2xidy–2yidx+2dy+(2b–1)dx (1.4)
d1–d2是用以判断符号的误差。由于在第一象限,dx总大于0,所以Pi仍旧可以用做判断符号的误差。Pi+1为
Pi+1 = Pi+2dy–2(yi+1–yi)dx (1.5)
求误差的初值P1,可将x1、y1和b代入式(1.4)中的xi、yi,而得到
P1 = 2dy–dx
综述上面的推导,第一象限内的直线Bresenham算法思想如下:
(1)画点(x1, y1),dx=x2–x1,dy=y2–y1,计算误差初值P1=2dy–dx,i=1。
(2)求直线的下一点位置xi+1 = xi + 1,如果Pi>0,则yi+1=yi+1,否则yi+1=yi。
(3)画点(xi+1, yi+1)。
(4)求下一个误差Pi+1,如果Pi>0,则Pi+1=Pi+2dy–2dx,否则Pi+1=Pi+2dy。
(5)i=i+1;如果i<dx+1则转步骤(2);否则结束操作。
四. 程序设计
1 程序设计功能说明
编程实现上述算法,本程序利用最基本的绘制元素(如点、直线等),绘制图形。如图1-4所示,为程序运行主界面,通过选择菜单及下拉菜单的各功能项分别完成各种对应算法的图形绘制。

图1-4 基本图形生成的程序运行界面
2 创建工程名称为“基本图形的生成”单文档应用程序框架
(1)启动VC,选择“文件”|“新建”菜单命令,并在弹出的新建对话框中单击“工程”标签。
(2)选择MFC AppWizard(exe),在“工程名称”编辑框中输入 “基本图形的生成”作为工程名称,单击“确定”按钮,出现Step 1对话框。
(3)选择“单个文档”选项,单击“下一个”按钮,出现Step 2对话框。
(4)接受默认选项,单击“下一个”按钮,在出现的Step 3~Step 5对话框中,接受默认选项,单击“下一个”按钮。
(5)在Step 6对话框中单击“完成”按钮,即完成“基本图形的生成”应用程序的所有选项,随后出现工程信息对话框(记录以上步骤各选项选择情况),如图1-5所示,单击“确定”按钮,完成应用程序框架的创建。

图1-5 信息程序基本
3 编辑菜单资源
设计如图1-4所示的菜单项。在工作区的ResourceView标签中,单击Menu项左边“+”,然后双击其子项IDR_MAINFRAME,并根据表1-1中的定义编辑菜单资源。此时VC已自动建好程序框架,如图1-5所示。
表1-1 菜单资源表
菜单标题 菜单项标题 标示符ID
直线 DDA算法生成直线 ID_DDALINE
Bresenham算法生成直线 ID_BRESENHAMLINE
中点算法生成直线 ID_MIDPOINTLINE
4 添加消息处理函数
利用ClassWizard(建立类向导)为应用程序添加与菜单项相关的消息处理函数,ClassName栏中选择CMyView,根据表1-2建立如下的消息映射函数,ClassWizard会自动完成有关的函数声明。
表1-2 菜单项的消息处理函数
菜单项ID 消 息 消息处理函数
ID_DDALINE CONMMAN OnDdaline
ID_MIDPOINTLINE CONMMAN OnMidpointline
ID_BRESENHAMLINE CONMMAN OnBresenhamline
5 程序结构代码,在CMyView.cpp文件中相应位置添加如下代码:
// DDA算法生成直线
void CMyView:: OnDdaline()
{
CDC* pDC=GetDC();//获得设备指针
int xa=100,ya=300,xb=300,yb=200,c=RGB(255,0,0);//定义直线的两端点,直线颜色
int x,y;
float dx, dy, k;
dx=(float)(xb-xa), dy=(float)(yb-ya);
k=dy/dx, y=ya;
if(abs(k)<1)
{
for (x=xa;x<=xb;x++)
{pDC->SetPixel (x,int(y+0.5),c);
y=y+k;}
}
if(abs(k)>=1)
{
for (y=ya;y<=yb;y++)
{pDC->SetPixel (int(x+0.5),y,c);
x=x+1/k;}
}
ReleaseDC(pDC);
}

说明:
(1)以上代码理论上通过定义直线的两端点,可得到任意端点之间的一直线,但由于一般屏幕坐标采用右手系坐标,屏幕上只有正的x, y值,屏幕坐标与窗口坐标之间转换知识请参考第3章。
(2)注意上述程序考虑到当k1的情形x每增加1,y最多增加1;当k>1时,y每增加1,x相应增加1/k。在这个算法中,y与k用浮点数表示,而且每一步都要对y进行四舍五入后取整。

//中点算法生成直线
void CMyView::OnMidpointline()
{
CDC* pDC=GetDC();
int xa=300, ya=200, xb=450, yb=300,c=RGB(0,255,0);
int a, b, d1, d2, d, x, y;
a=ya-yb, b=xb-xa, d=2*a+b;
d1=2*a, d2=2* (a+b);
x=xa, y=ya;
pDC->SetPixel(x, y, c);
while (x<xb)
{ if (d<0) {x++, y++, d+=d2; }
else {x++, d+=d1;}
pDC->SetPixel(x, y, c);
}
ReleaseDC(pDC);
}

说明:
(1)其中d是xp, yp的线性函数。为了提高运算效率,程序中采用增量计算。具体算法如下:若当前像素处于d>0情况,则取正右方像素P1(xp+1, yp),判断下一个像素点的位置,应计算d1=F(xp+2, yp+0.5)=a(xp+2)+b(yp+0.5)=d+a;,其中增量为a。若d<0时,则取右上方像素P2(xp+1, yp+1)。再判断下一像素,则要计算d2 = F(xp+2, yp+1.5)=a(xp+2)+b(yp+1.5) + c=d+a+b,增量为a+b。
(2) 画线从(x0, y0)开始,d的初值d0=F(x0+1, y0+0.5)=F(x0, y0)+a+0.5b,因F(x0, y0)=0,则d0=a+0.5b。
(3)程序中只利用d的符号,d的增量都是整数,只是初始值包含小数,用2d代替d,使程序中仅包含整数的运算。

//Bresenham算法生成直线
void CMyView::OnBresenhamline()
{
CDC* pDC=GetDC();
int x1=100, y1=200, x2=350, y2=100,c=RGB(0,0,255);
int i,s1,s2,interchange;
float x,y,deltax,deltay,f,temp;
x=x1;
y=y1;
deltax=abs(x2-x1);
deltay=abs(y2-y1);
if(x2-x1>=0) s1=1; else s1=-1;
if(y2-y1>=0) s2=1; else s2=-1;
if(deltay>deltax){
temp=deltax;
deltax=deltay;
deltay=temp;
interchange=1;
}
else interchange=0;
f=2*deltay-deltax;
pDC->SetPixel(x,y,c);
for(i=1;i<=deltax;i++){
if(f>=0){
if(interchange==1) x+=s1;
else y+=s2;
pDC->SetPixel(x,y,c);
f=f-2*deltax;
}
else{
if(interchange==1) y+=s2;
else x+=s1;
f=f+2*deltay;
}
}
}

说明:
(1)以上程序已经考虑到所有象限直线的生成。
(2)Bresenham算法的优点如下:
① 不必计算直线的斜率,因此不做除法。
② 不用浮点数,只用整数。
③ 只做整数加减运算和乘2运算,而乘2运算可以用移位操作实现。
④ Bresenham算法的运算速度很快。

阅读全文

与中点算法画直线相关的资料

热点内容
压缩袋怎么封口 浏览:252
人脸识别算法c语言 浏览:377
外网服务器是干什么用的 浏览:406
平面图形面积计算法 浏览:542
手机shell命令 浏览:93
拯救者有解压软件吗 浏览:406
加密短信认证限额 浏览:969
程序员职述报告ppt 浏览:155
程序员有什么重要的证书 浏览:304
零基础学算法第二版 浏览:816
在哪里关app弹出信息 浏览:615
加密播放软件提取视频 浏览:351
安卓手机转到苹果手机用什么软件 浏览:461
taptap怎么改吃鸡国际服服务器 浏览:340
钢筋工焊接需要加密吗 浏览:797
servu服务器ip地址怎么查看 浏览:901
西红柿解压球里装的是什么 浏览:482
多位数口算法 浏览:906
收二手安卓手机测机软件用什么 浏览:648
口袋写作app在哪里看 浏览:113