问题
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 = QP2The 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