How to get the CGPoint(s) of a CGPath

前端 未结 4 1184
天命终不由人
天命终不由人 2020-11-27 04:22

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

4条回答
  •  夕颜
    夕颜 (楼主)
    2020-11-27 04:53

    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, element: UnsafePointer) {
                let body = unsafeBitCast(info, Body.self)
                body(element.memory)
            }
            print(sizeofValue(body))
            let unsafeBody = unsafeBitCast(body, UnsafeMutablePointer.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) -> 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) -> 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)
        }
    }
    

提交回复
热议问题