如何检测 UIBezierPath 的交集并将其擦除
How to detect intersection of a UIBezierPath and erase it
我正在制作一个 iOS
绘图应用程序,并希望添加擦除 UIBezierPath
将擦除整个路径而不仅仅是用白色覆盖该部分的功能。
我存储了一个 UIBezierPaths
的数组,但我不确定为每个触摸点循环遍历整个数组、检测它是否与当前触摸点相交并删除它的效率如何从阵列。
有什么建议吗?
如果我理解正确的话,你至少需要遍历路径。他们毕竟是独立的
一个 UIBezierPaths
有方法 contains
可以告诉你一个点是否在路径内。如果那是可用的,那么您需要做的就是
paths = paths.filter { ![=10=].contains(touchPoint) }
但由于这是绘图应用程序,因此可以安全地假设您使用的是描边而不是填充,这很可能无法按照您希望的方式与 contains
一起使用。
你可以手动做交点,它应该有相对较好的性能,直到你有太多的点。但是当你有太多点时,我打赌绘图性能会更受你的关注。包含一些笔划线宽度的交叉点仍然可能有点问题;用户需要穿过你的线的中心才能检测到命中。
有一种方法可以将描边路径转换为填充路径。这样做将使您能够使用 contains
方法。该方法称为 replacePathWithStrokedPath
,但问题是它仅存在于 CGContext
上(至少我从未设法在 UIBezierPath
上找到等效方法)。因此,这样做的过程包括创建上下文。例如这样的东西会起作用:
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)
}
所以结果应该类似于:
static func filterPaths(_ paths: [UIBezierPath], containingPoint point: CGPoint) -> [UIBezierPath] {
return paths.filter { !(try! convertStrokePathToFillPath([=12=]).contains(point)) }
}
我正在制作一个 iOS
绘图应用程序,并希望添加擦除 UIBezierPath
将擦除整个路径而不仅仅是用白色覆盖该部分的功能。
我存储了一个 UIBezierPaths
的数组,但我不确定为每个触摸点循环遍历整个数组、检测它是否与当前触摸点相交并删除它的效率如何从阵列。
有什么建议吗?
如果我理解正确的话,你至少需要遍历路径。他们毕竟是独立的
一个 UIBezierPaths
有方法 contains
可以告诉你一个点是否在路径内。如果那是可用的,那么您需要做的就是
paths = paths.filter { ![=10=].contains(touchPoint) }
但由于这是绘图应用程序,因此可以安全地假设您使用的是描边而不是填充,这很可能无法按照您希望的方式与 contains
一起使用。
你可以手动做交点,它应该有相对较好的性能,直到你有太多的点。但是当你有太多点时,我打赌绘图性能会更受你的关注。包含一些笔划线宽度的交叉点仍然可能有点问题;用户需要穿过你的线的中心才能检测到命中。
有一种方法可以将描边路径转换为填充路径。这样做将使您能够使用 contains
方法。该方法称为 replacePathWithStrokedPath
,但问题是它仅存在于 CGContext
上(至少我从未设法在 UIBezierPath
上找到等效方法)。因此,这样做的过程包括创建上下文。例如这样的东西会起作用:
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)
}
所以结果应该类似于:
static func filterPaths(_ paths: [UIBezierPath], containingPoint point: CGPoint) -> [UIBezierPath] {
return paths.filter { !(try! convertStrokePathToFillPath([=12=]).contains(point)) }
}