简体   繁体   English

如何检测并删除UIBezierPath的交集

[英]How to detect intersection of a UIBezierPath and erase it

I am making an iOS drawing app and would like to add functionality where erasing a UIBezierPath will erase the whole path and not just overlay the segment with a white color. 我正在制作一个iOS绘图应用程序,并想添加一些功能,其中擦除UIBezierPath会擦除整个路径,而不仅仅是用白色覆盖该段。

I have an array of UIBezierPaths stored, but I am not sure how efficient it is to loop through the entire array for each touch point, detect if it intersects with the current touch point, and remove it from the array. 我存储了一个UIBezierPaths数组,但不确定每个接触点遍历整个数组,检测它是否与当前接触点相交并将其从数组中删除,效率如何。

Any suggestions? 有什么建议么?

If I understand correctly you need to loop through path at least. 如果我正确理解,则至少需要遍历路径。 They are independent after all. 他们毕竟是独立的。

An UIBezierPaths has method contains which would tell you if a point is inside the path. 一个UIBezierPaths有方法contains这会告诉你,如果一个点是路径内。 If that is usable then what you need to do is simply 如果这是可用的,那么您需要做的就是

paths = paths.filter { !$0.contains(touchPoint) }

But since this is drawing app it is safe to assume you are using stroke and not fill which will most likely not work with contains the way you want it to. 但是由于这是绘图应用程序,因此可以安全地假设您正在使用笔触而不是填充,这很可能无法使用contains您想要的方式。

You could do the intersection manually and it should have relatively good performance up until you have too many points. 您可以手动进行交点,直到交点过多为止,它应该具有相对较好的性能。 But when you have too many points I wager drawing performance will be more of your concern. 但是,当您的分数过多时,我会更关注下注性能。 Still the intersection may be a bit problematic with including some stroke line width; 在包含一些笔划线宽时,交点仍然可能会有些问题。 user would need to cross the center of your line to detect a hit. 用户需要越过您的行的中心才能检测到点击。

There is a way though to convert stroked path to filled path. 但是,有一种方法可以将描边路径转换为填充路径。 Doing that will then enable you to use contains method. 这样做将使您能够使用contains方法。 The method is called replacePathWithStrokedPath but the thing is that it only exists on CGContext (At least I have never managed to find an equivalent on UIBezierPath ). 该方法称为replacePathWithStrokedPath但事实是它仅存在于CGContext (至少我从未设法在UIBezierPath上找到等效UIBezierPath )。 So procedure to do so includes creating a context. 因此,此过程包括创建上下文。 For instance something like this will work: 例如这样的事情将工作:

static func convertStrokePathToFillPath(_ path: UIBezierPath) throws -> UIBezierPath {
    UIGraphicsBeginImageContextWithOptions(CGSize(width: 1.0, height: 1.0), true, 1.0)
    guard let context = UIGraphicsGetCurrentContext() else { throw NSError(domain: "convertStrokePathToFillPath", code: 500, userInfo: ["dev_message":"Could not generate image context"]) }

    context.addPath(path.cgPath)
    context.setLineWidth(path.lineWidth)
    // TODO: apply all possible settings from path to context
    context.replacePathWithStrokedPath()

    guard let returnedPath = context.path else { throw NSError(domain: "convertStrokePathToFillPath", code: 500, userInfo: ["dev_message":"Could not get path from context"]) }
    UIGraphicsEndImageContext()

    return UIBezierPath(cgPath: returnedPath)
}

So the result should look something like: 因此结果应类似于:

static func filterPaths(_ paths: [UIBezierPath], containingPoint point: CGPoint) -> [UIBezierPath] {
    return paths.filter { !(try! convertStrokePathToFillPath($0).contains(point)) }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM