在CGPath上获取随机CGPoint

时间:2014-06-15 02:03:15

标签: core-graphics cgpoint cgpath

我有一个代表椭圆的CGPath。我想在该路径上的随机点放置一个精灵节点。如何在CGPath上获得随机CGPoint?

2 个答案:

答案 0 :(得分:1)

谈到一个已关闭的CGPath并想到一个快速的方法来获得CGPath内无限点之间的随机点,首先我已经翻译成 Swift 这个:

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
    }

    func spriteKitCenter() ->CGPoint {
        let shape = SKShapeNode(path: self)
        return CGPointMake(CGRectGetMidX(shape.frame),CGRectGetMidY(shape.frame))
    }

    func uiKitCenter() ->CGPoint {
        let layer = CAShapeLayer()
        layer.path = self
        return CGPointMake(CGRectGetMidX(layer.frame),CGRectGetMidY(layer.frame))
    }
}

我使用了我的irregulars多边形的跟随方法,它基于三角形,所以如果你使用弧线,一些曲线部分将丢失(如果你有任何建议评论,请不要感激) :

  • 获取所有CGPath边界点(构成我路径的元素)
  • 获取CGPath
  • 的中心
  • 获取我的积分与中心之间的三角形列表
  • 从三角形列表中选择一个随机三角形
  • 选择三角形内的随机点

这是三角形方法:

func getRandomPointInTriangle (aPoint:CGPoint,bPoint:CGPoint,cPoint:CGPoint)->CGPoint {

    var randomA = CGFloat(Float(arc4random()) / Float(UINT32_MAX))
    var randomB = CGFloat(Float(arc4random()) / Float(UINT32_MAX))

    if (randomA + randomB > 1) {
        randomA = 1-randomA
        randomB = 1-randomB
    }

    let randomC = 1-randomA-randomB

    let rndX = (randomA*aPoint.x)+(randomB*bPoint.x)+(randomC*cPoint.x)
    let rndY = (randomA*aPoint.y)+(randomB*bPoint.y)+(randomC*cPoint.y)

    return CGPointMake(rndX,rndY)
}

这是主要方法:

func getRandomPoint()->CGPoint {
        let points = self.path!.getPathElementsPoints()
        let center = self.path!.spriteKitCenter()
        // divide the cgpath in triangles
        var triangles = Array<Array<CGPoint>>()
        for i in 0..<points.count-1 {
            let triangle = [center,points[i],points[i+1]]
            triangles.append(triangle)
        }
        let chooseTriangleNum = Int(arc4random()) % triangles.count
        let chooseTriangle = triangles[chooseTriangleNum]
        return getRandomPointInTriangle(chooseTriangle[0],bPoint: chooseTriangle[1],cPoint: chooseTriangle[2])
}

答案 1 :(得分:0)

原谅复活:)

取边界框并在两个相对的边上挑选两个随机点(这应该保证一条线穿过路径的某个点。

使用path.contains()走线,找到路径中的第一个点。

当然这不是随机的,因为它忽略了'内部'循环,所以如果你想要更随机,走完整行并记录所有的交叉点,然后选择一个随机的交叉点。

它仍然不是很随机,因为它有利于周边更多的“中心”点。

接下来的优化,也许你需要更快一些,而path.contains()并没有削减它。

将您的路径绘制到屏幕外位图(笔触,无填充),然后检查点是否在路径上,您只需要获得该点的颜色。这应该比path.contains()快很多。