如何获得CGPath的CGPoint(s)

时间:2023-02-05 20:45:02

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

如何获得包含在给定CGPath (CGMutablePathRef)中的所有CGPoint(s)的数组?

3 个解决方案

#1


13  

You can use CGPathApply() to iterate over every segment in the path and run a custom function with that segment. That will give you all the information the path has.

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

However, if by "all the CGPoint(s)", you meant every point that has a pixel rendered to it, that's an infinitely-sized set. Although you could certainly use the apply function to get each segment, and then for every non-move segment, evaluate your own math with the segment's control points to get a list of points at whatever density you want.

然而,如果使用“所有CGPoint(s)”,你意味着每一个点,一个像素呈现,这是一个infinitely-sized集。尽管你当然可以使用应用函数每一部分,然后每non-move段,评估自己的数学部分的控制点,在任何你想要的密度点的列表。

#2


30  

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

使用快速2。x(斯威夫特3。x和斯威夫特4。我发现了这篇关于C回调的精彩文章。

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

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

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

所以,我认为最好的方法是获取创建特定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.x

(there are some corrections due to syntax re-introduction of @convention(c)):

(由于@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)
    }
}

#3


4  

A CGPath is an opaque data type and does not necessarily store all the points used. In addition to this, a path may not actually draw all the points used as input (for example, consider Bézier control points).

CGPath是一种不透明的数据类型,并不一定要存储所使用的所有点。除此之外,路径可能不会实际绘制作为输入的所有点(例如,考虑Bezier控制点)。

The only two documented ways of getting information out of a path is to use CGPathGetBoundingBox to get the bounding box, or the more complicated method of using CGPathApply to call a callback function that will give you a sequence if CGPathElement types.

从路径中获取信息的惟一两种文档化方法是使用CGPathGetBoundingBox来获取边界框,或者使用CGPathApply调用回调函数的更复杂的方法,如果CGPathElement类型,这个回调函数将给您一个序列。

#1


13  

You can use CGPathApply() to iterate over every segment in the path and run a custom function with that segment. That will give you all the information the path has.

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

However, if by "all the CGPoint(s)", you meant every point that has a pixel rendered to it, that's an infinitely-sized set. Although you could certainly use the apply function to get each segment, and then for every non-move segment, evaluate your own math with the segment's control points to get a list of points at whatever density you want.

然而,如果使用“所有CGPoint(s)”,你意味着每一个点,一个像素呈现,这是一个infinitely-sized集。尽管你当然可以使用应用函数每一部分,然后每non-move段,评估自己的数学部分的控制点,在任何你想要的密度点的列表。

#2


30  

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

使用快速2。x(斯威夫特3。x和斯威夫特4。我发现了这篇关于C回调的精彩文章。

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

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

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

所以,我认为最好的方法是获取创建特定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.x

(there are some corrections due to syntax re-introduction of @convention(c)):

(由于@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)
    }
}

#3


4  

A CGPath is an opaque data type and does not necessarily store all the points used. In addition to this, a path may not actually draw all the points used as input (for example, consider Bézier control points).

CGPath是一种不透明的数据类型,并不一定要存储所使用的所有点。除此之外,路径可能不会实际绘制作为输入的所有点(例如,考虑Bezier控制点)。

The only two documented ways of getting information out of a path is to use CGPathGetBoundingBox to get the bounding box, or the more complicated method of using CGPathApply to call a callback function that will give you a sequence if CGPathElement types.

从路径中获取信息的惟一两种文档化方法是使用CGPathGetBoundingBox来获取边界框,或者使用CGPathApply调用回调函数的更复杂的方法,如果CGPathElement类型,这个回调函数将给您一个序列。