Skip to content

Instantly share code, notes, and snippets.

@eonist
Created March 18, 2017 16:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eonist/f5bb11533ee52ce24bad3ee47044239a to your computer and use it in GitHub Desktop.
Save eonist/f5bb11533ee52ce24bad3ee47044239a to your computer and use it in GitHub Desktop.
find y for x on a Cubic Curve segment
import Foundation
class CubicCurveUtils {
/**
* Returns Y given X on a CubicPath segment
* PARAM: p0: prev end point
* PARAM: c0: controllpoint 1 for prev end point
* PARAM: c1: control point 2 for end point
* PARAM: p1: end point
*/
static func point(_ p0:CGPoint,_ c0:CGPoint,_ c1:CGPoint,_ p1:CGPoint,_ x:CGFloat)->CGPoint{
let a:CGFloat = p0.x
let b:CGFloat = c0.x
let c:CGFloat = c1.x
let d:CGFloat = p1.x
/**/
let A:CGFloat = d - 3*c + 3*b - a
let B:CGFloat = 3*c - 6*b + 3*a
let C:CGFloat = 3*b - 3*a
let D:CGFloat = a-x
/*So we need to solve At³ + Bt² + Ct + D = 0*/
let t:CGFloat = Utils.cubic(A,B,C,D);
/*Replace the t on Bezier function and get x,y */
let p:CGPoint = Utils.point(p0,c0,c1,p1,t)
return p
}
}
private class Utils{
/**
* Returns point on a CubicCurve for PARAM: t (0-1)
*/
static func point(_ a:CGPoint,_ b:CGPoint,_ c:CGPoint,_ d:CGPoint,_ t:CGFloat)->CGPoint{
var point:CGPoint = CGPoint(x:0,y:0)
let mt:CGFloat = 1-t
let mt2:CGFloat = mt*mt
let mt3:CGFloat = mt2*mt
/*fx(t) = x1 * (1-t)³ + x2 * 3 * (1-t)²t + x3 * 3 * (1-t)t² + x4 * t³*/
point.x = a.x*mt3 + b.x*3*mt2*t + c.x*3*mt*t*t + d.x*t*t*t
/*fy(t) = y1 * (1-t)³ + y2 * 3 * (1-t)²t + y3 * 3 * (1-t)t² + y4 * t³*/
point.y = a.y*mt3 + b.y*3*mt2*t + c.y*3*mt*t*t + d.y*t*t*t
return point
}
/**
* Cubic Equation Calculator
* refer to http://www.1728.org/cubic.htm
* FORMULA: ax³ + bx² + cx + d = 0
* PARAMS: a,b,c,d
* RETURNS: x
*/
static func cubic(_ a:CGFloat,_ b:CGFloat,_ c:CGFloat,_ d:CGFloat)->CGFloat{
var d:CGFloat = d//may not work, could be inout?!? seems to work regardless
var m:CGFloat = 0
var m2:CGFloat = 0
var k:CGFloat = 0
var n:CGFloat = 0
var n2:CGFloat = 0
var x:CGFloat = 0
var r:CGFloat = 0
var rc:CGFloat = 0
var theta:CGFloat = 0
var sign:CGFloat = 0
var dans:CGFloat = 0
/**/
let f:CGFloat = (((3*c)/a) - (((b*b)/(a*a))))/3;
/**/
let b3:CGFloat = b*b*b
let a3:CGFloat = a*a*a
let a2:CGFloat = a*a
/**/
let g:CGFloat = ((2*((b3)/(a3))-(9*b*c/(a2)) + ((27*(d/a)))))/27
/**/
let h:CGFloat = (((g*g)/4) + ((f*f*f)/27));
/**/
if (h > 0) {
m = (-(g/2) + (sqrt(h)))
k = m < 0 ? -1:1
m2 = (pow((m*k),(1/3)))
m2 = m2*k
n = (-(g/2) - (sqrt(h)))
k = n<0 ? -1:1
n2 = (pow((n*k),(1/3)))
n2 = n2*k
x = ((m2 + n2) - (b/(3*a)))
}else {
r = ((sqrt((g*g/4)-h)))
k = r<0 ? -1:1
rc = pow((r*k),(1/3))*k
theta = acos((-g/(2*r)))
x = (2*(rc*cos(theta/3))-(b/(3*a)))
x=x*1E+14
x=round(x)
x=(x/1E+14)
}
if ((f+g+h)==0){
if (d<0) {
sign = sign - 1
}
if (d>=0) {
sign = 1
}
if (sign>0){
dans = pow(d/a,1/3)
dans = dans * -1
}
if (sign<0){
d = d * -1
dans = pow(d/a,1/3)
}
x = dans
}
return x
}
}
@eonist
Copy link
Author

eonist commented Mar 18, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment