查找触摸在路径上的位置(按百分比)
Find where on a path a touch is (by percentage)
我有一个 CGPath
,在那个路径上我检测到了触摸。路径基本上是一条直线或曲线,但没有填充。这个想法是用户抚摸路径,所以无论用户沿着路径抚摸什么,我都想用不同的 stroke/color 等绘制路径
首先,为了确定触摸是否在路径内,并给用户一些错误空间,我使用了 CGPathCreateCopyByStrokingPath
和 CGPointInsidePath
。这很好用。
接下来,我需要找出用户沿着路径抚摸了多远。这就是今天的问题。
完成后,我的答案是 33%,那么我将在路径上对 strokeEnd
进行简单分配。 (两份副本,一份完整路径,一份在上面,strokeEnd
设置为到目前为止用户用手指抚摸过的完整路径的任何百分比)。
有什么想法可以找到用户手指抚摸路径的距离吗?
我有一个实用程序 class GHPathUtilies.m 其中包括一个方法:
+(CGFloat) totalLengthOfCGPath:(CGPathRef)pathRef
这都是在 Objective-C 中编写的,但大概您可以使用相同的技术沿着路径元素行走,使用 CGPathApply,直到您足够近,或者已经通过目标点。总体思路是将每个元素之间的曲线分成小线段,并保持每个线段长度的 运行 之和。
当然,如果路径本身折返,你就必须弄清楚哪个点是接触点。
我已经在这方面工作了很长时间,想分享我的答案(我就是问这个问题的人)。
- 我想检测沿路径的触摸(例如贝塞尔曲线)。问题是它只能告诉你触摸是否击中路径,但不能告诉你在哪里(使用
CGPathContainsPoint
)。
- 为避免用户准确点击路径,使用
CGPathCreateCopyByStrokingPath
) 创建一个更胖的版本,以便检查触摸。
- 主要问题仍然是,路径上的 触摸命中。我所做的是创建一个带有
CGPathCreateCopyByDashingPath
且间距最小的虚线路径副本。该路径从未实际显示。然后我通过 CGPathApply
将每个路径元素保存在数组中。 得到了它的每一部分
- 当检测到触摸并且在 "fat path" 内时,我只是循环遍历路径破折号元素数组,检查到每个起点的距离(只是常规的毕达哥拉斯)路径破折号元素。
如果触摸点距离第14个元素最近,并且有例如总共 140 个元素,这意味着我们已经完成了 10%。
- 现在我们有了百分比。我现在想要的是画出触摸的路径。我尝试在路径上使用建议的
strokeEnd
属性。这与我计算的百分比完全不符。实际上,在我看来,这是很不准确的。或者我的计算是。
无论如何,既然我们已经有了所有的路径元素,并且知道要停在哪一个(第 14 个元素),我所做的就是使用路径元素构建一条新路径。因为我不想要一条虚线路径(这只是找出触摸在长的连续路径上的位置的技巧),所以我只是跳过了所有 moveTo 路径元素(第一个元素除外)。这将创建一个连续的路径。
CGPathApply - 根据要求
// MARK: - Stuff for CGPathApply
typealias MyPathApplier = @convention(block) (UnsafePointer<CGPathElement>) -> Void
//
// Note: You must declare MyPathApplier as @convention(block), because
// if you don't, you get "fatal error: can't unsafeBitCast between
// types of different sizes" at runtime, on Mac OS X at least.
func myPathApply(path: CGPath!, block: MyPathApplier) {
let callback: @convention(c) (UnsafeMutablePointer<Void>, UnsafePointer<CGPathElement>) -> Void = { (info, element) in
let block = unsafeBitCast(info, MyPathApplier.self)
block(element)
}
CGPathApply(path, unsafeBitCast(block, UnsafeMutablePointer<Void>.self), unsafeBitCast(callback, CGPathApplierFunction.self))
}
我有一个 CGPath
,在那个路径上我检测到了触摸。路径基本上是一条直线或曲线,但没有填充。这个想法是用户抚摸路径,所以无论用户沿着路径抚摸什么,我都想用不同的 stroke/color 等绘制路径
首先,为了确定触摸是否在路径内,并给用户一些错误空间,我使用了 CGPathCreateCopyByStrokingPath
和 CGPointInsidePath
。这很好用。
接下来,我需要找出用户沿着路径抚摸了多远。这就是今天的问题。
完成后,我的答案是 33%,那么我将在路径上对 strokeEnd
进行简单分配。 (两份副本,一份完整路径,一份在上面,strokeEnd
设置为到目前为止用户用手指抚摸过的完整路径的任何百分比)。
有什么想法可以找到用户手指抚摸路径的距离吗?
我有一个实用程序 class GHPathUtilies.m 其中包括一个方法:
+(CGFloat) totalLengthOfCGPath:(CGPathRef)pathRef
这都是在 Objective-C 中编写的,但大概您可以使用相同的技术沿着路径元素行走,使用 CGPathApply,直到您足够近,或者已经通过目标点。总体思路是将每个元素之间的曲线分成小线段,并保持每个线段长度的 运行 之和。
当然,如果路径本身折返,你就必须弄清楚哪个点是接触点。
我已经在这方面工作了很长时间,想分享我的答案(我就是问这个问题的人)。
- 我想检测沿路径的触摸(例如贝塞尔曲线)。问题是它只能告诉你触摸是否击中路径,但不能告诉你在哪里(使用
CGPathContainsPoint
)。 - 为避免用户准确点击路径,使用
CGPathCreateCopyByStrokingPath
) 创建一个更胖的版本,以便检查触摸。 - 主要问题仍然是,路径上的 触摸命中。我所做的是创建一个带有
CGPathCreateCopyByDashingPath
且间距最小的虚线路径副本。该路径从未实际显示。然后我通过CGPathApply
将每个路径元素保存在数组中。 得到了它的每一部分
- 当检测到触摸并且在 "fat path" 内时,我只是循环遍历路径破折号元素数组,检查到每个起点的距离(只是常规的毕达哥拉斯)路径破折号元素。
如果触摸点距离第14个元素最近,并且有例如总共 140 个元素,这意味着我们已经完成了 10%。
- 现在我们有了百分比。我现在想要的是画出触摸的路径。我尝试在路径上使用建议的
strokeEnd
属性。这与我计算的百分比完全不符。实际上,在我看来,这是很不准确的。或者我的计算是。
无论如何,既然我们已经有了所有的路径元素,并且知道要停在哪一个(第 14 个元素),我所做的就是使用路径元素构建一条新路径。因为我不想要一条虚线路径(这只是找出触摸在长的连续路径上的位置的技巧),所以我只是跳过了所有 moveTo 路径元素(第一个元素除外)。这将创建一个连续的路径。
CGPathApply - 根据要求
// MARK: - Stuff for CGPathApply
typealias MyPathApplier = @convention(block) (UnsafePointer<CGPathElement>) -> Void
//
// Note: You must declare MyPathApplier as @convention(block), because
// if you don't, you get "fatal error: can't unsafeBitCast between
// types of different sizes" at runtime, on Mac OS X at least.
func myPathApply(path: CGPath!, block: MyPathApplier) {
let callback: @convention(c) (UnsafeMutablePointer<Void>, UnsafePointer<CGPathElement>) -> Void = { (info, element) in
let block = unsafeBitCast(info, MyPathApplier.self)
block(element)
}
CGPathApply(path, unsafeBitCast(block, UnsafeMutablePointer<Void>.self), unsafeBitCast(callback, CGPathApplierFunction.self))
}