Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the CGPoint(s) of a CGPath

How can I get an array with all the CGPoint(s) contained in a given CGPath (CGMutablePathRef)?

like image 545
jeddi Avatar asked Oct 20 '12 20:10

jeddi


1 Answers

Using Swift 2.x (for Swift 3.x, Swift 4.x and Swift 5.x read here below..) , i've found this fantastic article about C Callbacks in Swift.

Trying to obtain "all the CGPoint(s)", as explained by Lily Ballard, can be a bad idea as she said.

So, I think maybe the best way is to get the path elements points used to create a particular CGPath:

//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     } } 

With this extension you can do for example:

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 and Swift 4.1 (look below for Swift 4.2 or major..)

(there are some corrections due to syntax re-introduction of @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)     } } 

Swift > 4.1 (also Swift 5.x) and iOS 9.x and > compatible

extension CGPath {     func forEach( body: @escaping @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)     } } 
like image 71
Alessandro Ornano Avatar answered Oct 13 '22 13:10

Alessandro Ornano