Erica Sadun 提供了一组有用的函数来处理 UIBezierPath 和 CGPathRef。
本书使用此代码。
她没有提供 CGPathRef 展平的实现,但可以使用以下函数轻松完成:
https ://github.com/erica/iOS-Drawing/blob/master/C05/Quartz%20Book%20Pack /Bezier/BezierFunctions.m
特别是,这些函数将有助于离散非线性贝塞尔线段:
float CubicBezier(float t, float start, float c1, float c2, float end)
float QuadBezier(float t, float start, float c1, float end)
CGPoint CubicBezierPoint(CGFloat t, CGPoint start, CGPoint c1, CGPoint c2, CGPoint end);
CGPoint QuadBezierPoint(CGFloat t, CGPoint start, CGPoint c1, CGPoint end);
所以基本上,初始化一个空的 CGMutablePathRef,对于原始路径中的每个 CGPath 元素,如果它是线性的,要么复制它,要么根据 Bezier 段的度数对其进行离散化。
您可能还想应用Ramer–Douglas–Peucker 算法来删除不必要的点。
您也可以直接使用:- (NSArray *) interpolatedPathPoints
它返回一个 NSArray 点,可用于构建路径的近似值。该算法是幼稚的,因此您必须简化这种情况下的结果,例如,三次贝塞尔路径将是线性的(如果控制点对齐);和以前一样,Ramer-Douglas-Peucker 算法完成了这项工作。
这是实际离散化的样子。代码不是自包含的,您必须使用所有依赖项。
- (NSArray *) interpolatedPathPoints
{
NSMutableArray *points = [NSMutableArray array];
BezierElement *current = nil;
int overkill = 3;
for (BezierElement *element in self.elements)
{
switch (element.elementType)
{
case kCGPathElementMoveToPoint:
case kCGPathElementAddLineToPoint:
[points addObject:[NSValue valueWithCGPoint:element.point]];
current = element;
break;
case kCGPathElementCloseSubpath:
current = nil;
break;
case kCGPathElementAddCurveToPoint:
{
for (int i = 1; i < NUMBER_OF_BEZIER_SAMPLES * overkill; i++)
{
CGFloat percent = (CGFloat) i / (CGFloat) (NUMBER_OF_BEZIER_SAMPLES * overkill);
CGPoint p = CubicBezierPoint(percent, current.point, element.controlPoint1, element.controlPoint2, element.point);
[points addObject:[NSValue valueWithCGPoint:p]];
}
[points addObject:[NSValue valueWithCGPoint:element.point]];
current = element;
break;
}
case kCGPathElementAddQuadCurveToPoint:
{
for (int i = 1; i < NUMBER_OF_BEZIER_SAMPLES * overkill; i++)
{
CGFloat percent = (CGFloat) i / (CGFloat) (NUMBER_OF_BEZIER_SAMPLES * overkill);
CGPoint p = QuadBezierPoint(percent, current.point, element.controlPoint1, element.point);
[points addObject:[NSValue valueWithCGPoint:p]];
}
[points addObject:[NSValue valueWithCGPoint:element.point]];
current = element;
break;
}
}
}
return points;
}
代码属于 Erica Sadun。完整的实现见这里:https ://github.com/erica/iOS-Drawing
Rob Napier 还在iOS 6 Pushing the limits , Chapter 26 Fancy Text Layout 中写了关于 Bezier 曲线的文章。他并没有试图展平完整的 UIBezierPath,只有一个由四个点定义的三次 Bezier 路径,但实际上这完全一样(离散化 Bezier 路径)另外,您可能会发现这篇文章很有趣:http ://robnapier.net/更快的贝塞尔曲线