Created
March 18, 2017 16:33
-
-
Save eonist/f5bb11533ee52ce24bad3ee47044239a to your computer and use it in GitHub Desktop.
find y for x on a Cubic Curve segment
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 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 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
More discussion and original JS code here: http://stackoverflow.com/questions/5634460/quadratic-bezier-curve-calculate-point