Cubic.jsx (2135B)
1 import { useContext } from 'preact/hooks'; 2 import { PlotContext } from '../../scripts/contexts.js'; 3 import { getColourClass, getSymmetricBounds } from '../../scripts/graphUtils.js'; 4 5 function getDepressedCubicRoots(a, b, c, d) { 6 // https://en.wikipedia.org/wiki/Cubic_equation#Depressed_cubic 7 const p = (3*a*c - b*b) / (3*a*a); 8 const q = (2*b*b*b - 9*a*b*c + 27*a*a*d) / (27*a*a*a); 9 const discriminantish = q*q/4 + p*p*p/27; 10 11 if (discriminantish > 0) { 12 // https://en.wikipedia.org/wiki/Cubic_equation#Cardano's_formula 13 const sqrt = Math.sqrt(discriminantish); 14 const root = Math.cbrt(-q/2 + sqrt) + Math.cbrt(-q/2 - sqrt); 15 return [root]; 16 } 17 18 if (discriminantish === 0) { 19 // https://en.wikipedia.org/wiki/Cubic_equation#Multiple_root 20 if (p === 0) return [0,0,0]; 21 const doubleRoot = -3*q/(2*p); 22 return [3*q/p, doubleRoot, doubleRoot]; 23 } 24 25 // https://en.wikipedia.org/wiki/Cubic_equation#Trigonometric_and_hyperbolic_solutions 26 const cosCoef = 2*Math.sqrt(-p/3); 27 const arccosine = 1/3 * Math.acos(3*q/(2*p) * Math.sqrt(-3/p)); 28 const kCoef = 2*Math.PI / 3; 29 return [0,1,2].map(k => cosCoef * Math.cos(arccosine - kCoef * k)); 30 } 31 32 export default function Cubic({ a=1, b=0, c=0, d=0, colour="auto" }) { 33 const p = useContext(PlotContext); 34 // https://math.stackexchange.com/questions/3356084/to-construct-a-polynomial-using-b%C3%A9zier-curves 35 // http://graphics.stanford.edu/courses/cs164-09-spring/Handouts/handout19.pdf 36 function G(u, v, w) { return a*u*v*w + b*(v*w + w*u + u*v)/3 + c*(u + v + w)/3 + d; } 37 38 const midX = -b / (3*a); 39 40 const intercepts = [ 41 ...getDepressedCubicRoots(a,b,c,d - p.minY), 42 ...getDepressedCubicRoots(a,b,c,d - p.maxY) 43 ]; 44 const dx = Math.max(...intercepts.map(x => Math.abs(x))); 45 46 const [i, f] = getSymmetricBounds(midX, dx, p); 47 48 // https://math.stackexchange.com/questions/2414459/draw-cubic-polynomial-using-2d-cubic-bezier-curve 49 const x1 = 2/3 * i + 1/3 * f; 50 const x2 = 1/3 * i + 2/3 * f; 51 52 d = `M ${i},${G(i,i,i)} C ${x1},${G(i,i,f)} ${x2},${G(i,f,f)} ${f},${G(f,f,f)}`; 53 return <path d={d} class={getColourClass(colour)} /> 54 }