河南洛阳 祝小鹰 2015-07-07
接触AGG一年多,积累了一些心得体会。现在贴出来与大家分享。
注1:学习笔记按记录时间的逆序排列。
注2:当初学习AGG的目的是为了绘制SVG图形文件,因此夹杂了一些SVG的内容。
注3:早期的笔记由于刚接触AGG,可能存在一些错误。
例程和库文件下载:http://pan.baidu.com/s/1o6OhqMQ
-----------------------------------------------------------------------
关于SVG中<linearGradinet>、<radialGradient>的属性xlink:href的补充说明:
- 只有在不包含<stop>子元素的情况下,才“继承”引用元素的<stop>子元素。
- 如果引用的url不存在,则忽略xlink:href属性。
- 允许间接引用,例如lg3引用lg2,而lg2引用lg1。
- <linearGradinet>可引用<radialGradient>,反之亦可。
-----------------------------------------------------------------------
AGG的marker locator(vcgen_markers_term)在处理分段线段时,每一个子线段都会生成一组起点和终点的定位信息。也就是说,每一个子线段的起点和终点都将绘制标记点。但是SVG仅在第一个起点和最后一个终点处绘制标记点。
因此为svg_viewer编写了一个类模板svg_markers_term,用于将AGG的marker locator转换为SVG规范。转换后,只保留第一个起点和最后一个终点的定位信息。
-----------------------------------------------------------------------
SVG中,图元的transform属性对渐变色绘制的影响:
- SVG先按照图元的坐标数据进行渐变色渲染,然后渐变色随同图元一起进行坐标变换(应用图元的transform属性)。这意味着在AGG中实现时,插值器矩阵需要叠加图元的transform属性。
- 对于objectBoundingBox模式,其参考坐标系是图元应用transform属性之前的包围矩形。
-----------------------------------------------------------------------
在SVG中:不论是绘制填充区域,还是绘制轮廓线,对于objectBoundingBox模式下的渐变色渲染,其参考坐标系均为填充区域的包围矩形。
-----------------------------------------------------------------------
使用AGG实现objectBoundingBox模式的渐变色绘制的步骤:
1 以单位矩形为基准,设计渐变方式和参考值区间。
2 对插值器矩阵应用gradientTransform中的变换(注意按逆序),此时得到的渐变区域仍然基于单位矩形。
3 通过缩放(w,h)和平移(x0,y0),将渐变区域变换至待填充图元的包围矩形。(x0,y0,w,h)是包围矩形在绝对坐标系中的几何参数。
上述方法还存在一个问题。首先分析一下像素颜色的计算过程:
1 待填充的像素通过插值器矩阵(上述变换的逆矩阵),变换至单位矩形。
2 计算参考值,并将参考值映射至颜色区间,从而得到像素颜色。在此过程中,已变换至单位矩形的点坐标和参考值区间[d1,d2]均换算成亚像素坐标(其实就是乘以16然后取整)参与计算。
由于单位矩形的边长换算成亚像素只有16,而参考值区间又是以单位矩形为基准选取的,因此参考值区间对应的亚像素数目有限,导致映射至颜色区间后,颜色看上去不连续。
解决办法:以边长w的正方形为基准,设计渐变方式和参考值区间,gradientTransform属性中的相对长度也乘以w,然后缩放系数改为(1,h/w)。
但是在绘制SVG图元前,gradientTransform属性已经被解析为一个矩阵,如何实现“相对长度乘以w”?参考《计算机图形学 第三版》P201 公式5.42,将矩阵的平移项(第3列前两个元素)乘以w即可。
-----------------------------------------------------------------------
SVG中,objectBoundingBox模式的渐变色绘制的实现原理:
在objectBoundingBox模式下,<linearGradient>和<radialGradient>的属性参数所设定的渐变区域,是以单位矩形(边长为1)为基准,然后通过缩放(w,h)和平移(x0,y0),变换至待填充图元的包围矩形。(x0,y0,w,h)是包围矩形在绝对坐标系中的几何参数。
-----------------------------------------------------------------------
SVG中,<linearGradient>使用向量标识渐变方向。用AGG实现时,通常使用水平渐变gradient_x,以原点为渐变起始点,参考值区间为[0,向量长度],然后通过插值器矩阵的旋转、平移,变换至渐变向量的位置。
要考虑向量长度近似为0的情况:如果向量长度 < 0.5,则按实色填充,填充色取第一个渐变色。
-----------------------------------------------------------------------
关于SVG中线性渐变元素<linearGradient>的描述:
属性:
id 元素标识
x1, y1 渐变矢量的起点,缺省值“0, 0”
x2, y2 渐变矢量的终点,缺省值“100%, 0”
gradientUnits x1 y1 x2 y2的坐标系,缺省值为“objectBoundingBox”
- userSpaceOnUse 用户坐标系(与SVG图元使用同一个坐标系)
- objectBoundingBox 以对象的包围矩形为参考坐标系
spreadMethod 重复方式,默认值为“pad”
- pad 不重复
- repeat 对应agg::gradient_repeat_adaptor
- reflect 对应agg::gradient_reflect_adaptor
xlink:href 引用另外一个已定义好的渐变元素
gradientTransform 变换矩阵,缺省值为单位阵
与图元的transform属性类似,也是按逆序应用变换(绝对坐标系)
用于AGG中的插值器时,矩阵还要求逆
gradientUnits对gradientTransform有影响
- userSpaceOnUse 坐标变换使用用户坐标系(与SVG图元使用同一个坐标系)
在此情况下,不需要对坐标值和变换矩阵进行额外处理
- objectBoundingBox 坐标变换以对象的包围矩形为参考坐标系
* translate(x,y)中,参数x,y是相对长度
* rotate(angle,cx,cy)中,cx,cy是相对长度
* 注意:这里的相对长度不支持百分比,只能用小数
如果x1 y1 x2 y2 gradientUnits均使用缺省值,填充效果如何?
经测试,等效于 (x1,y1) = (0,0) (x2,y2) = (1,0)
如果x1 y1 x2 y2使用缺省值,gradientUnits=userSpaceOnUse,填充效果如何?
经测试&