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

中点直线生成算法qt

发布时间:2023-05-13 01:38:26

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

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

❷ 图形学中的中点画线法与Bresenham算法画线的区别

个人认为最关键的区别就是那个决策参数的计算方式!
在Bresenham算法中,假设我们在(x0,y0)处画了一个点,那我们就要决定下一个点是在(x0+1,y0)还是在(x0+1,y0+1)处画,这两个点一般都不在直线上,我们要计算这两个点离直线有多远,分别设两个点离直线的距离为p1、p2,然后决策参数就是p=p2-p1,再根据p的符号来判断选择哪个点
至于中点法,我没有用它来画过直线,只用来画过圆(自我感觉画圆用这个算法比Bresenham算法要好很多),但原理应该差不多!
在中点算法中,决策参数的就是方式就是圆的方程(换成直线就是直线的方程了),比如要画x^2+y^2=r^2的圆,那决策参数p=x^2+y^2-r^2,然后就不是代入上面找到的两个点直接代进去,而是代这两个点的中点进去,求出p的值,根据p的符号来判断那个中点是在圆上、圆内还是圆外,再进一步决定选择绘哪个点!
具体的计算过程没办法在这里完整演示,但个人认为不同之处还是在于决策参数的选择与计算

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

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

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

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

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

❹ 直线扫描算法(个人总结,仅供参考)

直线扫描算法主要包含三种算法,DDA算法、中点画线算法、Bresenham直线算法。

这三种算法都要事先要确定两个端点(起点和终点),从起点开始每次走一步,每走一步画一个点,直至到达终点。

这个前提也比较好理解,因为如果朝斜率大的方向走,可能没走几步就走完了,那画出来的直线就是离散的。

以下我们宏隐只讨论朝x方向移动的情况。(y方向的情况是一样的)

DDA算法实际上是根据 斜截式直线方程 来画的。

但这么做实际上是比较消耗性能的,因为斜截式方程, 它涉及到了乘法运算 。因此我们需要通过 增量思想 对它进行优化。

这样转换后,我们就可以根据当前的位置来找到下一步的位置,且每次计算只需要进行一次 浮点的加法运算 ,一次四舍五入取整即蔽历厅可。

中点画线算法实际上是根据 一般式直线方程 来画的。它是通过判断中点在直线的下方还是上方,来决定下一步的坐标位置。

但这样也是非常消耗性能的,把中点带入F(x, y)中,会涉及到2个乘法,4个加法。我们依然可以通过增量的方式来对它进行优化。

这样我们就优化到每次只需要一次 整数加法 即可,且还不需要四舍五入。因此它要更优于DDA算法。

Breseham算法是通过比较d(交点与交点下方最近的点的距离)来进行选择的。d每次按照k的大小增加。

但这么做依旧和DDA算法一样,会涉及到浮点数k的加法。我们可以通过 换元的方式 对它进行下优化。

这样就能使得每次进行一次或两次的 整数加法运算 ,不需要四舍五入。效率高于DDA,低于中点画线算法。

但Bresenham算法不依赖直线方程,使得它能有更宽泛烂中的适用范围。

❺ 求中点画线算法的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算法的运算速度很快。

❼ 利用C语言编写 能够画出任意斜率的直线算法程序(利用中点画线法改编)

将DDA算法改成中点划线算法即可
// DDA画线View.cpp : implementation of the CDDAView class
//

#include "stdafx.h"
#include "DDA画线.h"

#include "DDA画线Doc.h"
#include "DDA画线View.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDDAView

IMPLEMENT_DYNCREATE(CDDAView, CView)

BEGIN_MESSAGE_MAP(CDDAView, CView)
//{{AFX_MSG_MAP(CDDAView)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDDAView construction/destruction

CDDAView::CDDAView()
{
// TODO: add construction code here

}

CDDAView::~CDDAView()
{
}

BOOL CDDAView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs

return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CDDAView drawing

void CDDAView::OnDraw(CDC* pDC)
{
CDDADoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
int xx,yy,x2,y2,m,n;
float dx,dy,k,x,y;
int x0=50,y0=500,x1=50,y1=50;
if(x0>x1)
{
m=x0;x0=x1;x1=m;
m=y0;y0=y1;y1=m;
}
dx=x1-x0;
dy=y1-y0;
k=dy/dx;
if(x0==x1)
{
if(y0>y1)
{
n=y0;
y0=y1;
y1=n;
}
for(y2=y0;y2<=y1;)
{
for(n=-10;n<11;)
{
pDC->SetPixel(x0+n,y2,255);
n++;
}
y2=y2+3;
}

}
if(k>=-1&&k<=1.0)
{
y=y0;
for(x2=x0;x2<=x1;)
{
yy=(int)(y+0.5);
for(n=-10;n<11;)
{
pDC->SetPixel(x2,yy+n,255);
n++;
}
y=y+k;
x2++;
}
}
else if(k>1)
{
x=x0;
k=dx/dy;
for(y2=y0;y2<=y1;)
{
xx=(int)(x+0.5);
for(n=-10;n<11;)
{
pDC->SetPixel(xx+n,y2,255);
n++;
}
x=x+k;
y2++;
}
}
else if(k<-1)
{
x=x1;
k=dx/dy;
for(y2=y1;y2<=y0;)
{
xx=(int)(x+0.5);
for(n=-10;n<11;)
{
pDC->SetPixel(xx+n,y2,255);
n++;
}
x=x+k;
y2++;
}

}
// TODO: add draw code for native data here
}

/////////////////////////////////////////////////////////////////////////////
// CDDAView printing

BOOL CDDAView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}

void CDDAView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}

void CDDAView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CDDAView diagnostics

#ifdef _DEBUG
void CDDAView::AssertValid() const
{
CView::AssertValid();
}

void CDDAView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}

CDDADoc* CDDAView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDDADoc)));
return (CDDADoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CDDAView message handlers

阅读全文

与中点直线生成算法qt相关的资料

热点内容
传奇源码分析是什么 浏览:267
解放压缩机支架 浏览:255
程序员秃顶搞笑相遇 浏览:6
IBM手机app商店叫什么名字 浏览:834
jpeg压缩质量 浏览:774
云服务器评测对比 浏览:145
java日期转string 浏览:221
openfire源码编译 浏览:897
在线小工具箱引流网站源码 浏览:337
非科班程序员自学 浏览:799
压缩泡沫鞋底底材 浏览:219
程序员职场第一课2正确的沟通 浏览:679
遇到不合法app应该怎么办 浏览:90
汇编程序编译后的文件 浏览:79
大智慧均线源码 浏览:373
单片机排阻的作用 浏览:215
滴滴金融app被下架如何还款 浏览:212
jpg转换成pdf免费软件 浏览:744
范里安pdf 浏览:447
伪造pdf 浏览:79