AGG高质量图形输出 下载本文

VertexSource VS; //其它顶点源

// 使用顶点转换器,并指定Markers类型为vcgen_markers_term

// 顶点转换器可以是conv_dash、conv_stroke或conv_marker_adaptor,见后文《坐标转换管道》

// vcgen_markers_term:以端点作为标记点

conv_stroke csVS(VS); ...draw_term

// 用conv_marker指定ah作为线段marker点的标记

conv_marker arrow(csVS.markers(), ah); ras.add_path(csVS);

ras.add_path(arrow); //marker要紧随其后加入 ...render

ah.head()和ah.tail()方法中的d1,d2,d3,d4参数的意义见下图

例,画一条简单的箭头直线(基于此处代码)

在on_draw()方法最后加上下列代码: ? 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));

得到的图形是:

注意要加头文件: #include \#include \#include \#include \

试验代码,自定义一个顶点源(基于此处代码)

为了对顶点源有更深入的了解,我们要自己实现一个顶点源,这个顶点源只是很简单的一个三角形。

前面说过,只要实现了 void rewind(unsigned path_id); 和 unsigned vertex(double* x, double* y); 方法就可以作为顶点源。

rewind方 法指示顶点源回到第一个顶点;vertex方 法取出当前顶点然后把当前顶点下移,返回值是当前顶点所带的命令。所谓的命令是一个enum path_commands_e类 型,定义如下:

?? enum path_commands_e

?? { ?? ?? ?? ??

path_cmd_stop = 0, //----path_cmd_stop path_cmd_move_to = 1, //----path_cmd_move_to path_cmd_line_to = 2, //----path_cmd_line_to path_cmd_curve3 = 3, //----path_cmd_curve3

?? path_cmd_curve4 = 4, //----path_cmd_curve4 ?? path_cmd_curveN = 5, //----path_cmd_curveN ?? path_cmd_catrom = 6, //----path_cmd_catrom ?? path_cmd_ubspline = 7, //----path_cmd_ubspline ?? path_cmd_end_poly = 0x0F, //----path_cmd_end_poly ?? path_cmd_mask = 0x0F //----path_cmd_mask ?? };

path_commands_e还 能和path_flags_e组 合: ?? enum path_flags_e

?? {

?? path_flags_none = 0, //----path_flags_none ?? path_flags_ccw = 0x10, //----path_flags_ccw ?? path_flags_cw = 0x20, //----path_flags_cw ?? path_flags_close = 0x40, //----path_flags_close ?? path_flags_mask = 0xF0 //----path_flags_mask ?? };

vertex()返回的命令中含有path_cmd_stop时 表示结束。 ?? // 等边三角形 ?? ?? ?? ?? ??

class triangle{ public:

triangle(double cx, double cy, double r)//中心点,r为中心点到边的长度 {

// 直接准备好三个点

?? m_step = 0;

?? m_pt[0].x = cx; m_pt[0].y = cy-r;

?? m_pt[1].x = cx+r*0.866; m_pt[1].y = cy+r*0.5; ?? m_pt[2].x = cx-r*0.866; m_pt[2].y = cy+r*0.5;

?? //AGG把方向作为区分多边形内部和外部的依据,可以试试m_pt[1]和m_pt[2]对调

?? }

?? void rewind(unsigned) ?? {

?? m_step = 0; ?? }

?? unsigned vertex(double* x, double* y) ?? {

?? switch(m_step++) ?? {

?? case 0:

?? //第一步,move_to ?? *x = m_pt[0].x; ?? *y = m_pt[0].y;

?? return agg::path_cmd_move_to; ?? case 1: ?? case 2:

?? //第二、三步,line_to ?? *x = m_pt[m_step-1].x; ?? *y = m_pt[m_step-1].y; ?? return agg::path_cmd_line_to; ?? case 3:

?? // 第四步,闭合多边形

?? return agg::path_cmd_end_poly|agg::path_flags_close; ?? default:

?? // 第五步,结束 ?? return agg::path_cmd_stop; ?? } ?? } ?? ?? ?? ??

private:

agg::point_d m_pt[3]; unsigned m_step; };

在on_draw()方法里把

agg::ellipse ell(100,100,50,50); 改成triangle ell(100,100,50);

typedef agg::conv_contour ell_cc_type;改成typedef agg::conv_contour ell_cc_type;

得到的图形是:

除了文字输出功能(gsv_text只能输出ASCII文字),上面这些顶点源提供的图形丰富程度已经超过了系统API。文字输出功能 将以单独的篇幅讲述。

Coordinate conversion pipeline 坐标转换管道

坐标转换管道用于改变顶点源产生的顶点,包括坐标、命令、产生新顶点等。如对顶点进行矩阵变换、插入顶点形成虚线之类的功能。

变换矩阵(trans_affine)

在认识转换管道之前,先了解一下AGG的变换矩阵。通过顶点坐标与矩阵的运行,我们可以得到新的坐标。关于图像的矩阵运算,MSDN里 有一篇关 于GDI+矩阵运算的文章,很值得一看 头文件

#include 类型

trans_affine 成员变量

这六个变量组成一个2*3的矩阵,与坐标计算后得到一个新的坐标。比

如对点(x,y)进行变换,则新的点(x',y') 为:

double sx, shy, shx, sy, tx, ty;

x' = x*sx + y*shx + tx; y' = x*shy + y*sy + ty;

成员方法

void transform(double* x, double* y) const; const trans_affine& scale(double s);

const trans_affine& scale(double x, double y);

用上面的公式转换x,y坐标 缩放

旋转,弧度单位(pi/180) const trans_affine& rotate(double a);

const trans_affine& translate(double x, double y) 平移

trans_affine operator * (const trans_affine& m); 矩阵乘法

取反矩阵 const trans_affine& invert();

坐标转换管道中有个叫conv_transform的 转换器,它能利用矩阵对源顶点进行变换,

我们先在这里玩玩吧^_^ 实验代码(基于此 处代码)

加入头文件 #include \

把on_draw()方法的里从“// Vertex Source”到“// Scanline Rasterizer”之间的代码改写成:

? // Vertex Source

? agg::ellipse ell(0,0,50,50); //圆心在中间 ?

? // Coordinate conversion pipeline ? agg::trans_affine mtx;

? mtx.scale(0.5,1); // x轴缩小到原来的一半