common bezier: enhancement to the common Bezier function

Add a method that returns the angle at position 't'.
also revise bezAt() method to allow optimal usages.
This commit is contained in:
Hermet Park 2023-07-14 16:26:33 +09:00 committed by Hermet Park
parent 20cf8c6725
commit d53d8d726f
2 changed files with 30 additions and 8 deletions

View file

@ -108,26 +108,25 @@ void bezSplitLeft(Bezier& cur, float at, Bezier& left)
} }
float bezAt(const Bezier& bz, float at) float bezAt(const Bezier& bz, float at, float length)
{ {
auto len = bezLength(bz);
auto biggest = 1.0f; auto biggest = 1.0f;
auto smallest = 0.0f; auto smallest = 0.0f;
auto t = 0.5f; auto t = 0.5f;
//just in case to prevent an infinite loop //just in case to prevent an infinite loop
if (at <= 0) return 0.0f; if (at <= 0) return 0.0f;
if (at >= len) return len; if (at >= length) return length;
while (true) { while (true) {
auto right = bz; auto right = bz;
Bezier left; Bezier left;
bezSplitLeft(right, t, left); bezSplitLeft(right, t, left);
len = bezLength(left); length = bezLength(left);
if (fabsf(len - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) { if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) {
break; break;
} }
if (len < at) { if (length < at) {
smallest = t; smallest = t;
t = (t + biggest) * 0.5f; t = (t + biggest) * 0.5f;
} else { } else {
@ -142,7 +141,7 @@ float bezAt(const Bezier& bz, float at)
void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right)
{ {
right = cur; right = cur;
auto t = bezAt(right, at); auto t = bezAt(right, at, bezLength(right));
bezSplitLeft(right, t, left); bezSplitLeft(right, t, left);
} }
@ -169,4 +168,26 @@ Point bezPointAt(const Bezier& bz, float t)
return cur; return cur;
} }
float bezAngleAt(const Bezier& bz, float t)
{
if (t < 0 || t > 1) return 0;
//derivate
// p'(t) = 3 * (-(1-2t+t^2) * p0 + (1 - 4 * t + 3 * t^2) * p1 + (2 * t - 3 *
// t^2) * p2 + t^2 * p3)
float mt = 1.0f - t;
float d = t * t;
float a = -mt * mt;
float b = 1 - 4 * t + 3 * d;
float c = 2 * t - 3 * d;
Point pt ={a * bz.start.x + b * bz.ctrl1.x + c * bz.ctrl2.x + d * bz.end.x, a * bz.start.y + b * bz.ctrl1.y + c * bz.ctrl2.y + d * bz.end.y};
pt.x *= 3;
pt.y *= 3;
return atan2(pt.x, pt.y) * 180.0f / 3.141592f;
}
} }

View file

@ -39,9 +39,10 @@ struct Bezier
void bezSplit(const Bezier&cur, Bezier& left, Bezier& right); void bezSplit(const Bezier&cur, Bezier& left, Bezier& right);
float bezLength(const Bezier& cur); float bezLength(const Bezier& cur);
void bezSplitLeft(Bezier& cur, float at, Bezier& left); void bezSplitLeft(Bezier& cur, float at, Bezier& left);
float bezAt(const Bezier& bz, float at); float bezAt(const Bezier& bz, float at, float length);
void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right); void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right);
Point bezPointAt(const Bezier& bz, float t); Point bezPointAt(const Bezier& bz, float t);
float bezAngleAt(const Bezier& bz, float t);
} }