nsbezierpath를 cgpath로 어떻게 변환 할 수 있습니까?
-
07-07-2019 - |
문제
어떻게 변환 할 수 있습니까? NSBezierPath
에게 CGPath
.
감사.
해결책
Apple 문서에서 바로 : nsbezierpath 객체에서 cgpathref 생성
다음은 관련 코드입니다.
@implementation NSBezierPath (BezierPathQuartzUtilities)
// This method works only in OS X v10.2 and later.
- (CGPathRef)quartzPath
{
int i, numElements;
// Need to begin a path here.
CGPathRef immutablePath = NULL;
// Then draw the path elements.
numElements = [self elementCount];
if (numElements > 0)
{
CGMutablePathRef path = CGPathCreateMutable();
NSPoint points[3];
BOOL didClosePath = YES;
for (i = 0; i < numElements; i++)
{
switch ([self elementAtIndex:i associatedPoints:points])
{
case NSMoveToBezierPathElement:
CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
break;
case NSLineToBezierPathElement:
CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y);
didClosePath = NO;
break;
case NSCurveToBezierPathElement:
CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y,
points[1].x, points[1].y,
points[2].x, points[2].y);
didClosePath = NO;
break;
case NSClosePathBezierPathElement:
CGPathCloseSubpath(path);
didClosePath = YES;
break;
}
}
// Be sure the path is closed or Quartz may not do valid hit detection.
if (!didClosePath)
CGPathCloseSubpath(path);
immutablePath = CGPathCreateCopy(path);
CGPathRelease(path);
}
return immutablePath;
}
@end
버그 리포터
RDAR : // 15758302: cgpath에 대한 nsbezierpath.
다른 팁
Xcode 8 GM의 구문은 위의 Rob-Mayoff의 답변에서 수정 된 코드가 더 단순화되었습니다. 이것과 도우미를 사용합니다 addLine(to point: CGPoint)
드로잉 코드 크로스 플랫폼을 공유하고 있습니다.
extension NSBezierPath {
public var cgPath: CGPath {
let path = CGMutablePath()
var points = [CGPoint](repeating: .zero, count: 3)
for i in 0 ..< self.elementCount {
let type = self.element(at: i, associatedPoints: &points)
switch type {
case .moveToBezierPathElement:
path.move(to: points[0])
case .lineToBezierPathElement:
path.addLine(to: points[0])
case .curveToBezierPathElement:
path.addCurve(to: points[2], control1: points[0], control2: points[1])
case .closePathBezierPathElement:
path.closeSubpath()
}
}
return path
}
}
이것은 Swift 3.1 이상에서 작동합니다.
import AppKit
public extension NSBezierPath {
public var cgPath: CGPath {
let path = CGMutablePath()
var points = [CGPoint](repeating: .zero, count: 3)
for i in 0 ..< self.elementCount {
let type = self.element(at: i, associatedPoints: &points)
switch type {
case .moveToBezierPathElement: path.move(to: points[0])
case .lineToBezierPathElement: path.addLine(to: points[0])
case .curveToBezierPathElement: path.addCurve(to: points[2], control1: points[0], control2: points[1])
case .closePathBezierPathElement: path.closeSubpath()
}
}
return path
}
}
다른 사람이 필요하다고 생각하는 경우 신속한 버전은 다음과 같습니다.
extension IXBezierPath {
// Adapted from : https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Paths/Paths.html#//apple_ref/doc/uid/TP40003290-CH206-SW2
// See also: http://www.dreamincode.net/forums/topic/370959-nsbezierpath-to-cgpathref-in-swift/
func CGPath(forceClose forceClose:Bool) -> CGPathRef? {
var cgPath:CGPathRef? = nil
let numElements = self.elementCount
if numElements > 0 {
let newPath = CGPathCreateMutable()
let points = NSPointArray.alloc(3)
var bDidClosePath:Bool = true
for i in 0 ..< numElements {
switch elementAtIndex(i, associatedPoints:points) {
case NSBezierPathElement.MoveToBezierPathElement:
CGPathMoveToPoint(newPath, nil, points[0].x, points[0].y )
case NSBezierPathElement.LineToBezierPathElement:
CGPathAddLineToPoint(newPath, nil, points[0].x, points[0].y )
bDidClosePath = false
case NSBezierPathElement.CurveToBezierPathElement:
CGPathAddCurveToPoint(newPath, nil, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y )
bDidClosePath = false
case NSBezierPathElement.ClosePathBezierPathElement:
CGPathCloseSubpath(newPath)
bDidClosePath = true
}
if forceClose && !bDidClosePath {
CGPathCloseSubpath(newPath)
}
}
cgPath = CGPathCreateCopy(newPath)
}
return cgPath
}
허용 된 답변이 왜 정교한 근접 경로 논리를 추가하는지 알 수 없습니다 (어떤 상황에서는 필요할 수도 있지만) 깨끗합니다 경로의 변환, 여기에서는 해당 코드의 정리 된 버전이 정기적 인 방법으로 구현됩니다.
- (CGMutablePathRef)CGPathFromPath:(NSBezierPath *)path
{
CGMutablePathRef cgPath = CGPathCreateMutable();
NSInteger n = [path elementCount];
for (NSInteger i = 0; i < n; i++) {
NSPoint ps[3];
switch ([path elementAtIndex:i associatedPoints:ps]) {
case NSMoveToBezierPathElement: {
CGPathMoveToPoint(cgPath, NULL, ps[0].x, ps[0].y);
break;
}
case NSLineToBezierPathElement: {
CGPathAddLineToPoint(cgPath, NULL, ps[0].x, ps[0].y);
break;
}
case NSCurveToBezierPathElement: {
CGPathAddCurveToPoint(cgPath, NULL, ps[0].x, ps[0].y, ps[1].x, ps[1].y, ps[2].x, ps[2].y);
break;
}
case NSClosePathBezierPathElement: {
CGPathCloseSubpath(cgPath);
break;
}
default: NSAssert(0, @"Invalid NSBezierPathElement");
}
}
return cgPath;
}
BTW, 나는 "nsbezierpath 스트로크가 포인트 포함"방법을 구현하기 위해 이것을 필요로했다.
나는이 전환이 전화 할 것을 찾았다 CGPathCreateCopyByStrokingPath()
, 그것은 변환합니다 NSBezierPath
정기적 인 경로에 대한 뇌졸중 개요이므로 스트로크에 대한 히트를 테스트 할 수 있으며 다음은 해결책이 있습니다.
// stroke (0,0) to (10,0) width 5 --> rect (0, -2.5) (10 x 5)
NSBezierPath *path = [[NSBezierPath alloc] init];
[path moveToPoint:NSMakePoint(0.0, 0.0)];
[path lineToPoint:NSMakePoint(10.0, 0.0)];
[path setLineWidth:5.0];
CGMutablePathRef cgPath = [self CGPathFromPath:path];
CGPathRef strokePath = CGPathCreateCopyByStrokingPath(cgPath, NULL, [path lineWidth], [path lineCapStyle],
[path lineJoinStyle], [path miterLimit]);
CGPathRelease(cgPath);
NSLog(@"%@", NSStringFromRect(NSRectFromCGRect(CGPathGetBoundingBox(strokePath))));
// {{0, -2.5}, {10, 5}}
CGPoint point = CGPointMake(1.0, 1.0);
BOOL hit = CGPathContainsPoint(strokePath, NULL, point, (bool)[path windingRule]);
NSLog(@"%@: %@", NSStringFromPoint(NSPointFromCGPoint(point)), (hit ? @"yes" : @"no"));
// {1, 1}: yes
CGPathRelease(strokePath);
이것은 비슷합니다 QPainterPathStroker
QT에서. 그러나 NSBezierPath
.
MacOS의 경우 더 나은 사용 - cgmutablepath
그러나 원한다면 cgPath
~을 위한 NSBezierPath
:
스위프트 5.0
extension NSBezierPath {
var cgPath: CGPath {
let path = CGMutablePath()
var points = [CGPoint](repeating: .zero, count: 3)
for i in 0 ..< self.elementCount {
let type = self.element(at: i, associatedPoints: &points)
switch type {
case .moveTo:
path.move(to: points[0])
case .lineTo:
path.addLine(to: points[0])
case .curveTo:
path.addCurve(to: points[2], control1: points[0], control2: points[1])
case .closePath:
path.closeSubpath()
@unknown default:
break
}
}
return path
}
}