VC中矢量图形快速重画的技巧

时间:2022-08-06 05:46:45

VC中矢量图形快速重画的技巧

【摘要】本文介绍了vc6.0用OnDraw() 函数对视图进行重画的原理,并提出了一种通过图形元素的边界矩形对矢量图形快速画的方法。

【关键词】矢量,边界矩形,OnDraw() 函数

我们用VC6.0开发环境对小型矢量图形系统进行开发。在图形放大、缩小、删除、添加图形元素、重画上屏等操作时,要不断地对图形进行重画。虽然计算机运行速度越来越快,但对一个复杂的矢量图形来说,图形显示一次也要花费大量时间。尤其对于绘图函数,即使是画一条直线的LineTo函数都要花费大量时间计算出应该显示的像素位置,才能实现对每个像素的显示。所以在开发矢量图形软件时应尽可能采取好的算法提高图形的重画速度。

一、激活视图重画的基本方法

所谓图形重画,就是把当前视图屏幕重新绘制一次,也就是让视图类的OnDraw(CDC* pDC) 函数重新执行一次。OnDraw函数是被Cview类的消息处理函数OnPaint调用的。在MFC中OnPaint函数的实现代码如下:

void Cview:: OnPaint()

{ CpaintDC dc(this);

OnPrepareDC(&dc);

OnDraw(&dc);

}

OnPaint函数是窗口消息WM_PAINT的消息处理函数,WM_PAINT的消息处理函数是当窗口失效或完整性受到破坏时发出的一个窗口消息。要使视图屏幕重新绘制就要激活视图的绘制机制,有两种方法可实现这个功能:

1、在视图类函数的实现代码中,加入以下代码来激活重画机制:

CDrawDoc *pDoc=GetDocument();

pDoc->UpdateAllViews(this);

UpdateAllViews函数使属于当前文档对象的所有视图屏幕客户区失效重画。如果应用程序采用单文档结构,此时系统只有一个视图,执行此命令时激发视图类的OnDraw函数重新执行来完成重画。如果应用程序采用多文档结构,一个文档具有多个视图,UpdateAllViews函数可使属于当前文档对象的所有视图都重新绘制。

2、加入Invalidate()函数使当前视图屏幕客户区失效从而激活图形重画。Invalidate函数与UpdateAllViews函数的不同点是前者只能使当前视图重画而与其同文档的其他视图并不重画。

二、提高图形重画速度的基本算法

因为矢量图形具有无极放缩的功能,一般情况下并不是所有图形元素都能够显示到屏幕上(除非在显示全图状态),而上述的图形重画机制是把所有图形元素不管在屏幕内还是在屏幕外都进行了绘制。为解决这个问题,一个基本的方法就是在显示一个图形前对每个图形元素进行判断,看这个图形元素是否在视图屏幕中,如果不在当前视图屏幕中就不对这个图形元素进行绘制来节省绘制时间。我们通过判断图形元素当前视图屏幕矩形是否相交来判断图形元素是否在视图屏幕中。一般采用这个图形元素的边界矩形和视图屏幕边界矩形是否相交的方法。

三、提高图形重画速度的程序实现

1、得到视图屏幕边界矩形坐标

我们为这个应用程序命名为Draw。通过以上分析我们首先要得到视图屏幕边界矩形坐标。这里我们定义四个全局浮点变量xMinScreen,yMixScreen,xMaxScreen,yMaxScreen来传递绘制视图的左下角和右上角的实际坐标。这四个全局变量在每次调用OnDraw函数实现视图的绘制前被初始化。在绘制函数CDrawView::OnDraw(CDC* pDC)中加入代码实现在每次绘制前得到视图屏幕边界的实际坐标:

void CDrawView::OnDraw(CDC* pDC)

{

CDrawDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

xMixScreen=xStart; //(xStart,yStart)为图形屏幕坐下角点的实际坐标

yMixScreen=yStart;

xMaxScreen=xMixScreen+blc*wScreen; //变量blc为逻辑坐标与实际坐标的比例关系

yMaxScreen=yMixScreen+blc*hScreen; //wScreen,hScreen为当前视图的高度和宽度

}

2、得到各图形元素的边界矩形

一般来说简单图形元素主要包括直线、连续直线、多边形、圆形、圆弧、标注文本等。下面分别介绍如何得到其边界矩形。

