绘图图形库






4.95/5 (66投票s)
用于MFC项目中绘制数据(线条、地图等)的库

描述
PGL 是一个封装了绘图功能的库,适用于 MFC 项目,支持 VC6 和 VC7。它旨在无需任何外部软件即可轻松绘制项目中生成的数据。实际上,通过 CView 和 CDialog 派生类,您可以在 5 分钟内让您的应用程序显示图表。
PGL 的目标不是提供一个用户友好的环境,而是能够从源代码生成任何绘图。
PGL 最初使用 OpenGL 进行光栅图形渲染,但现在它使用 GDI+(因此您需要安装 Microsoft SDK 才能编译 PGL)。
许可
CodeProject 上的源代码根据 LGPL 许可。但是,后续版本将不再免费(哎呀,抱歉)。您可以在 PGL 官方主页 查看最新开发动态。无论如何,请享受精美的图表绘制。
特点
- 线带,完全可定制- 颜色 (RGBA)
- 线型
- 点类型(圆圈、方框、三角形等)
- 线宽
- 填充
- 线阴影
- 多条线带
- 等等。
 
- 具有细节层次 (LOD) 功能的线带(基于 Douglas-Peukler 线简化算法)
- 矢量地图
- 高度图
- 文本- 可变刻度
- 多种字体
- 方向可调
 
- 无限子图
- 自动坐标轴
- 时间标签
- 导出为 EPS, SVG, JPEG, TIFF, PNG
- 用于快速集成到现有项目的 CView派生类
- CDialog派生类等。
UML
UML 图可在此 PDF 文件 中找到。虽然不完整,但应该有助于您理解该库。
安装
以下是将 PGL 用于您项目的安装步骤
- 安装 GDI+(Microsoft SDK 的一部分)。
- 下载 Gdiplus.dll 并确保它在系统路径中。
- 重新编译源代码,将在 lib 目录中生成 .lib 文件,在 bin 目录中生成 .dll 文件。
- 将包含 PGL二进制文件的目录添加到您的系统路径中(默认情况下是 C:\Program Files\PGL\bin)。
- 将 include 目录和 lib 目录添加到 Visual C++ 的 include/lib 目录中。
- 确保头文件可用。
就是这样!
开始您的项目
- 在您的 StdAfx.h 文件中添加以下内容#include "PGL.h" 
- 	由于 PGL使用GDI+,您必须初始化它- 在您的 CWinApp派生类中添加以下变量ULONG_PTR m_ulGdiplusToken; 
- 在 CWinApp::OnInitInstance函数中添加以下内容以初始化GDI+// initialize <code>GDI+ (gdi+ is in Gdiplus namespace) Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_ulGdiplusToken, &gdiplusStartupInput, NULL);
- 在 CWinApp::OnExitInstance函数中添加以下内容以清理GDI+。// shutdown GDI+ Gdiplus::GdiplusShutdown(m_ulGdiplusToken); 
 
- 在您的 
您的项目现在应该可以正常工作了。
示例
所有这些示例都可以在源代码中找到。请参阅 TestPGL 的示例菜单。
示例 1:绘制简单线条
这是一个第一个解释性示例。我们假设线条的点 (x,y) 已经生成并存储在大小为 nPoints 的两个数组 pX,pY 中(请注意,您也可以将数据作为 std::vector<double> 传递给 PGL)。

以下是我用于生成数据的代码:一个简单的正弦曲线。请注意,y 的范围在 [-1.1, 1.1] 之间,但 PGL 会自动处理坐标轴标签,使其具有良好的单位。
// generate data
int nPoints = 50;
double* pX=new double[nPoints];
double* pY=new double[nPoints];
for (UINT i=0;i< nPoints;i++)
{
	pX[i]=i;
	pY[i]=sin(i/(double)nPoints*2*3.14)*1.1;
}
- 首先,创建一个图表对象CPGLGraph* pGraph = new CPGLGraph; 请注意,由于所有PGL对象都继承自CObject,您可以使用ASSERT_VALID来检查它们。
- 	创建一个 2D 线条 CPGLLine2D* pLine = new CPGLLine2D; 
- 	将数据附加到线条上。 PGL将在此之后处理内存。也就是说,它将在对象销毁时删除数据指针。这意味着pX,pY必须在堆上分配!pLine->SetDatas( nPoints /* number of points */, pX /* x(i) */, pY /* y(i) */);
- 	(可选)更改线条的某些属性: pLine->SetLineWidth(2);
- 将线条添加到图表中(请注意,一个对象只能添加到一个图表中)pGraph->AddObject(pLine); 
- 	让 PGL自动缩放绘图pGraph->ZoomAll(); 
- 	创建一个对话框并显示绘图 CPGLGraphBitDlg graphdlg(this, pGraph); graphdlg.DoModal(); 
您应该会看到与上面图像相同的结果。请注意,这张图像(PNG)是由 PGL 生成的。
示例 2:添加具有细节层次控制的线条
您可能需要绘制包含数千个点的线条。这可能会变得非常耗费资源,特别是当您将其导出为 EPS 时,文件可能会变得非常大。为了解决这个问题,您可以使用 PGL 中内置的带 LOD 的线条。

