展平CGPath

Geo*_* WS 4 core-graphics uikit ios

简单地说,我正在寻找-bezierPathByFlatteningPath可以在iOS上使用的NSBezierPath的等价物.对我来说,这是一个直接处理UGPezierPath上的CGPath或方法的函数并不重要,因为这两个函数可以很容易地来回转换.CGPath ReferenceUIBezierPath Class Reference都没有表明存在任何此类函数或方法.

另外:我知道CGPath的CGPathApply功能,我缺乏时间和技能来实现我自己的展平算法,通过遍历路径中的元素来实现CGPathApplierFunction.我正在寻找一个现有的解决方案 - 一个应用程序功能,一个关于UIBezierPath的类别,等等.当然存在一个.

ale*_*ail 7

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);
Run Code Online (Sandbox Code Playgroud)

所以基本上,初始化一个空的CGMutablePathRef,并且对于原始路径中的每个CGPath元素,如果它是线性的,则复制它,或者根据贝塞尔曲线段的程度对其进行离散化.

您可能还想应用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;
}
Run Code Online (Sandbox Code Playgroud)

代码属于Erica Sadun.请参阅此处以获取完整的实现:https://github.com/erica/iOS-Drawing

Rob Napier还在iOS 6中推出了 Bezier曲线,推动了极限,第26章花式文本布局.他并没有试图压平一个完整的UIBezierPath,只有一个用四个点定义的立方Bezier路径,但实际上这是完全相同的事情(离散Bezier路径)另外,你可能会发现这篇文章很有趣:http://robnapier.net/快贝塞尔