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类型,这个回调函数将给您一个序列。