基于Windows GDI+的几何线条处理

基于Windows GDI+的几何线条处理

徐歆恺  梁博  葛庆平

首都师范大学信息工程学院,北京100044

摘要 介绍了GDI+对几何线条创建、应用等基本方法,并以实例的方式对其中难于理解的部分提供了示例代码,实现了原先GDI不易实现的功能,并为进一步利用GDI+进行更复杂的图形处理奠定了良好的基础。

关键词 GDI+ ;几何线条

1 引言

GDI+是原Windows GDI的扩展,增加了新功能并对原功能模块进行了优化,使编程人员更易实现多种高级功能。因GDI+的强大功能及其完美的性能,微软倡导新应用程序的开发基于GDI+进行。[1]

所谓路径,是指可以被填充的、画出轮廓或同时被画出轮廓并填充的一个或多个图形。路径的引入,大大地丰富了Windows的图形功能,使得应用程序可以方便地建立复杂区域,绘制和填充不规则图形。[2]

路径一般由以下元素组成:直线、矩形、椭圆、圆弧、多边形、三次样条和贝塞尔曲线。在GDI+中,几何线条的处理主要是通过调用图形路径(GraphicsPath)的方法来实现的。使用GraphicsPath对象可以将这些元素收集到一个单元中。以后只需调用Graphics类的DrawPath方法,就可以一次绘制出该对象收集的全部元素序列。[3]

2 编程方法与实例

2.1 准备工作

使用GDI+编程,必须包含gdiplus.h头文件,要使用Gdiplus名称空间,连接时需要Gdiplus.lib。使用GDI+绘制对象时需要获取一个设备描述表句柄,把它作为参数传递给Graphics的构造函数,这样就可以使用Graphics对象的库函数了。[4]

使用GDI+编程必须在创建GDI+对象前执行GdiplusStartup实现初始化,在程序结束时调用GdiplusShutdown关闭GDI+功能,清理占用的资源。两组函数要成对调用。[1]

示例代码如下所示:

//---------------------------stdafx.h文件中-----------------------------------//

#include "Gdiplus.h"

using namespace Gdiplus ;

#pragma comment (lib, "Gdiplus.lib")

//----------------------在应用程序类的InitInstance函数中-----------------------//

GdiplusStartupInput     gdiplusStartupInput ;

GdiplusStartup (&m_GdiplusToken, &gdiplusStartupInput, NULL) ;

//-----------------------在应用程序类的ExitInstance函数中---------------------//

GdiplusShutdown (m_GdiplusToken) ;

注:其中变量m_GdiplusToken应该是ULONG_PTR类型的全局变量,或者是应用程序类的成员变量

2.2 路径的创建

GraphicsPath类提供了许多创建路径元素的接口:AddArc(圆弧)、AddBezier(贝塞尔曲线)、AddBeziers(贝塞尔曲线序列)、AddClosedCurve(闭合的基数样条曲线)、AddCurve(基数样条曲线)、AddEllipse(椭圆)、AddLine(直线段)、AddLines(直线段序列)、AddPie(扇形)、AddPolygon(多边形)、AddRectangle(矩形)、AddRectangles(矩形序列)和AddString(字符串轮廓路径)。

1 MSDN中提供的路径的例子

2.3 子路径的添加和提取

GraphicsPath还可以包含多个图形,其中每一个图形被称为子路径(figures)。如果在GraphicsPath对象中使用了StartFigureCloseFigure函数,在这两个之后对路径所添加的线条都将构成一个的子路径。[5]这两个函数的区别是,StartFigure方法不闭合当前图形即开始一个新图形,而CloseFigure方法闭合当前图形并开始新的图形。

下面两段示例代码在路径中添加了两个条路径,前一条子路径由两条直线段组成,后一条子路径是一个圆形。两段代码不同的地方仅仅在于StartFigureCloseFigure函数的使用,因而它们的效果也不相同,如图2和图3所示。


//示例代码1----使用StartFigure

GraphicsPath path;

path.AddLine(100,100,100,150);

path.AddLine(100,150,150,150);

path.StartFigure();

path.AddEllipse(75,75,50,50);

Graphics g(hdc);

g.DrawPath(&Pen(Color::Black,1),&path);

//示例代码2----使用CloseFigure

GraphicsPath path;

path.AddLine(100,100,100,150);

path.AddLine(100,150,150,150);

path.CloseFigure();

path.AddEllipse(75,75,50,50);

Graphics g(hdc);

g.DrawPath(&Pen(Color::Black,1),&path);


                        

2 StartFigure效果          图3 CloseFigure效果

GDI+GraphicsPathIterator类完成了对路径的一个或多个子路径的描述、管理、测试等功能。GraphicsPathIterator能够从给定的路径中进行多种与子路径相关的操作。[5]

1 GraphicsPathIterator类常用成员函数

常用成员函数

功能描述

HasCurve

指示与此GraphicsPathIterator对象关联的路径是否包含曲线

NextSubpath

将此子路径移到指定的GraphicsPath对象中的下一子路径

Rewind

将此GraphicsPathIterator对象重绕到其关联路径的起始处

GetSubpathCount

获取路径中子路径的数目

