Degrafa的Bezier源码浅析(一)
先解释下Bezier曲线:
http://en.wikipedia.org/wiki/Bézier_curve
Degrafa是一套很强大的图形算法类库,并且开源,对Bezier曲线的绘制提供了很好的支持。说起Bezier曲线,其实就是Photoshop和flash里常用的钢笔工具啦,主要就是用来绘画路径或者绘画不规则图形。前者的应用领域非常广泛,比如使图形沿着路径运动,或者按路径不规则排列图形(具体一例就是扭曲的美术字布局)。这些都会用到Bezier曲线。
Degrafa提供的tutorial不是很完备,很多时候为了扩展应用不得不看源码。我这里只就Bezier相关的处理过程分析一下。
Degrafa下面的类非常之多,跟Bezier相关的主要有:
- com.degrafa.geometry.splines.BezierSpline
- com.degrafa.geometry.CubicBezier
两者都继承自com.degrafa.geometry.Geometry。很多图形库都有着类似的继承体系,Geometry作为一个基础的图形类,下面还有很多经过定义的不同种类的图形。
CubicBezier看字面意思,是一个三次贝塞尔曲线,事实上确实如此,它有四个点(start,end,2 control points)控制,其实也就是wiki上的那个图形
![]()
而BezierSpline跟真正的钢笔工具非常像,它由一系列点和control points来控制一整条曲线。这里最好看它的注释:
The BezierSpline can be used for drawing of a smooth curve through
multiple points, with some shape control over the curve via a tension
parameter. It may also be used for general path animation with tension
control, optional closed-path control, and velocity control
(arc-length parameterization).
乍看一下,它好像就是若干个CubicBezier的组合,其实关系不是很近。BezierSpline内部确实用到了CubicBezier对象(源码的第一行private var _bezier:Array),它是用来管理三次bezier曲线段的(BezierSpline包括很多的段)。
在使用BezierSpline曲线之前,需要提供一系列的点(钢笔工具的点类似)。使用到的property包括:
- points
- data
两者实质相同形式不同而已。
绘画曲线都使用draw方法,这个方法是由Geometry定义,并由它的子类重写的(典型的继承体系)。BezierSpline和CubicBezier都有类似的draw定义方式:
/**
* Begins the draw phase for geometry objects. All geometry objects
* override this to do their specific rendering.
*
* @param graphics The current context to draw to.
* @param rc A Rectangle object used for fill bounds.
**/
override public function draw(graphics:Graphics,rc:Rectangle):void{
//re init if required
if (invalidated) preDraw();
//init the layout in this case done after predraw.
if (_layoutConstraint) calculateLayout();
super.draw(graphics, (rc)? rc:bounds);
}
preDraw在这个体系里非常重要,是用来在绘画之前计算各个点的位置,就像我们使用graphic那样定义好MoveTo和lineTo,所不同的这里会用到很多算法。与draw一样,preDraw在Geometry里定义在子类里重写,每个子类都有不同的方法。比如BezierSpline:
/**
* @inheritDoc
**/
override public function preDraw():void{
if( invalidated ){
if(!points.length){return;}
_assignControlPoints();
//add a move to for the first item.
commandStack.length=0;
//add a MoveTo at the start of the commandStack rendering chain
commandStack.addMoveTo(points[0].x,points[0].y);
var cubic:CubicBezier;
//todo not sure were this extra one is coming from yet.
//re:: - 1 on the count
for( var i:uint=0; i<_bezier.length-1; ++i ){
cubic = _bezier[i];
commandStack.addCubicBezierTo(cubic.x0,cubic.y0,cubic.cx,
cubic.cy,cubic.cx1,cubic.cy1,cubic.x1,cubic.y1,1);
}
invalidated = false;
}
}
挖到这里,基本上快看到bezier算法在Degrafa里怎么实现的了,关键就是这个commandStack,字面意思:命令退栈,命令集合。


