CAShapeLayer.线是否通过该点?

Мих*_*аил 1 ios swift swift2 swift3

我使用CAShapeLayer在屏幕上画一条线.在touchesEnded方法中,我想检查"线是否通过该点?".在我的代码中,当我按下屏幕的任何部分时,该方法包含返回始终为true.也许,我在line.frame =(view?.bounds)遇到了问题!.我该如何解决?对不起,我的英语不好.

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    let touch = touches.first
    let firstPosition = touch?.location(in: self)

    if atPoint(firstPosition!) == lvl1 {

        let firstPositionX = firstPosition?.x
        let firstPositionY = frame.size.height - (firstPosition?.y)!
        view?.layer.addSublayer(line)
        line.lineWidth = 8
        let color = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1).cgColor
        line.strokeColor = color
        line.fillColor = nil
        line.frame = (view?.bounds)!
        path.move(to: CGPoint(x: firstPositionX!, y: firstPositionY))

    }

}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    let touch = touches.first
    let firstPosition = touch?.location(in: self)

    if atPoint(firstPosition!) == lvl1 {

        let firstPositionX = firstPosition?.x
        let firstPositionY = frame.size.height - (firstPosition?.y)!
        path.addLine(to: CGPoint(x: firstPositionX!, y: firstPositionY))
        line.path = path.cgPath

    }
}


override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

    if line.contains(screenCenterPoint) {
        print("ok")
    }

}
Run Code Online (Sandbox Code Playgroud)

Dam*_*aux 5

问题

如果图层的边界包含点func contains(_ p: CGPoint) -> Bool,则CAShapeLayer返回的方法.(见文件)true

所以你不能用它来检查线是否包含一个点.

但是,在类CGPath中具有相同名称的另一个方法返回指定的点是否在路径的内部.但是,由于你只是抚摸你的路径并且你没有填充内部,这种方法也不会给出期望的结果.

诀窍是使用以下方法创建路径轮廓:

let outline = path.cgPath.copy(strokingWithWidth: line.lineWidth, lineCap: .butt, lineJoin: .round, miterLimit: 0)
Run Code Online (Sandbox Code Playgroud)

然后检查轮廓内部是否包含您的 screenCenterPoint

if outline.contains(screenCenterPoint) {
    print("ok")
}
Run Code Online (Sandbox Code Playgroud)

中风与大纲

性能考虑因素

由于您只在触摸结束时检查包含,我认为创建路径轮廓不会增加太多开销.

当您想要实时检查包含时,例如在touchesMoved函数内部,计算轮廓可能会产生一些开销,因为这种方法每秒被调用很多次.路径越长,计算轮廓所需的时间越长.

因此,实时最好只生成最后绘制的段的轮廓,然后检查该轮廓是否包含您的点.

如果您想严肃地减少开销,可以编写自己的包含功能.直线点的遏制相当简单,可以简化为以下公式:

给定一个从线startendwidth和点p

计算:

  • dx = start.x - end.x
  • dy = start.y - end.y
  • a = dy * p.x - dx * p.y + end.x * start.y - end.y * start.x
  • b = hypot(dy, dx)

该行包含点,p如果:

abs(a/b) < width/2 p在该行的边界框中.