react-native-redash
Version:
Utility library for React Native Reanimated
160 lines (148 loc) • 4.79 kB
text/typescript
import Animated from "react-native-reanimated";
import { find } from "../Array";
import { acos, approximates } from "../Math";
const {
Value,
and,
cond,
divide,
add,
multiply,
block,
greaterThan,
eq,
lessThan,
pow,
sqrt,
set,
sub,
cos,
not
} = Animated;
const isRootValidForCubicBezier = (root: Animated.Node<number>) =>
and(greaterThan(root, 0), lessThan(root, 1));
// pomax.github.io/bezierinfo/#extremities
const cuberoot = (v: Animated.Adaptable<number>) =>
cond(
lessThan(v, 0),
multiply(pow(multiply(v, -1), 1 / 3), -1),
pow(v, 1 / 3)
);
const cubicBezierSolve = (
pa: Animated.Adaptable<number>,
pb: Animated.Adaptable<number>,
pc: Animated.Adaptable<number>,
pd: Animated.Adaptable<number>
): Animated.Node<number> => {
const a: Animated.Value<number> = new Value();
const b: Animated.Value<number> = new Value();
const c: Animated.Value<number> = new Value();
const d: Animated.Value<number> = new Value();
const root1: Animated.Value<number> = new Value();
const root2: Animated.Value<number> = new Value();
const root3: Animated.Value<number> = new Value();
const q: Animated.Value<number> = new Value();
const q2: Animated.Value<number> = new Value();
const p: Animated.Value<number> = new Value();
const p3: Animated.Value<number> = new Value();
const discriminant: Animated.Value<number> = new Value();
const mp3: Animated.Value<number> = new Value();
const mp33: Animated.Value<number> = new Value();
const r: Animated.Value<number> = new Value();
const t: Animated.Value<number> = new Value();
const cosphi: Animated.Value<number> = new Value();
const phi: Animated.Value<number> = new Value();
const crtr: Animated.Value<number> = new Value();
const t1: Animated.Value<number> = new Value();
const u1: Animated.Value<number> = new Value();
const sd: Animated.Value<number> = new Value();
const v1: Animated.Value<number> = new Value();
const sq: Animated.Value<number> = new Value();
return block([
set(a, add(multiply(3, pa), multiply(-6, pb), multiply(3, pc))),
set(b, add(multiply(-3, pa), multiply(3, pb))),
set(c, pa),
set(d, add(multiply(-1, pa), multiply(3, pb), multiply(-3, pc), pd)),
cond(
approximates(d, 0),
cond(
approximates(d, 0),
cond(not(approximates(b, 0)), set(root1, divide(multiply(-1, c), b)), [
set(q, sqrt(sub(pow(b, 2), multiply(4, a, c)))),
set(root1, divide(sub(q, b), multiply(2, a))),
set(root2, divide(sub(multiply(b, -1), q), multiply(2, a)))
])
),
[
set(a, divide(a, d)),
set(b, divide(b, d)),
set(c, divide(c, d)),
set(p, divide(sub(multiply(3, b), multiply(a, a)), 3)),
set(p3, divide(p, 3)),
set(
q,
divide(
add(multiply(2, a, a, a), multiply(-9, a, b), multiply(27, c)),
27
)
),
set(q2, divide(q, 2)),
set(discriminant, add(multiply(q2, q2), multiply(p3, p3, p3))),
cond(
lessThan(discriminant, 0),
[
set(mp3, divide(multiply(p, -1), 3)),
set(mp33, multiply(mp3, mp3, mp3)),
set(r, sqrt(mp33)),
set(t, divide(multiply(q, -1), multiply(2, r))),
set(
cosphi,
cond(lessThan(t, -1), -1, cond(greaterThan(t, 1), 1, t))
),
set(phi, acos(cosphi)),
set(crtr, cuberoot(r)),
set(t1, multiply(2, crtr)),
set(root1, sub(multiply(t1, cos(divide(phi, 3))), divide(a, 3))),
set(
root2,
sub(
multiply(t1, cos(divide(add(phi, 2 * Math.PI), 3))),
divide(a, 3)
)
),
set(
root3,
sub(
multiply(t1, cos(divide(add(phi, 4 * Math.PI), 3))),
divide(a, 3)
)
)
],
cond(
eq(discriminant, 0),
[
set(
u1,
cond(
lessThan(q2, 0),
cuberoot(multiply(q2, -1)),
multiply(cuberoot(q2), -1)
)
),
set(root1, sub(multiply(2, u1), divide(a, 3))),
set(root2, sub(multiply(-1, u1), divide(a, 3)))
],
[
set(sd, sqrt(discriminant)),
set(u1, cuberoot(sub(sq, q2))),
set(v1, cuberoot(add(sq, q2))),
set(root1, sub(u1, v1, divide(a, 3)))
]
)
)
]
),
find([root1, root2, root3], isRootValidForCubicBezier)
]);
};
export default cubicBezierSolve;