2.4 路径的几何变形

GDI+提供的Matrix类封装表示几何变形的3×3仿射矩阵。通过设置Matrix对象,可以旋转、缩放、错切或平移GraphicsPath对象。

2 Matrix类常用成员函数

常用成员函数

功能描述

Rotate

相对于原点顺时针旋转指定角度

Scale

缩放操作

Shear

错切变换操作

Translate

平移操作

Reset

重置此Matrix对象,使其成为单位矩阵

以矩形为例,路径变形的示例代码如下:

Graphics g(hdc);

GraphicsPath path;

path.AddRectangle(Rect(40, 10, 200, 50));

g.DrawPath(&Pen(Color(255, 0, 0, 0),1), &path);     // 在应用变形矩阵之前绘制矩形

// 路径变形

Matrix matrix;

matrix.Rotate( 30.0f );   //旋转顺时针30

matrix.Scale( 0.5f , 0.5f );//缩小一半

path.Transform(&matrix);//应用变形

g.DrawPath(&Pen(Color(255, 0, 0,  0),3), &path);    // 3象素宽的粗线绘制变换后的矩形

4 矩形的旋转与缩放

类似的,用GraphicsPath类的Warp方法,可以对路径应用由一个矩形和一个平行四边形定义的扭曲变形。

2.5 路径的存储与读取

GraphicsPath 对象存储一系列直线和贝塞尔样条。尽管可以将若干种类型的曲线(椭圆、弧形和基数样条)添至路径,但在存储到路径中之前,各种曲线都会自动转化为贝塞尔样条。直线可以由起点和终点来构成,而贝塞尔样条曲线是由起点、终点和控制点定义。所以,对于一个路径的描述,可以通过对路径点信息的处理来实现。[4]

2.5.1   存储路径

GraphicsPath对象的存储过程中,有三个函数非常重要,那就是GetPointCountGetPathPointsGetPathTypes,利用这3个函数,可以获得路径中路径点的数目、坐标和类型。具体代码如下:

INT count = path.GetPointCount();          // 获得路径点数目

ar<<count;                                 // 存储路径点数目

dataPoints = new Point[count];       

path.GetPathPoints(dataPoints, count);     // 获得路径点坐标

pTypes = new BYTE[count];

path.GetPathTypes(pTypes, count);          // 获得路径点类型

//开始存储

for(INT i=0;i<count;i++){

ar<<dataPoints[i].X<<dataPoints[i].Y;     // 存储路径点坐标

ar<<pTypes[i];                            // 存储路径点类型

}

……………………

delete dataPoints;                         // 回收内存

delete pTypes;

2.5.2   读取路径

由于GraphicsPath类中只有构造函数才能由路径点创建,读取路径的方法就要复杂一些了。具体代码如下:

path.Reset();                              // 重置路径

INT count;

ar>>count;                                 // 读取路径点数目

dataPoints = new Point[count];             // 定义路径点坐标

pTypes = new BYTE[count];                  // 定义路径点类型

//开始读取

for(INT i=0;i<count;i++){

ar>>dataPoints[i].X>>dataPoints[i].Y;     // 读取路径点坐标

ar>>pTypes[i];                            // 读取路径点类型

}

GraphicsPath pa(dataPoints,pTypes,count);  // 由路径点创建临时路径pa

path.AddPath(&pa,false);                   // 将临时路径pa添加到路径path

……………………

delete dataPoints;                         // 回收内存

delete pTypes;

2.6 路径的线段逼近

调用GraphicsPath对象的Flatten方法,可以将路径中的曲线全部转换成多段相连的直线段,如图5所示,这种方法也被称为“拉平”或“展平”。Flatten方法接收拉平参数,该参数指定拉平的路径和原始路径之间的最大距离。

5 原始曲线路径与拉平后的路径(这里拉平参数为8.0

将路径拉平后,使用直线段长度累加的方法,可以轻易地计算出路径曲线的长度和其他信息,并可以通过降低拉平参数值的方法来提高计算的精度。由于路径点的坐标是以浮点数的形式保存的,因而用这种方式得到的曲线长度的精度还是相当高的。

3 结束语

GraphicsPath还有很多种用法,比如可以使用IsVisible方法判断坐标点是否落在路径上,使用IsOutlineVisible方法指示当使用指定的Pen对象绘制此GraphicsPath 对象时,指定点是否包含在后者的轮廓内。

从开发的实践过程来看,使用GDI+进行图形编程,比原先的GDI编程过程要容易很多,而且最终的图形功能也更强大。

参考文献

1、朱平军,庞雄奇,周海燕.基于GDI+VC图形的填充[J].计算机时代,2003年,(11):38-39.

2、周鸣扬.Visual C++界面编程技术[M].北京:北京希望电子出版社,2003.242-256.

3、李博轩.Visual C++.NET多媒体应用开发技术[M].北京:国防工业出版社,2002.31-41.

4、史晓峰,赵耀红.基本图像处理功能在GDI+中的实现方法[J].长春工程学院学报(自然科学版),200343):67-69.

5、周鸣扬.GDI+程序设计实例[M].北京:中国水利水电出版社,2004.189-233.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值