來自http://www.cppprog.com/2009/0821/150.html
上次講了AGG的顯示原理並舉了一個簡單的例子,這一篇文章開始講AGG工作流程裡的每個環節。為了方便對照,再放一次AGG顯示流程 圖
另外,上 一篇文章裡的例 程也 很重要,後面的例子都將基於這個代碼。
下面,我們來考察AGG顯示流程中的每個環節。理解每個環節最好的方法是編寫實驗代碼,建議先參照這裡建 立一個可以啟動並執行AGG實驗環境。
頂點源(Vertex Source)
<!--基本屬性-->
頂點源(Vertex Source)
頂點源是一種可以產生多邊形所需要的“帶命令的頂點”的對象。比如三角形頂點源,就應該會產生一個帶“MoveTo”命令的點,另外二 個帶"LineTo"命令的點和最終閉合的“ClosePoly”命令。
標頭檔
#include <agg_path_storage.h> //path_storage#include <agg_ellipse.h> // ellipse#include <agg_arc.h> // arc#include <agg_arrowhead.h> // arrowhead#include <agg_curves.h> // curve3, curve4#include <agg_gsv_text.h> // gsv_text, gsv_text_outline#include <agg_rounded_rect.h> // rounded_rect...
類型
| 自訂類 |
所有實現了void rewind(unsigned path_id);和unsigned vertex(double* x, double* y);的類。 |
| ellipse |
圓,輸入為中心點座標和XY軸半徑,本文所用的例子就 使用了這個頂點源 |
| arc |
弧線,輸入為中心點座標和XY軸半徑,以及起始和終止角(rad),順時針/逆時針方向 |
| curve3 |
貝茲路徑,輸入為起點座標、第一控制點座標、終點點座標 |
| curve4 |
貝茲路徑,輸入為起點座標、第一控制點座標、第二控制點座標、終點座標 |
| gsv_text |
使用AGG內建字模的文字輸出(只支援ASCII碼),使用start_point方法指定文字位置,text方法指定 文字,flip指定是否上下倒轉,size指定文字大小,適合與conv_stroke或gsv_text_outline配合。 |
| gsv_text_outline<> |
可變換文字,輸入為gsv_text和變換矩陣(預設為trans_affine,後文會提到)。width方法設定文 字寬度 |
| rounded_rect |
圓角方形,輸入為左上方右下角座標和圓角半徑 |
| path_storage |
路徑儲存空間,可以用join_path方法加入多個頂點源。而且path_storage本身支援move_to, line_to,curve和arc_to等畫線功能 |
| arrowhead |
箭頭,它是作為標記點來用的 |
其中的arrowhead頗為特殊,它一般作為線段的標記點,具體用法是這樣的:
arrowhead ah;ah.head(d1,d2,d3,d4); //定義箭頭ah.tail(d1,d2,d3,d4); //定義箭尾VertexSource VS; //其它頂點源// 使用頂點轉換器,並指定Markers類型為vcgen_markers_term// 頂點轉換器可以是conv_dash、conv_stroke或conv_marker_adaptor,見後文《座標轉換管道》// vcgen_markers_term:以端點作為標記點conv_stroke<VertexSource, vcgen_markers_term> csVS(VS);...draw_term// 用conv_marker指定ah作為線段marker點的標記conv_marker<vcgen_markers_term, arrowhead> 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<agg::path_storage, agg::vcgen_markers_term> csps(ps);
- agg::conv_marker<agg::vcgen_markers_term, agg::arrowhead>
- 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 "agg_conv_marker.h"#include "agg_arrowhead.h"#include "agg_path_storage.h"#include "agg_vcgen_markers_term.h"
實驗代碼,自訂一個頂點源(基於此處代碼)
為了對頂點源有更深入的瞭解,我們要自己實現一個頂點源,這個頂點源只是很簡單的一個三角形。
前面說過,只要實現了 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<agg::ellipse> ell_cc_type;改成typedef agg::conv_contour<triangle> ell_cc_type;
得到的圖形是:
除了文字輸出功能(gsv_text只能輸出ASCII文字),上面這些頂點源提供的圖形豐富程度已經超過了系統API。文字輸出功能 將以單獨的篇幅講述。