将CGPathRef转换为NSBezierPath

3
在苹果文档中,他们提供了将NSBezierPath转换为CGPathRef的代码。我需要将CGPathRef转换为NSBezierPath。UIBezierPath有一个名为cgPath的属性,因此如果我在iPhone上工作,那就不是问题,但我正在MacOS上工作。
这可能是一个老问题,我肯定可以在互联网上找到答案,但没有运气。可能是我漏掉了什么。非常感谢任何帮助。
1个回答

6

虽然这个问题旧了,但我相信这对其他人仍有帮助。(你没有说明是Objective-C还是Swift;这是一个Objective-C答案。)

你可以使用CGPathApply()和一个应用程序函数回调将CGPathRef转换为NSBezierPath,并将CGPathRef的点转换为NSBezierPath的点。唯一棘手的部分是从CGPathRef的二次曲线到NSBezierPath的三次曲线的转换,但是有一个方程式可以解决这个问题:

Any quadratic spline can be expressed as a cubic (where the cubic term is zero). The end points of the cubic will be the same as the quadratic's.

 CP0 = QP0
 CP3 = QP2 

The two control points for the cubic are:

 CP1 = QP0 + 2/3 * (QP1-QP0)
 CP2 = QP2 + 2/3 * (QP1-QP2)

... There is a slight error introduced due to rounding, but it is usually not noticeable.

使用上述方程式,这是一个用于将CGPathRef转换为NSBezierPath的类别:

NSBezierPath+BezierPathWithCGPath.h

@interface NSBezierPath (BezierPathWithCGPath)
+ (NSBezierPath *)JNS_bezierPathWithCGPath:(CGPathRef)cgPath; //prefixed as Apple may add bezierPathWithCGPath: method someday
@end

NSBezierPath+BezierPathWithCGPath.m

static void CGPathToBezierPathApplierFunction(void *info, const CGPathElement *element) {
    NSBezierPath *bezierPath = (__bridge NSBezierPath *)info;
    CGPoint *points = element->points;
    switch(element->type) {
        case kCGPathElementMoveToPoint: [bezierPath moveToPoint:points[0]]; break;
        case kCGPathElementAddLineToPoint: [bezierPath lineToPoint:points[0]]; break;
        case kCGPathElementAddQuadCurveToPoint: {
            NSPoint qp0 = bezierPath.currentPoint, qp1 = points[0], qp2 = points[1], cp1, cp2;
            CGFloat m = (2.0 / 3.0);
            cp1.x = (qp0.x + ((qp1.x - qp0.x) * m));
            cp1.y = (qp0.y + ((qp1.y - qp0.y) * m));
            cp2.x = (qp2.x + ((qp1.x - qp2.x) * m));
            cp2.y = (qp2.y + ((qp1.y - qp2.y) * m));
            [bezierPath curveToPoint:qp2 controlPoint1:cp1 controlPoint2:cp2];
            break;
        }
        case kCGPathElementAddCurveToPoint: [bezierPath curveToPoint:points[2] controlPoint1:points[0] controlPoint2:points[1]]; break;
        case kCGPathElementCloseSubpath: [bezierPath closePath]; break;
    }
}

@implementation NSBezierPath (BezierPathWithCGPath)
+ (NSBezierPath *)JNS_bezierPathWithCGPath:(CGPathRef)cgPath {
    NSBezierPath *bezierPath = [NSBezierPath bezierPath];
    CGPathApply(cgPath, (__bridge void *)bezierPath, CGPathToBezierPathApplierFunction);
    return bezierPath;
}
@end

如下所示调用:

//...get cgPath (CGPathRef) from somewhere
NSBezierPath *bezierPath = [NSBezierPath JNS_bezierPathWithCGPath:cgPath];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接