Ekulelu's Blog

iOS基于CoreGraphics的可变粗细的划线

之前的文章有提及过现在Drawing里面使用的画图方式:基于系统的CoreGraphics框架的CGContextAddLineToPoint来进行绘制,但是这些都有个问题,你会发现你调用stroke之前,只能设定唯一的宽度,当你调用stroke的时候,该path里面的点都会以这个宽度进行绘制。为了实现宽度可变,原生接口只能采用一个很极端的方式:每两个点就调用一次stroke方法,也就是说每两个点组成一个path,然后改变不同的path的宽度就可以绘制出一条可变宽度的线段。
代码如下:

注:下面的插值方法已经使用了二次贝塞尔方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CGFloat x0 = self.lastMidPoint.x;
CGFloat y0 = self.lastMidPoint.y;
CGFloat x1 = point.x;
CGFloat y1 = point.y;
CGFloat x2 = midP.x;
CGFloat y2 = midP.y;
CGFloat stepZ = ((CGFloat)(midP.z - self.lastMidPoint.z)) * increment;
CGFloat stepT = ((CGFloat)(midP.t - self.lastMidPoint.t)) * increment;
int index = 0;
for (CGFloat t = increment; t <=1.0; t += increment) {
//二次贝塞尔曲线
CGFloat x = (1-t) * (1-t) * x0 + 2*t*(1-t)*x1 + t*t*x2;
CGFloat y = (1-t) * (1-t) * y0 + 2*t*(1-t)*y1 + t*t*y2;
RYPoint3 *insertPoint = [RYPoint3 pointWithX:x y:y z:self.lastMidPoint.z + stepZ * index t:self.lastMidPoint.t + stepT * index];
index++;
[self changeLineWidthWithPoint:insertPoint context:context];
CGContextAddLineToPoint(context, insertPoint.x, insertPoint.y);
CGContextStrokePath(context);
CGContextMoveToPoint(context, insertPoint.x, insertPoint.y);
}

当然这里使用这样的方法是有很大代价的。每次调用stroke方法,相当于发送一次绘制指令给GPU,每两个点就调用一次,这个十分消耗性能。
更好的做法是使用OpenGLES,把绘制指令的发送交给自己管理,且用OpenGLES可以直接使用三角形条来绘制可变粗细的线条。