Skip to content

Instantly share code, notes, and snippets.

@kakajika
Last active April 25, 2016 12:50
Show Gist options
  • Save kakajika/bf0270bf03c8fbcf39db to your computer and use it in GitHub Desktop.
Save kakajika/bf0270bf03c8fbcf39db to your computer and use it in GitHub Desktop.
Point hit tester for lines, quadratic bezier curves, and cubic bezier curves in Swift.
import UIKit
public class CurveHitTester {
typealias CurvePointMapper = (t: CGFloat, u: CGFloat) -> (x: CGFloat, y: CGFloat)
public static func hitTestLine(point: CGPoint, p1: CGPoint, p2: CGPoint, segments: Int, lineWidth: CGFloat) -> Bool {
return hitTestPoints(point, segments: segments, lineWidth: lineWidth) { (t, u) in
let x = u * p1.x + t * p2.x
let y = u * p1.y + t * p2.y
return (x, y)
}
}
public static func hitTestQuad(point: CGPoint, p1: CGPoint, c1: CGPoint, p2: CGPoint, segments: Int, lineWidth: CGFloat) -> Bool {
return hitTestPoints(point, segments: segments, lineWidth: lineWidth) { (t, u) in
let x = u * u * p1.x + 2.0 * u * t * c1.x + t * t * p2.x
let y = u * u * p1.y + 2.0 * u * t * c1.y + t * t * p2.y
return (x, y)
}
}
public static func hitTestCubic(point: CGPoint, p1: CGPoint, c1: CGPoint, c2: CGPoint, p2: CGPoint, segments: Int, lineWidth: CGFloat) -> Bool {
return hitTestPoints(point, segments: segments, lineWidth: lineWidth) { (t, u) in
let x = u * u * u * p1.x + 3.0 * u * u * t * c1.x + 3.0 * u * t * t * c2.x + t * t * t * p2.x
let y = u * u * u * p1.y + 3.0 * u * u * t * c1.y + 3.0 * u * t * t * c2.y + t * t * t * p2.y
return (x, y)
}
}
// 曲線上の点との当たり判定
// シンプルにタッチ座標周囲の円が点を含むかで判定
private static func hitTestPoints(point: CGPoint, segments: Int, lineWidth: CGFloat, toCurvePoint: CurvePointMapper) -> Bool {
guard segments > 0 else {
return false
}
let ll = lineWidth * lineWidth / 4.0
func isNearPoint(x: CGFloat, y: CGFloat) -> Bool {
let dx = point.x - x
let dy = point.y - y
return (dx*dx + dy*dy <= ll)
}
return [Int](0...segments)
.map { i in
let t = CGFloat(i) / CGFloat(segments)
return (t: t, u: 1 - t)
}
.map(toCurvePoint)
.filter(isNearPoint)
.count > 0
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment