26

特定の( )CGPointに含まれるすべての(s)を含む配列を取得するにはどうすればよいですか?CGPathCGMutablePathRef

4

4 に答える 4

63

Swift 2.xを使用して(Swift 3.xSwift 4.x、およびSwift 5.xについては、以下をお読みください。)、SwiftでのCコールバックに関するこの素晴らしい記事を見つけました。

リリー・バラードCGPointが説明したように、「すべて」を取得しようとすることは、彼女が言ったように悪い考えである可能性があります。

したがって、おそらく最良の方法は、特定の作成に使用されるパス要素のポイントを取得することだと思います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
    }
}

この拡張機能を使用すると、たとえば次のことができます。

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

Swift3.xおよびSwift4.1(Swift 4.2またはメジャーについては以下を参照してください。)

(構文の再導入によるいくつかの修正があります@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(Swift 5.xも)およびiOS9.xおよび>互換

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)
    }
}
于 2016-04-02T14:00:29.087 に答える
19

Appleは、 iOS11.0以降およびmacOS10.13以降で利用可能なインスタンスメソッド CGPath.applyWithBlockを追加しました

前の回答で説明したように、CGPath.applyを使用してパスの各要素を調べることができます。ただし、CスタイルのポインタとunsafeBitCastの使用を避けたい場合は、はるかに便利なインスタンスメソッドを使用する必要があります applyWithBlock。たとえば、CGPathのCGPointの配列を取得する場合は、CGPathに拡張機能 追加できます。この例では、CGPathのCGPointを収集する計算プロパティ(ポイント)です。

/// Extension to collect CGPath points
extension CGPath {

  /// this is a computed property, it will hold the points we want to extract
  var points: [CGPoint] {

     /// this is a local transient container where we will store our CGPoints
     var arrPoints: [CGPoint] = []

     // applyWithBlock lets us examine each element of the CGPath, and decide what to do
     self.applyWithBlock { element in

        switch element.pointee.type
        {
        case .moveToPoint, .addLineToPoint:
          arrPoints.append(element.pointee.points.pointee)

        case .addQuadCurveToPoint:
          arrPoints.append(element.pointee.points.pointee)
          arrPoints.append(element.pointee.points.advanced(by: 1).pointee)

        case .addCurveToPoint:
          arrPoints.append(element.pointee.points.pointee)
          arrPoints.append(element.pointee.points.advanced(by: 1).pointee)
          arrPoints.append(element.pointee.points.advanced(by: 2).pointee)

        default:
          break
        }
     }

    // We are now done collecting our CGPoints and so we can return the result
    return arrPoints

  }
}
于 2018-11-13T13:36:03.777 に答える
15

CGPathApply()を使用して、パス内のすべてのセグメントを反復処理し、そのセグメントでカスタム関数を実行できます。これにより、パスに含まれるすべての情報が得られます。

ただし、「すべてのCGPoint」とは、ピクセルがレンダリングされているすべてのポイントを意味する場合、それは無限のサイズのセットです。確かにapply関数を使用して各セグメントを取得し、次に移動しないすべてのセグメントについて、セグメントのコントロールポイントを使用して独自の計算を評価し、必要な密度のポイントのリストを取得できます。

于 2012-10-20T20:45:25.810 に答える
6

ACGPathは不透明(OPAQUE)型であり、使用されるすべてのポイントを格納する必要はありません。これに加えて、パスは実際に入力として使用されるすべてのポイントを描画しない場合があります(たとえば、ベジェコントロールポイントを検討してください)。

パスから情報を取得するための文書化された2つの方法は、バウンディングボックスを取得するために使用する方法、またはタイプの場合にシーケンスを提供するコールバック関数を呼び出すためCGPathGetBoundingBoxに使用するより複雑な方法です。CGPathApplyCGPathElement

于 2012-10-20T20:48:44.537 に答える