Convert CGPathRef to NSBezierPath

可紊 提交于 2020-01-14 19:00:07

问题


In Apple docs they give you code of how to convert NSBezierPath to CGPathRef. I need to convert the other way around, from CGPathRef to NSBezierPath. UIBezierPath has a property called cgPath so if I was working on iPhone that would not be a problem, but I'm working on MacOS.

This must be an old question, and I was sure to find an answer on Internet but no luck. Could be I'm missing something. Any help appreciated.


回答1:


Old question but I'm sure this will still be helpful for others. (You didn't specify Objective-C or Swift; this is an Objective-C answer.)

You can convert a CGPathRef to an NSBezierPath using CGPathApply() with a callback that translates the CGPathRef points to NSBezierPath points. The only tricky part is the conversation from CGPathRef's quadratic curves to NSBezierPath's cubic curves but there's an equation for that:

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.

Using the equation above, here's an NSBezierPath category for converting from CGPathRef:

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 CGPathCallback(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, CGPathCallback);
    return bezierPath;
}
@end

Called like so:

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


来源:https://stackoverflow.com/questions/45967240/convert-cgpathref-to-nsbezierpath

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!