开源2D图形库AGG研究(一)

      AGG(Anti-Grain Geometry),强大的2D几何图形库。因为GDI+的一些缺陷(不能跨平台,某些应用场合精度差),我一直在寻求可以替换gdi+绘图组件的方案,最终我选择了AGG,提供亚像素精度显示效果,反锯齿效果超好,跨平台,代码精致亦适合嵌入式开发。网上关于2D图形库的组件非常多,类似的还有GOOGLE PICASSO,CAIRO(firefox底层采用的渲染器),QT,OpenGL等等。从易用性的角度来说AGG比较困难,因为官方只给出了C++源代码,没有组件库和封装好的包,其他语言要想直接用是不可能了。从网上关于使用效果的评论来说,AGG是最高效,跨平台最好的。

      起初学习是从看中文档开始的,在网上有写得比较好的文章(目前最全面的),题目是<<用AGG实现高质量图形输出>>。如果按照文章大致做下来就能对AGG有一个初步了解。参考上述文章,自己动手做一下,感觉稍微能熟悉些,不然直接看源码或英文文档比较累。现在是边用边看源码,翻翻原始文档,感觉学习效率会高一些。因为以前专门写过一段时间的GIS数据格式解析有一定基础(要是参考AGG就好了),再过来看AGG源码,还是比较过瘾的,其间有很多数据结构的写法其实也适用于GIS(例如各种图形对象如何用程序表达)。在我看来AGG的代码结构非常清晰和优美,源码使用C++模版中规中矩(本人非常不赞成奇技淫巧式的C++变态语句)。

      什么样的人适合使用AGG类库?稍微有点计算机图形学基础,但是比较熟悉C++的人适合上手。其实一般的开发基本用不上AGG类库,因为太多人去搞应用开发,很少人会关注绘图质量,图像变换的底层实现了。AGG的绘图质量的确很好,在用户列表中有PDFNet,该公司的SDK产品被AutoDesk公司采用了,而此SDK的底层就是采用的AGG图形库。AGG类库非常用于图形学实践,熟悉了源码可以自己在现有类的基础上进行扩展。

      介绍了这么多AGG背景,开始学习使用AGG吧。第一步,Hello World ?不,我们需要下载源码。目前最新版本是2.5在以下网址下载 http://www.antigrain.com/download/index.html。下载后直接解压,文件夹中罗列了一堆的.cpp、.h文件。当然我们的开发环境是VC6.0,所以我们下载的是Windows版本。

     1、VC6.0下新建一个Windows Console工程,名称随便起,姑且叫AggTest.

     2、关键步骤,设置AGG类库的引用,最野蛮和最有效的方式把Include下的.h文件连同其下文件夹全部拷贝到VC6安装目录下的Microsoft Visual Studio/VC98/Include文件夹中,把解压目录中的src文件夹下的cpp文件都添加到AggTest工程中。

    3、拷贝如下代码到你的AggTest.cpp文件中

         #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_u.h" #include "agg_renderer_scanline.h" #include "agg_pixfmt_rgb.h" #include "platform/agg_platform_support.h" #include "agg_ellipse.h" #include "agg_conv_contour.h" #include "agg_conv_stroke.h" #include "agg_conv_marker.h" #include "agg_arrowhead.h" #include "agg_path_storage.h" #include "agg_vcgen_markers_term.h" #include // conv_stroke #include // conv_dash #include // conv_marker #include // conv_curve #include // conv_contour #include // conv_smooth_poly1.h #include // conv_bspline #include // conv_transform class the_application : public agg::platform_support { public: the_application(agg::pix_format_e format, bool flip_y) : agg::platform_support(format, flip_y) { } virtual void on_draw() { //Rendering Buffer //用于存放像素点阵数据的内存块,这里是最终形成的图像数据 agg::rendering_buffer &rbuf = rbuf_window(); agg::pixfmt_bgr24 pixf(rbuf); // Renderers typedef agg::renderer_base renderer_base_type; //底层渲染器 renderer_base_type renb(pixf); // typedef agg::renderer_scanline_aa_solid renderer_scanline_type; //高层渲染器 typedef agg::renderer_scanline_bin_solid renderer_scanline_type; //高层渲染器 renderer_scanline_type rensl(renb); /* // Vertex Source //agg::ellipse ell(100,100,50,50); //顶点源,里面存放了一堆2D顶点以及对应的命令,这个顶点源呈现的是一个圆形 agg::triangle ell(100,100,50); // Coordinate conversion pipeline //坐标转换管道,它可以变换Vertex Source中的顶点,比如矩阵变换,轮廓提取,转换为虚线等。 //typedef agg::conv_contour ell_cc_type; //扩展轮廓线 typedef agg::conv_contour ell_cc_type; ell_cc_type ccell(ell); typedef agg::conv_stroke ell_cc_cs_type; //只显示轮廓线 ell_cc_cs_type csccell(ccell); */ // Vertex Source agg::ellipse ell(0,0,50,50); // 圆心在中间 // Coordinate conversion pipeline agg::trans_affine mtx; // trans_affine不 仅仅用于源顶点的变换,在AGG库中有不少地方都能看到它 mtx.scale(0.5,1); // x轴缩小到原来的一半 mtx.rotate(agg::deg2rad(30)); // 旋转30度 mtx.translate(100,100); // 平移100,100 typedef agg::conv_transform ell_ct_type; ell_ct_type ctell(ell, mtx); // 矩阵变换 typedef agg::conv_contour ell_cc_type; ell_cc_type ccell(ctell); // 轮廓变换 typedef agg::conv_dash ell_cd_type; ell_cd_type cdccell(ccell); cdccell.add_dash(5,5); typedef agg::conv_stroke ell_cc_cs_type; // ell_cc_cs_type csccell(ccell); // 转换成多义线 ell_cc_cs_type csccell(cdccell); // csccell.width(3); // Scanline Rasterizer //把顶点数据(矢量数据)转换成一组水平扫描线,扫描线由一组线段(Span)组成,线段(Span)包含了起始位置、长度和覆盖率(可以理解为透明度)信息。AGG的抗锯齿(Anti-Aliasing)功能也是在这时引入的。 agg::rasterizer_scanline_aa<> ras; agg::scanline_u8 sl; // Draw renb.clear(agg::rgba8(255,255,255)); // renb.clip_box(30,30,160,160); // 设置可写区域 for(int i=0; i<5; i++) { ccell.width(i*20); ras.add_path(csccell); rensl.color( agg::rgba8(0,0,i*50)); // agg::render_scanlines(ras,sl,rensl); agg::render_scanlines_aa_solid(ras,sl,renb,agg::rgba8(0,0,i*50)); } agg::path_storage ps; ps.start_new_path(); ps.move_to(200,60); ps.line_to(400,100); ps.line_to(300,140); ps.end_poly(); agg::conv_stroke csps(ps); ras.add_path(csps); agg::render_scanlines_aa_solid(ras,sl,renb,agg::rgba8(0,0,0)); /* agg::arrowhead ah; ah.head(0,10,5,5); ah.tail(10,10,5,5); // 用path_storage生成一条直线 agg::path_storage ps; ps.move_to(160,60); ps.line_to(100,100); // 转换 agg::conv_stroke csps(ps); agg::conv_marker arrow(csps.markers(), ah); // 画线 ras.add_path(csps); agg::render_scanlines_aa_solid(ras,sl,renb,agg::rgba8(0,0,0)); // 画箭头 ras.add_path(arrow); agg::render_scanlines_aa_solid(ras,sl,renb,agg::rgba8(255,0,0)); agg::triangle t(100,100,50);//自定义顶点源 agg::conv_smooth_poly1_curve cspct(t); ras.add_path(cspct); agg::render_scanlines_aa_solid( ras,sl,renb,agg::rgba8(255,0,0)); for(int j=0; j<20; j++) pixf.blend_vline(50+j,20,100,agg::rgba(j/20.0,0,0),128); agg::int8u* p = rbuf.row_ptr(20);//得到第20行指针 memset(p,0,rbuf.stride_abs());//整行以0填充 */ } }; int agg_main(int argc, char* argv[]) { the_application app(agg::pix_format_bgr24, false); app.caption("AGG Example. Anti-Aliasing Demo"); if(app.init(600, 400, agg::window_resize)) { return app.run(); } return -1; }

      4、编译,当然通不过,你懂的。第一步,如果还有文件(如agg_platform_support.cpp)没有找到,你需要添加到工程中。第二步,报错后,看看是不是有两处地方没有修改,stdafx.h是不是注释掉了(纯C++么);是不是按下图设置了VC6下.cpp的设置。

      5、这下终于可以编译通过了,恭喜你程序上可以看到如下内容:

 

 

      环境配置还是比较简单的,能够成功运行的程序是对我们极大的鼓励下,后续我们开始研究代码。

     

    

你可能感兴趣的:(开源类库AGG,GIS制图)