将 CGPathRef 转换为 NSBezierPath
Convert CGPathRef to NSBezierPath
在 Apple 文档中,他们为您提供了如何将 NSBezierPath 转换为 CGPathRef 的代码。我需要反过来转换,从 CGPathRef 到 NSBezierPath。 UIBezierPath 有一个名为 cgPath 的 属性,所以如果我在 iPhone 上工作,那不会有问题,但我在 MacOS 上工作。
这一定是个老问题了,我肯定能在网上找到答案,但运气不好。可能是我遗漏了什么。任何帮助表示赞赏。
老问题,但我相信这对其他人仍然有帮助。 (您没有指定 Objective-C 或 Swift;这是一个 Objective-C 答案。)
您可以使用 CGPathApply()
将 CGPathRef
转换为 NSBezierPath
,并使用应用函数回调将 CGPathRef
点转换为 NSBezierPath
点。唯一棘手的部分是从 CGPathRef
的二次曲线到 NSBezierPath
的三次曲线的转换,但是 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.
使用上面的等式,这里有一个 NSBezierPath
类别,用于从 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 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];
在 Apple 文档中,他们为您提供了如何将 NSBezierPath 转换为 CGPathRef 的代码。我需要反过来转换,从 CGPathRef 到 NSBezierPath。 UIBezierPath 有一个名为 cgPath 的 属性,所以如果我在 iPhone 上工作,那不会有问题,但我在 MacOS 上工作。
这一定是个老问题了,我肯定能在网上找到答案,但运气不好。可能是我遗漏了什么。任何帮助表示赞赏。
老问题,但我相信这对其他人仍然有帮助。 (您没有指定 Objective-C 或 Swift;这是一个 Objective-C 答案。)
您可以使用 CGPathApply()
将 CGPathRef
转换为 NSBezierPath
,并使用应用函数回调将 CGPathRef
点转换为 NSBezierPath
点。唯一棘手的部分是从 CGPathRef
的二次曲线到 NSBezierPath
的三次曲线的转换,但是 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.
使用上面的等式,这里有一个 NSBezierPath
类别,用于从 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 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];