在此示例中,我们近似了上一条线。从上一个示例开始
- 更改代码行CPGLLine2D* pLine = new CPGLLine2D; to CPGLLine2DLOD* pLine = new CPGLLine2DLOD; 
- 更改细节层次的容差pLine->SetTol(0.05); 
- 按所需的压缩比缩小点的数量(此处为 10% 阈值为 2%)pLine->ShrinkNorm(0.1,0.02); 
在上图所示的图像中,您可以看到原始线和近似线。使用这种技术可以大大减少点的数量!
示例 3:自定义坐标轴、标签等
如上一张图像所示,对象的所有参数都可以通过代码进行更改。在此示例中,我们将
- 更改标题文本,
- 关闭水平网格,
- 显示右侧标签,
- 更改顶部坐标轴刻度的数量,
- 切换到 x 轴的时间标签,
- 以及更多...

我们从第二个示例开始,在调用 ZoomAll() 之前添加以下代码行。
- 获取坐标轴对象的指针(英文中有一个巨大的错误,但在法语中是正确的:(axe -> axis))CPGLAxe2D* pAxis = pGraph->GetAxe(); 
- 更改标题文本和颜色pAxis->SetTitle(str); 或pAxis->GetTitle()->SetString(str); pAxis->GetTitle()->SetColor(0 /* red */,0.5f /* green */, 0 /* blue*/ /* alpha optional */);
- 关闭垂直网格(垂直 -> 0,水平 -> 1)pAxis->SetShowGrid(1,FALSE); 
- 显示并更改右侧标签pAxis->GetRightLabel()->Show(TRUE); pAxis->GetRightLabel()->SetString("This is the right label");
- 显示右侧编号pAxis->GetRightNumber()->Show(); 
- 更改顶部坐标轴刻度的数量pAxis->SetTopSecondTicksNb(5); 
- 切换到 x 轴的时间标签// enable time labelling pAxis->SetTimeLabel(TRUE); // set origin, time step and format (see COleDateTime.Format for details) pAxis->SetTimeLabelFormat(COleDateTime::GetCurrentTime() /* Time at zero. */, COleDateTimeSpan(0,0,30,0) /* Time per unit */, "%H:%M:%S" /* String format */);
我还禁用了线条绘制,并将 LOD 线条的容差设置为 0.025。当然,您可以做得更多。这只是一个示例。
示例 4:子图!
如何在图形上放置多个绘图:这在 PGL 中有多种方式实现。事实上,您可以将绘图添加到绘图中,依此类推。

类 CPGLGraph 继承自一个通用的绘图类:CPGLRegion。您可以
- 使用函数 Divide(m,n)将区域分割成 m 行 n 列的数组(注意此方法会擦除区域中的所有对象)。之后,您可以通过GetChilds(i)访问子区域(子区域按行创建)。您可以使用GetNChilds()获取子区域的数量。// allocated somewhere CPGLRegion* pRegion; // dividing pRegion->Divide(m,n); // accessing region at row 2 and column 1 (zero based index) CPGLRegion* pChildRegion = pRegion->GetChild(2*n+1); 
- 直接创建并添加一个区域,使用 AddRegion。要使用此方法,您必须调用SetNormBBox(...)来设置边界框(以父区域的归一化坐标表示)。CPGLRegion* pChildRegion = pRegion->AddRegion(); pChildRegion->SetNormBBox(0.1 /* llx */ , 0.2 /* lly */ , 0.7 /* urx */ , 0.8 /* ury */);
当然,您可以分割子区域,依此类推。
示例 5:在运行时更改对象属性
您可以通过右键单击视图或对话框来探索对象层次结构。不幸的是,序列化尚未实现。所以之前的努力都白费了...

参考
文档是使用 Doxygen 和 Doxygen Studio 生成的。请参阅 Plot Graphic Library.dow 文件。否则,它会与 Microsoft Installer 一起提供。
下载
您可以在 PGL 官方主页 下载 Microsoft Installer。
编译源代码
提供了 PGL 的源代码。打开工作区
- 对于 VC6 用户,请打开 "Plot Graphic Library.dsw"
- 对于 VC7 用户,请打开 "Plot Graphic LibraryNET.dsw"
它包含 6 个项目
- AlgoTools。算法类集合。此项目包含线近似算法。
- IGfx。- PGL使用的图形库。多层图形接口,可导出为多种图形格式,如 EPS 或 SVG。
- IGfxTest。IGfx 的测试项目。
- OGLTools。用于在 Windows 中处理 OpenGL 的有用库。不再使用,但仍然有用。
- PGL。图形库。
- Testpgl。一个演示应用程序。
编译源代码。.lib 文件将位于 lib 目录中,DLL 文件将位于 bin 目录中。
历史
- 2002 年 11 月 6 日:添加了 VC7 构建,修复了一些问题并更新了 DPHull。
- 2002 年 7 月 15 日:修复了资源缺失问题,将 CP_THREAD_ACP更改为CP_ASP,修复了导出错误和文本条错误。
- 2002 年 6 月 5 日:更新了下载。
- 2002 年 3 月 29 日:重大更新!
- 2001 年 11 月 8 日:初始发布。


