基本图形的生成

一、直线

数学上,理想的直线是由无数个点构成的集合,没有宽度。

 计算机绘制直线是在显示器所给定的有限个像素组成的矩阵中,确定最佳逼近该直线的一组像素,并且按扫描线顺序,对这些像素进行写操作,实现显示器绘制直线,即通常所用说直线的扫描转换,或称直线光栅化。 
        由于一图形中可能包含成千上万条直线,所以要求绘制直线的算法应尽可能的快。
        一个像素宽直线的常用算法:数值微分法(DDA)、中点画线法、Bresenham算法。 

    1.DDA 数值微分法
        a.原理
            

 


注:此图把计算机像素抽象成了数学坐标系中的点。

 

如图1-1所示,已知过端点的直线段 p0 -- p1;
x方向距离为yDis = p1.y - p0.y;
y方向距离为xDis = p1.x - p0.x;
直线斜率为k = (yDis ) / (xDis ) ;
最大步长为nMaxStep = max(abs(xDis), abs(yDis));

        b.C++代码
void CSimpleGraphicsView::OnDda() 
{
// TODO: Add your command handler code here
CDC *pdc = GetDC();
POINT ptBeg, ptEnd;
COLORREF color = RGB(0, 0, 255);
ptBeg.x = 10;
ptBeg.y = 10;
ptEnd.x = 200;
ptEnd.y = 200;
long xDis = ptEnd.x - ptBeg.x;
long yDis = ptEnd.y - ptBeg.y;
long maxStep = max(abs(xDis), abs(yDis));
double xUnitLen = xDis / maxStep;
double yUnitLen = yDis / maxStep;
pdc->SetPixel(ptBeg, color);
double x, y;
x = ptBeg.x;
y = ptBeg.y;
/*
按照MSDN直线定义:
A line is a set of highlighted pixels on a raster display 
(or a set of dots on a printed page) identified by two points: 
as tarting point and an ending point. 
The pixel located at the starting point is always included in the line, 
and the pixel located at the ending point is always excluded. 
(This kind of line is sometimes called inclusive-exclusive.) 
不需要画终点的像素。所以循环范围为maxStep - 1.
*/
for(long i = 1; i < maxStep; i++)
{
x += xUnitLen;
y += yUnitLen;
pdc->SetPixel((int)x, (int)y, color);
}
ReleaseDC(pdc);
}

2.中点画线法
        a.原理
            

 


 

在画直线段的过程中,当前像 素点为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; 
注:-b/a 为直线的斜率,保证其比例不变的情况下,可以认为a=y0 - y1, b = x1 - x0;
点与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为下一个像素; 

        b.C++代码
void CSimpleGraphicsView::OnMidpoint() 
{
	// TODO: Add your command handler code here
	CDC *pdc = GetDC();
	COLORREF color = RGB(0, 255, 255);
	int a,b,d,d1,d2,x,y;
	a = ptBeg.y - ptEnd.y;
	b = ptEnd.x - ptBeg.x;
	d = 2 * a + b;
	d1 = 2 * a;
	d2 = 2 * (a + b);
	x = ptBeg.x;
	y = ptBeg.y;
	pdc->SetPixel(x, y, color);
	int xUnitLen = (ptBeg.x < ptEnd.x) ? 1 : -1;
	int yUnitLen = (ptBeg.y < ptEnd.y) ? 1 : -1;
	while(x < ptEnd.x)
	{
		TRACE("d %d\n", d);
		
		if(d < 0)
		{
			d += d2;
			x += xUnitLen;
			y += yUnitLen;
		}
		else
		{
			d += d1;
			x += xUnitLen;
		}
		pdc->SetPixel(x, y, color);
	}
	ReleaseDC(pdc);
}
注:此代码只适合直线斜率在-1 ~ 0之间的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值