直线的边界矩形就是以直线的两个顶点为对角顶点的矩形。在直线类中加入其函数的实现代码。

void CLine::GetRect(float *minX, float *minY, float *maxX, float *maxY)

{

*minX=min(m_X1,m_X2); //计算并返回最小x值

*maxX=max(m_X1,m_X2); //计算并返回最大x值

*minY=min(m_Y1,m_Y2); //计算并返回最小y值

*maxY=max(m_Y1,m_Y2); //计算并返回最大y值

}

多边形可看作封闭的连续直线因此连续直线和多边形可作为同一类图形元素处理。连续直线(或多边形)的边界矩形就是它所有顶点的最小和最大坐标。在连续直线(或多边形)类中加入其函数的实现代码。

void CPline::GetRect(float *minX, float *minY, float *maxX, float *maxY)

{

float x1,y1,x2,y2; //用第一个顶点的坐标初试化变量

x1=m_PointList[0].x; x2=m_PointList[0].y;

y1=m_PointList[0].x; y2=m_PointList[0].y;

// m_PointList为存储多边形顶点坐标的数组

for(int i=1;i

{

x1=min(x1,m_PointList[i].x); //得到最小x坐标

x2=max(x2,m_PointList[i].x); //得到最大x坐标

y1=min(y1,m_PointList[i].y); //得到最小y坐标

y2=max(y2,m_PointList[i].y); //得到最大y坐标

}

*minX=x1;*maxX=x2;*minY=y1;*maxY=y2; //将值赋给地址返回

}

圆的边界矩形就是一个中心在圆心,边长等于圆直径的矩形。在圆形类中加入其函数的实现代码。

void CCircle::GetRect(float *minX, float *minY, float *maxX, float *maxY)

{

*minX=m_CircleX-m_CircleR; //得到并返回最小x值

*minY=m_CircleY-m_CircleR; //得到并返回最大x值

*maxX=m_CircleX+m_CircleR; //得到并返回最小y值

*maxY=m_CircleY+m_CircleR; //得到并返回最大y值

}

圆弧边界矩形的计算方法稍微复杂一些。圆弧的边界矩形主要由以下三个特征点决定:即圆弧的起点、终点以及圆弧中点。圆弧中点可由圆弧的起点、终点及圆心来确定。标注文本边界矩形的计算方法比较简单,每一行标注文本本身就在一个四边形内。若文本进行了旋转,可根据角度得到四边形的四个顶点坐标,通过比较即可得到标注文本的边界矩形。

对于其它类别的图形元素,可根据这些图形元素的几何特征,参考以上介绍的各种计算边界矩形的方法实现计算其边界矩形的函数。

四、判断图形边界矩形与视图屏幕边界矩形的关系

以上我们已经计算出了视图屏幕边界矩形和各图形元素的边界矩形,为判断两矩形是否相交定义了一个全局函数:BOOL RectCross()函数,返回值为布尔型。函数实现代码如下:

BOOL RectCross(float minx,float miny,float maxx,float maxy)

{

if (minx>xMaxScreen || maxxyMaxScreen || maxy

return 0; //如不相交函数返回0

else

return 1; //如果相交就返回1

}

函数的四个参数是边界矩形区域的左下角(minx,miny)和右下角(maxx,maxy)的实际坐标。最后把判断结果加入到各类图形元素的绘制函数中使其能够先判断图形元素的边界矩形是否与屏幕区域相交来决定是否对图形元素进行绘制。以直线类CLine为例在其函数DrawLine()中加入以下代码:

void DrawLine(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor);

{

void GetRect(float *minX, float *minY, float *maxX, float *maxY ); //得到边界矩形的函数

if (RectCross(float minX,float minY,float maxX,float maxY)) //判断是否相交

{绘制图形元素程序略;

else return;

}

};

对于其它图形元素类,同样在其绘制函数中加入类似的代码不再一一列出。

参考文献:

[1]陈建春. Visual C++开发GIS系统—开发实例剖析.电子工业出版社[M].北京,2000.9

[2]Microsoft Corporation著,欣力等译.Win32程序员参考大全(二)[M].北京:清华大学出版社,1995.

上一篇:新型轻钢龙骨结构厂房与门钢结构厂房用钢量比... 下一篇:基于asp.net物流系统