Skip to content

Instantly share code, notes, and snippets.

@kybernetyk
Created October 2, 2024 12:31
Show Gist options
  • Save kybernetyk/cba65121fa7f178100a4e8fe1d575a1d to your computer and use it in GitHub Desktop.
Save kybernetyk/cba65121fa7f178100a4e8fe1d575a1d to your computer and use it in GitHub Desktop.
import CoreGraphics
func getPointOnCurve(path: CGPath, t: CGFloat) -> CGPoint? {
// Scale the curve to the unit interval
var transform = CGAffineTransform(scaleX: 1, y: 1)
let bounds = path.boundingBoxOfPath
transform = transform.scaledBy(x: 1 / bounds.width, y: 1 / bounds.height)
transform = transform.translatedBy(x: -bounds.minX, y: -bounds.minY)
guard let scaledPath = path.copy(using: &transform) else {
return nil
}
// Split the curve into segments
let dashLengths: [CGFloat] = [1, 100]
guard let dashedPath = scaledPath.copy(dashingWithPhase: 0, lengths: dashLengths) else {
return nil
}
// Find the segment that contains the point
var segmentIndex = 0
var segmentStart = CGFloat(0)
var segmentEnd = CGFloat(0)
var foundSegment = false
dashedPath.apply(info: nil) { (element, info) in
switch element.pointee.type {
case .moveToPoint:
segmentStart = CGFloat(segmentIndex)
case .addLineToPoint:
segmentEnd = CGFloat(segmentIndex + 1)
if t >= segmentStart && t < segmentEnd {
foundSegment = true
}
segmentStart = segmentEnd
default:
break
}
if foundSegment {
return false
}
segmentIndex += 1
return true
}
guard foundSegment else {
return nil
}
// Use binary search to find the parameter value that corresponds to the point
var lowerBound = segmentStart
var upperBound = segmentEnd
var currentT = (lowerBound + upperBound) / 2
var currentPoint = scaledPath.currentPoint
while abs(currentT - t) > 0.001 {
currentPoint = scaledPath.point(at: currentT)
if currentPoint.x < t {
lowerBound = currentT
} else {
upperBound = currentT
}
currentT = (lowerBound + upperBound) / 2
}
// Transform the point back to the original coordinate system
return currentPoint.applying(transform.inverted())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment