VertexSource VS; //其它顶点源
// 使用顶点转换器,并指定Markers类型为vcgen_markers_term
// 顶点转换器可以是conv_dash、conv_stroke或conv_marker_adaptor,见后文《坐标转换管道》
// vcgen_markers_term:以端点作为标记点
conv_stroke
// 用conv_marker指定ah作为线段marker点的标记
conv_marker
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
?? agg::conv_marker
?? 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
得到的图形是:
除了文字输出功能(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轴缩小到原来的一半