1、VC 中矢量图形快速重画的技巧【摘要】本文介绍了 VC6.0 用 OnDraw() 函数对视图进行重画的原理,并提出了一种通过图形元素的边界矩形对矢量图形快速重画的方法。 【关键词】矢量,边界矩形,OnDraw() 函数 我们用 VC6.0 开发环境对小型矢量图形系统进行开发。在图形放大、缩小、删除、添加图形元素、重画上屏等操作时,要不断地对图形进行重画。虽然计算机运行速度越来越快,但对一个复杂的矢量图形来说,图形显示一次也要花费大量时间。尤其对于绘图函数,即使是画一条直线的 LineTo 函数都要花费大量时间计算出应该显示的像素位置,才能实现对每个像素的显示。所以在开发矢量图形软件时应尽可能
2、采取好的算法提高图形的重画速度。 一、激活视图重画的基本方法 所谓图形重画,就是把当前视图屏幕重新绘制一次,也就是让视图类的 OnDraw(CDC* pDC) 函数重新执行一次。OnDraw 函数是被 Cview类的消息处理函数 OnPaint 调用的。在 MFC 中 OnPaint 函数的实现代码如下: void Cview: OnPaint() CpaintDC dc(this) ; OnPrepareDC(&dc) ; OnDraw(&dc) ; OnPaint 函数是窗口消息 WM_PAINT 的消息处理函数,WM_PAINT 的消息处理函数是当窗口失效或完整性受到破坏时发出的一个窗口
3、消息。要使视图屏幕重新绘制就要激活视图的绘制机制,有两种方法可实现这个功能: 1、在视图类函数的实现代码中,加入以下代码来激活重画机制: CDrawDoc *pDoc=GetDocument() ; pDoc-UpdateAllViews(this) ; UpdateAllViews 函数使属于当前文档对象的所有视图屏幕客户区失效重画。如果应用程序采用单文档结构,此时系统只有一个视图,执行此命令时激发视图类的 OnDraw 函数重新执行来完成重画。如果应用程序采用多文档结构,一个文档具有多个视图,UpdateAllViews 函数可使属于当前文档对象的所有视图都重新绘制。 2、加入 Inval
4、idate()函数使当前视图屏幕客户区失效从而激活图形重画。Invalidate 函数与 UpdateAllViews 函数的不同点是前者只能使当前视图重画而与其同文档的其他视图并不重画。 二、提高图形重画速度的基本算法 因为矢量图形具有无极放缩的功能,一般情况下并不是所有图形元素都能够显示到屏幕上(除非在显示全图状态) ,而上述的图形重画机制是把所有图形元素不管在屏幕内还是在屏幕外都进行了绘制。为解决这个问题,一个基本的方法就是在显示一个图形前对每个图形元素进行判断,看这个图形元素是否在视图屏幕中,如果不在当前视图屏幕中就不对这个图形元素进行绘制来节省绘制时间。我们通过判断图形元素当前视图屏
5、幕矩形是否相交来判断图形元素是否在视图屏幕中。一般采用这个图形元素的边界矩形和视图屏幕边界矩形是否相交的方法。 三、提高图形重画速度的程序实现 1、得到视图屏幕边界矩形坐标 我们为这个应用程序命名为 Draw。通过以上分析我们首先要得到视图屏幕边界矩形坐标。这里我们定义四个全局浮点变量xMinScreen,yMixScreen,xMaxScreen,yMaxScreen 来传递绘制视图的左下角和右上角的实际坐标。这四个全局变量在每次调用 OnDraw 函数实现视图的绘制前被初始化。在绘制函数 CDrawView:OnDraw(CDC* pDC)中加入代码实现在每次绘制前得到视图屏幕边界的实际坐
6、标: 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、得到各图形元素的边界矩形 一般来说
7、简单图形元素主要包括直线、连续直线、多边形、圆形、圆弧、标注文本等。下面分别介绍如何得到其边界矩形。 直线的边界矩形就是以直线的两个顶点为对角顶点的矩形。在直线类中加入其函数的实现代码。 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) ; /计算并
8、返回最大 y 值 多边形可看作封闭的连续直线因此连续直线和多边形可作为同一类图形元素处理。连续直线(或多边形)的边界矩形就是它所有顶点的最小和最大坐标。在连续直线(或多边形)类中加入其函数的实现代码。 void CPline:GetRect (float *minX, float *minY, float *maxX, float *maxY) float x1,y1,x2,y2; /用第一个顶点的坐标初试化变量 x1=m_PointList0.x; x2=m_PointList0.y; y1=m_PointList0.x; y2=m_PointList0.y; / m_PointList 为
9、存储多边形顶点坐标的数组 for(int i=1;ixMaxScreen | maxxyMaxScreen | maxyyMinScreen) return 0; /如不相交函数返回 0 else return 1; /如果相交就返回 1 函数的四个参数是边界矩形区域的左下角(minx,miny)和右下角(maxx,maxy)的实际坐标。最后把判断结果加入到各类图形元素的绘制函数中使其能够先判断图形元素的边界矩形是否与屏幕区域相交来决定是否对图形元素进行绘制。以直线类 CLine 为例在其函数DrawLine()中加入以下代码: void DrawLine(CDC *pDC,int m_Dra
10、wMode,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 2Microsoft Corporation 著,欣力等译.Win32 程序员参考大全(二)M.北京:清华大学出版社,1995.