首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >平坦CGPath

平坦CGPath
EN

Stack Overflow用户
提问于 2013-09-17 19:12:04
回答 2查看 2.1K关注 0票数 4

简单地说,我正在寻找一个等价于NSBezierPath的-bezierPathByFlatteningPath,可以在iOS上使用。对于我来说,这是一个直接处理CGPath的函数还是UIBezierPath上的一个方法并不重要,因为这两个函数可以很容易地来回转换。CGPath参考UIBezierPath类引用都不表示存在任何这样的函数或方法。

另外:我知道CGPath的CGPathApply函数,而且我缺乏时间和技能来通过在CGPathApplierFunction中迭代路径的元素来实现自己的扁平算法。我正在寻找一个现有的解决方案--一个更实用的函数,一个UIBezierPath上的类别,等等。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-03-28 16:49:56

Erica提供了一组处理UIBezierPath和CGPathRef的有用函数。

此代码用于这本书

她没有提供CGPathRef扁平化的实现,但是可以很容易地使用可以在这里找到的函数:https://github.com/erica/iOS-Drawing/blob/master/C05/Quartz%20Book%20Pack/Bezier/BezierFunctions.m

特别是,这些函数将有助于离散非线性Bezier段:

代码语言:javascript
复制
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,可以用来构建路径的近似。算法太天真了,所以你必须简化结果,例如,三次Bezier路径是线性的(如果控制点对齐);就像以前一样,Ramer Peucker算法完成了这项工作。

下面是实际的离散化。代码不是自包含的,您必须使用所有的依赖项。

代码语言:javascript
复制
- (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;
}

密码是埃丽卡·萨顿的。有关完整实现,请参见此处:https://github.com/erica/iOS-Drawing

罗伯纳皮尔还写了贝塞尔曲线在iOS 6突破极限,第26章幻想文本布局。他不是试图平平一个完整的UIBezierPath,只有一个用四点定义的三次Bezier路径,但实际上这是完全相同的事情(离散Bezier路径),您可能会发现本文很有趣:http://robnapier.net/faster-bezier

票数 7
EN

Stack Overflow用户

发布于 2013-09-18 05:53:59

基本上,您想要做的是将路径转换为将所有曲线和quadCurves替换为直线。您可以使用CGPathApply轻松地完成此操作,并将其包装在UIBezierPath上的一个类别中。

代码语言:javascript
复制
#import <CoreGraphics/CoreGraphics.h>

@interface UIBezierPath (Flatten)
- (UIBezierPath *)bezierPathByFlatteningPath;
@end

void __flattenBezierPath(void *target, const CGPathElement *element) {
    UIBezierPath *newPath = (__bridge UIBezierPath *)(target);

    switch (element->type) {
        case kCGPathElementMoveToPoint:
            [newPath moveToPoint:element->points[0]];
            break;

        case kCGPathElementAddLineToPoint:
            [newPath addLineToPoint:element->points[0]];
            break;

        case kCGPathElementCloseSubpath:
            [newPath closePath];
            break;

        case kCGPathElementAddCurveToPoint:
            [newPath addLineToPoint:element->points[2]];
            break;

        case kCGPathElementAddQuadCurveToPoint:
            [newPath addLineToPoint:element->points[1]];
            break;
    }

}

@implementation UIBezierPath (Flatten)

- (UIBezierPath *)bezierPathByFlatteningPath
{
    UIBezierPath *newPath = [UIBezierPath bezierPath];
    CGPathApply(self.CGPath, (__bridge void *)(newPath), __flattenBezierPath);
    return newPath;
}

@end

效果如下,绿色是原始路径,红色是该方法生成的路径,黄色是使用setFlatness:MAXFLOAT生成的路径。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18858011

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档