Last active
April 25, 2016 12:50
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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