common/math: introduced custom atan2()

the custom atan2 algorithm by Remez.
see: https://en.wikipedia.org/wiki/Remez_algorithm

This improved the Lottie example by ~2ms.
Total atan2 performance time was reduced by 43%
This commit is contained in:
Hermet Park 2024-07-09 14:00:26 +09:00 committed by Hermet Park
parent 8c4102362f
commit 79cf7ca5af
9 changed files with 29 additions and 12 deletions

View file

@ -238,7 +238,7 @@ float bezAngleAt(const Bezier& bz, float t)
pt.x *= 3;
pt.y *= 3;
return mathRad2Deg(atan2(pt.y, pt.x));
return mathRad2Deg(mathAtan2(pt.y, pt.x));
}

View file

@ -22,6 +22,20 @@
#include "tvgMath.h"
//see: https://en.wikipedia.org/wiki/Remez_algorithm
float mathAtan2(float y, float x)
{
if (y == 0.0f) return 0.0f;
auto a = std::min(fabsf(x), fabsf(y)) / std::max(fabsf(x), fabsf(y));
auto s = a * a;
auto r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a;
if (fabsf(y) > fabsf(x)) r = 1.57079637f - r;
if (x < 0) r = 3.14159274f - r;
if (y < 0) return -r;
return r;
}
bool mathInverse(const Matrix* m, Matrix* out)
{

View file

@ -39,6 +39,7 @@
/* General functions */
/************************************************************************/
float mathAtan2(float y, float x);
static inline float mathDeg2Rad(float degree)
{
@ -76,7 +77,7 @@ bool operator==(const Matrix& lhs, const Matrix& rhs);
static inline bool mathRightAngle(const Matrix* m)
{
auto radian = fabsf(atan2f(m->e21, m->e11));
auto radian = fabsf(mathAtan2(m->e21, m->e11));
if (radian < FLOAT_EPSILON || mathEqual(radian, MATH_PI2) || mathEqual(radian, MATH_PI)) return true;
return false;
}

View file

@ -724,10 +724,10 @@ static void _updateStar(LottieGroup* parent, LottiePolyStar* star, Matrix* trans
y = radius * sinf(angle);
if (hasRoundness) {
auto cp1Theta = (atan2f(previousY, previousX) - MATH_PI2 * direction);
auto cp1Theta = (mathAtan2(previousY, previousX) - MATH_PI2 * direction);
auto cp1Dx = cosf(cp1Theta);
auto cp1Dy = sinf(cp1Theta);
auto cp2Theta = (atan2f(y, x) - MATH_PI2 * direction);
auto cp2Theta = (mathAtan2(y, x) - MATH_PI2 * direction);
auto cp2Dx = cosf(cp2Theta);
auto cp2Dy = sinf(cp2Theta);
@ -810,10 +810,10 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr
y = (radius * sinf(angle));
if (hasRoundness) {
auto cp1Theta = atan2f(previousY, previousX) - MATH_PI2 * direction;
auto cp1Theta = mathAtan2(previousY, previousX) - MATH_PI2 * direction;
auto cp1Dx = cosf(cp1Theta);
auto cp1Dy = sinf(cp1Theta);
auto cp2Theta = atan2f(y, x) - MATH_PI2 * direction;
auto cp2Theta = mathAtan2(y, x) - MATH_PI2 * direction;
auto cp2Dx = cosf(cp2Theta);
auto cp2Dy = sinf(cp2Theta);

View file

@ -20,6 +20,7 @@
* SOFTWARE.
*/
#include "tvgMath.h"
#include "tvgPaint.h"
#include "tvgFill.h"
#include "tvgLottieModel.h"
@ -249,7 +250,7 @@ Fill* LottieGradient::fill(float frameNo, LottieExpressions* exps)
P(static_cast<RadialGradient*>(fill))->radial(s.x, s.y, r, s.x, s.y, 0.0f);
} else {
if (mathEqual(progress, 1.0f)) progress = 0.99f;
auto startAngle = mathRad2Deg(atan2(e.y - s.y, e.x - s.x));
auto startAngle = mathRad2Deg(mathAtan2(e.y - s.y, e.x - s.x));
auto angle = mathDeg2Rad((startAngle + this->angle(frameNo, exps)));
auto fx = s.x + cos(angle) * progress * r;
auto fy = s.y + sin(angle) * progress * r;

View file

@ -156,7 +156,7 @@ struct LottieVectorFrame
{
if (!hasTangent) {
Point dp = next->value - value;
return mathRad2Deg(atan2(dp.y, dp.x));
return mathRad2Deg(mathAtan2(dp.y, dp.x));
}
auto t = (frameNo - no) / (next->no - no);

View file

@ -194,10 +194,10 @@ void _pathAppendArcTo(Array<PathCommand>* cmds, Array<Point>* pts, Point* cur, P
//We dont' use arccos (as per w3c doc), see
//http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
//Note: atan2 (0.0, 1.0) == 0.0
at = atan2(((y1p - cyp) / ry), ((x1p - cxp) / rx));
at = mathAtan2(((y1p - cyp) / ry), ((x1p - cxp) / rx));
theta1 = (at < 0.0f) ? 2.0f * MATH_PI + at : at;
nat = atan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
nat = mathAtan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
deltaTheta = (nat < at) ? 2.0f * MATH_PI - at + nat : nat - at;
if (sweep) {

View file

@ -20,6 +20,7 @@
* SOFTWARE.
*/
#include "tvgMath.h"
#include "tvgGlTessellator.h"
#include "tvgRender.h"
#include "tvgGlList.h"
@ -780,7 +781,7 @@ static int32_t _bezierCurveCount(const Bezier &curve)
static Bezier _bezFromArc(const GlPoint& start, const GlPoint& end, float radius) {
// Calculate the angle between the start and end points
float angle = atan2(end.y - start.y, end.x - start.x);
float angle = mathAtan2(end.y - start.y, end.x - start.x);
// Calculate the control points of the cubic bezier curve
float c = radius * 0.552284749831; // c = radius * (4/3) * tan(pi/8)

View file

@ -179,7 +179,7 @@ SwFixed mathTan(SwFixed angle)
SwFixed mathAtan(const SwPoint& pt)
{
if (pt.zero()) return 0;
return SwFixed(atan2f(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f);
return SwFixed(mathAtan2(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f);
}