Skip to content

Instantly share code, notes, and snippets.

@rlaguilar
Forked from swillits/Interpolation.swift
Created July 9, 2019 09:17
Show Gist options
  • Save rlaguilar/3a4ad083f697f00dcb00eb1f59c5bf6d to your computer and use it in GitHub Desktop.
Save rlaguilar/3a4ad083f697f00dcb00eb1f59c5bf6d to your computer and use it in GitHub Desktop.
import Foundation
import CoreGraphics
/*
Usage:
Interpolate(.linear).between(x, and: y, progress: progress) // progress is 0 to 1
*/
enum InterpolationCurveType {
case linear
}
func Interpolate(_ curveType: InterpolationCurveType) -> InterpolationCurve {
switch curveType {
case .linear:
return LinearInterpolation
}
}
struct InterpolationCurve {
let valueForProgress: (_ progress: Double) -> Double
init(_ block: @escaping (_ progress: Double) -> Double) {
valueForProgress = block
}
}
let LinearInterpolation = InterpolationCurve { (_ progress: Double) -> Double in
return progress
}
extension InterpolationCurve {
func between(_ from: Double, and to: Double, progress: Double) -> Double {
let cv = valueForProgress(progress)
return (1.0 - cv) * from + cv * to
}
func between(_ from: Float, and to: Float, progress: Double) -> Float {
let cv = valueForProgress(progress)
return Float(1.0 - cv) * from + Float(cv) * to
}
func between(_ from: CGFloat, and to: CGFloat, progress: Double) -> CGFloat {
let cv = valueForProgress(progress)
return CGFloat(1.0 - cv) * from + CGFloat(cv) * to
}
func between(_ from: CGPoint, and to: CGPoint, progress: Double) -> CGPoint {
let x = between(from.x, and: to.x, progress: progress)
let y = between(from.y, and: to.y, progress: progress)
return CGPoint(x: x, y: y)
}
func between(_ from: CGSize, and to: CGSize, progress: Double) -> CGSize {
let width = between(from.width, and: to.width, progress: progress)
let height = between(from.height, and: to.height, progress: progress)
return CGSize(width: width, height: height)
}
func between(_ from: CGRect, and to: CGRect, progress: Double) -> CGRect {
let origin = between(from.origin, and: to.origin, progress: progress)
let size = between(from.size, and: to.size, progress: progress)
return CGRect(origin: origin, size: size)
}
func between(_ from: CGAffineTransform, and to: CGAffineTransform, progress: Double) -> CGAffineTransform {
let tx1 = from.translationX
let tx2 = to.translationX
let tx = between(tx1, and: tx2, progress: progress)
let ty1 = from.translationY
let ty2 = to.translationY
let ty = between(ty1, and: ty2, progress: progress)
let sx1 = from.scaleX
let sx2 = to.scaleX
let sx = between(sx1, and: sx2, progress: progress)
let sy1 = from.scaleY
let sy2 = to.scaleY
let sy = between(sy1, and: sy2, progress: progress)
let deg1 = from.rotationDegrees
let deg2 = to.rotationDegrees
let deg = between(deg1, and: deg2, progress: progress)
return CGAffineTransform.makeCorrectly(tx, ty, sx, sy, deg)
}
}
extension CGAffineTransform {
var translationX: CGFloat { return tx }
var translationY: CGFloat { return ty }
var scaleX: CGFloat { return sqrt(a * a + c * c) }
var scaleY: CGFloat { return sqrt(b * b + d * d) }
var rotationDegrees: CGFloat { return (atan2(b, a) * 180) / CGFloat(M_PI_2) }
/// `CGAffineTransformMake()`, The Right Way™
///
/// - parameter tx: translation on x axis.
/// - parameter ty: translation on y axis.
/// - parameter sx: scale factor for width.
/// - parameter sy: scale factor for height.
/// - parameter deg: degrees.
static func makeCorrectly(_ tx: CGFloat, _ ty: CGFloat, _ sx: CGFloat, _ sy: CGFloat, _ deg: CGFloat) -> CGAffineTransform {
let translationTransform = CGAffineTransform(translationX: tx, y: ty)
let scaleTransform = CGAffineTransform(scaleX: sx, y: sy)
let rotationTransform = CGAffineTransform(rotationAngle: deg * CGFloat(M_PI_2) / 180.0)
return translationTransform.concatenating(scaleTransform).concatenating(rotationTransform)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment