如何从UIBezierPath获取点列表?

我有一个UIBezierPath ,我需要从一个点列表。

Qt有一个名为pointAtPercent的函数, pointAtPercent我的需求,但在Objective-C我找不到任何相同的东西。

有谁知道如何做到这一点?

你可以试试这个:

 UIBezierPath *yourPath; // Assume this has some points in it CGPath yourCGPath = yourPath.CGPath; NSMutableArray *bezierPoints = [NSMutableArray array]; CGPathApply(yourCGPath, bezierPoints, MyCGPathApplierFunc); 

path应用函数将依次交给每个path的path元素。
查看CGPathApplierFunction和CGPathApply 。

path应用函数可能看起来像这样

 void MyCGPathApplierFunc (void *info, const CGPathElement *element) { NSMutableArray *bezierPoints = (NSMutableArray *)info; CGPoint *points = element->points; CGPathElementType type = element->type; switch(type) { case kCGPathElementMoveToPoint: // contains 1 point [bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]]; break; case kCGPathElementAddLineToPoint: // contains 1 point [bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]]; break; case kCGPathElementAddQuadCurveToPoint: // contains 2 points [bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]]; [bezierPoints addObject:[NSValue valueWithCGPoint:points[1]]]; break; case kCGPathElementAddCurveToPoint: // contains 3 points [bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]]; [bezierPoints addObject:[NSValue valueWithCGPoint:points[1]]]; [bezierPoints addObject:[NSValue valueWithCGPoint:points[2]]]; break; case kCGPathElementCloseSubpath: // contains no point break; } } 

@Moritz很好的答案! 为了find一个类似Swift的解决scheme,我在这篇文章中碰到了一个方法,并实现了一个像这样的CGPath扩展来获取path中的点:

 extension CGPath { func points() -> [CGPoint] { var bezierPoints = [CGPoint]() self.forEach({ (element: CGPathElement) in let numberOfPoints: Int = { switch element.type { case .MoveToPoint, .AddLineToPoint: // contains 1 point return 1 case .AddQuadCurveToPoint: // contains 2 points return 2 case .AddCurveToPoint: // contains 3 points return 3 case .CloseSubpath: return 0 } }() for index in 0..<numberOfPoints { let point = element.points[index] bezierPoints.append(point) } }) return bezierPoints } func forEach(@noescape body: @convention(block) (CGPathElement) -> Void) { typealias Body = @convention(block) (CGPathElement) -> Void func callback(info: UnsafeMutablePointer<Void>, element: UnsafePointer<CGPathElement>) { let body = unsafeBitCast(info, Body.self) body(element.memory) } let unsafeBody = unsafeBitCast(body, UnsafeMutablePointer<Void>.self) CGPathApply(self, unsafeBody, callback) } } 

我认为你正在尝试做这样的事情:

https://math.stackexchange.com/questions/26846/is-there-an-explicit-form-for-cubic-bézier-curves

y=u0(1−x^3)+3u1(1−x^2)x+3u2(1−x)x^2+u3x^3

这是我打印该函数的所有值的方法。

 - (void)logXY { float u0 = 0; float u1 = 0.05; float u2 = 0.25; float u3 = 1; for (float x = 0; x <= 10.0; x = x + 0.1) { float y = u0 * (1 - x * x * x) + 3 * u1 * (1 - x * x) * x + 3 * u2 * (1 - x) * x * x + u3 * x * x * x; NSLog(@"x: %f\ty: %f", x, y); } } 

和输出是:

 x: 0.000000 y: 0.000000 x: 0.100000 y: 0.022600 x: 0.200000 y: 0.060800 x: 0.300000 y: 0.115200 x: 0.400000 y: 0.186400 x: 0.500000 y: 0.275000 x: 0.600000 y: 0.381600 x: 0.700000 y: 0.506800 x: 0.800000 y: 0.651200 x: 0.900000 y: 0.815400 x: 1.000000 y: 1.000000 x: 1.100000 y: 1.205600 x: 1.200000 y: 1.432800 x: 1.300000 y: 1.682200 x: 1.400000 y: 1.954401 x: 1.500000 y: 2.250001 x: 1.600000 y: 2.569601 x: 1.700000 y: 2.913801 x: 1.800000 y: 3.283201 x: 1.900000 y: 3.678401 x: 2.000000 y: 4.100001 x: 2.100000 y: 4.548601 x: 2.200000 y: 5.024800 x: 2.300000 y: 5.529200 x: 2.400000 y: 6.062399 x: 2.500000 y: 6.625000 x: 2.600000 y: 7.217597 x: 2.700000 y: 7.840797 x: 2.799999 y: 8.495197 x: 2.899999 y: 9.181394 x: 2.999999 y: 9.899996 

我写了一篇关于在UIBezierPath上find最接近点的文章,这与OP所寻找的非常相似。 我也在Swift上创build了一个演示项目: https : //github.com/andrew8712/BezierPathClosestPoint

我已经修改@FBente文章与迅速3

 extension CGPath { func points() -> [CGPoint] { var bezierPoints = [CGPoint]() self.forEach(body: { (element: CGPathElement) in let numberOfPoints: Int = { switch element.type { case .moveToPoint, .addLineToPoint: // contains 1 point return 1 case .addQuadCurveToPoint: // contains 2 points return 2 case .addCurveToPoint: // contains 3 points return 3 case .closeSubpath: return 0 } }() for index in 0..<numberOfPoints { let point = element.points[index] bezierPoints.append(point) } }) return bezierPoints } func forEach( body: @convention(block) (CGPathElement) -> Void) { typealias Body = @convention(block) (CGPathElement) -> Void func callback(info: UnsafeMutableRawPointer, element: UnsafePointer<CGPathElement>) { let body = unsafeBitCast(info, to: Body.self) body(element.pointee) } let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self) self.apply(info: unsafeBody, function: callback as! CGPathApplierFunction) } } 

更新了FBente的Swift 3扩展:

 extension CGPath { func points() -> [CGPoint] { var bezierPoints = [CGPoint]() self.forEach({ (element: CGPathElement) in let numberOfPoints: Int = { switch element.type { case .moveToPoint, .addLineToPoint: // contains 1 point return 1 case .addQuadCurveToPoint: // contains 2 points return 2 case .addCurveToPoint: // contains 3 points return 3 case .closeSubpath: return 0 } }() for index in 0..<numberOfPoints { let point = element.points[index] bezierPoints.append(point) } }) return bezierPoints } func forEach(_ body: @convention(block) (CGPathElement) -> Void) { typealias Body = @convention(block) (CGPathElement) -> Void func callback(info: UnsafeMutableRawPointer, element: UnsafePointer<CGPathElement>) { let body = unsafeBitCast(info, to: Body.self) body(element.pointee) } let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self) self.apply(info: unsafeBody, function: callback as! CGPathApplierFunction) } }