【问题标题】:CAShapeLayer. Does the line pass through the point?CAShapeLayer。线是否通过点?
【发布时间】:2018-01-13 21:34:51
【问题描述】:

我使用 CAShapeLayer 来在屏幕上画一条线。在 touchesEnded 方法中,我想检查“线是否通过点?”。在我的代码中,当我按下屏幕的任何部分时,方法 contains 总是返回 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")
    }

}

【问题讨论】:

标签: ios swift swift3 swift2


【解决方案1】:

问题

如果图层的bounds包含该点,CAShapeLayer 的方法func contains(_ p: CGPoint) -&gt; Bool 将返回true。 (see documentation)

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

但是,CGPath 类中还有另一个同名方法,它返回指定点是否为 interior 到路径。但由于您只描边您的路径而不是填充内部,因此此方法也不会给出预期的结果。

解决方案

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

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

然后检查大纲的内部是否包含你的screenCenterPoint

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

性能考虑

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

当您想要实时检查包含情况时,例如在touchesMoved 函数中,计算轮廓可能会产生一些开销,因为此方法每秒调用很多次。此外,路径越长,计算轮廓所需的时间就越长。

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

如果你想认真减少开销,你可以编写自己的包含函数。在一条直线上包含一个点相当简单,可以简化为以下公式:

给定一条从startend 的线,width 和一个点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) &lt; width/2 并且 p在行的边界框内。

【讨论】:

  • 惊人的答案!
猜你喜欢
  • 1970-01-01
  • 2013-05-16
  • 1970-01-01
  • 2018-08-24
  • 2018-04-11
  • 2021-07-11
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
相关资源
最近更新 更多