如何获得CGPath的CGPoint

我怎样才能得到一个给定的CGPathCGMutablePathRef )中包含的所有CGPoint的数组?

您可以使用CGPathApply()遍历path中的每个段,并使用该段运行自定义函数。 这会给你所有的path信息。

但是,如果使用“所有CGPoint”,则意味着每个点都具有一个像素,这是一个无限大的集合。 虽然你可以使用apply函数来获取每个段,然后对于每个非移动段,使用该段的控制点评估自己的math运算,以获得任意密度点的列表。

使用Swift 2.xSwift 3.x阅读下面这里..),我已经find了这个关于在C Swift的Ccallback的神奇的文章。

正如凯文·巴拉德 ( Kevin Ballard )所解释的那样,试图获得“所有CGPoint(s)”可能是一个坏主意,正如他所说的那样。

所以,我想也许最好的方法是获取用于创build特定CGPath的path元素点:

 //MARK: - CGPath extensions extension CGPath { 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) } print(sizeofValue(body)) let unsafeBody = unsafeBitCast(body, UnsafeMutablePointer<Void>.self) CGPathApply(self, unsafeBody, callback) } func getPathElementsPoints() -> [CGPoint] { var arrayPoints : [CGPoint]! = [CGPoint]() self.forEach { element in switch (element.type) { case CGPathElementType.MoveToPoint: arrayPoints.append(element.points[0]) case .AddLineToPoint: arrayPoints.append(element.points[0]) case .AddQuadCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) case .AddCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) arrayPoints.append(element.points[2]) default: break } } return arrayPoints } } 

有了这个扩展,你可以做例如:

 var bezier = UIBezierPath(ovalInRect: CGRectMake(0, 0, 400, 300)) let myOval = bezier.CGPath let junctionPoints = myOval.getPathElementsPoints() print("junction points are: \(junctionPoints)") 

更新Swift 3.x

(由于@convention(c)语法重新引入,有一些更正):

 extension CGPath { func forEach( body: @convention(block) (CGPathElement) -> Void) { typealias Body = @convention(block) (CGPathElement) -> Void let callback: @convention(c) (UnsafeMutableRawPointer, UnsafePointer<CGPathElement>) -> Void = { (info, element) in let body = unsafeBitCast(info, to: Body.self) body(element.pointee) } print(MemoryLayout.size(ofValue: body)) let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self) self.apply(info: unsafeBody, function: unsafeBitCast(callback, to: CGPathApplierFunction.self)) } func getPathElementsPoints() -> [CGPoint] { var arrayPoints : [CGPoint]! = [CGPoint]() self.forEach { element in switch (element.type) { case CGPathElementType.moveToPoint: arrayPoints.append(element.points[0]) case .addLineToPoint: arrayPoints.append(element.points[0]) case .addQuadCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) case .addCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) arrayPoints.append(element.points[2]) default: break } } return arrayPoints } func getPathElementsPointsAndTypes() -> ([CGPoint],[CGPathElementType]) { var arrayPoints : [CGPoint]! = [CGPoint]() var arrayTypes : [CGPathElementType]! = [CGPathElementType]() self.forEach { element in switch (element.type) { case CGPathElementType.moveToPoint: arrayPoints.append(element.points[0]) arrayTypes.append(element.type) case .addLineToPoint: arrayPoints.append(element.points[0]) arrayTypes.append(element.type) case .addQuadCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) arrayTypes.append(element.type) arrayTypes.append(element.type) case .addCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) arrayPoints.append(element.points[2]) arrayTypes.append(element.type) arrayTypes.append(element.type) arrayTypes.append(element.type) default: break } } return (arrayPoints,arrayTypes) } } 

CGPath是一个不透明的数据types,不一定要存储所有使用的点。 除此之外,一条path可能实际上并没有画出所有用作input的点(例如,考虑Bézier控制点)。

从path中获取信息的唯一两种logging方法是使用CGPathGetBoundingBox来获取边界框,或者使用CGPathApply调用callback函数的更复杂的方法,如果CGPathElementtypes会给您一个序列。