From 5e29f2c1b7844492c5ccaf194f524fe810947c3f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 15 Oct 2024 20:11:33 +0200 Subject: [PATCH] fixed atan2_t approximation was incorrect, now doing it right. also removed hypotf() from octopus, saving a little flash. --- wled00/FX.cpp | 6 ++++-- wled00/wled_math.cpp | 39 +++++++++++++++++---------------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 338dd2df9..5b4513dc7 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7749,8 +7749,10 @@ uint16_t mode_2Doctopus() { const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = 40.7436f * atan2_t((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI - rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp; //thanks Sutaburosu + rMap[XY(x, y)].angle = int(40.7436f * atan2_t((y - C_Y), (x - C_X))); // avoid 128*atan2()/PI + int dx = (x - C_X); + int dy = (y - C_Y); + rMap[XY(x, y)].radius = sqrtf(dx * dx + dy * dy) * mapp; //thanks Sutaburosu } } } diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index 080cc9425..1825ab198 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -88,8 +88,8 @@ uint8_t cos8_t(uint8_t theta) { float sin_approx(float theta) { theta = modd(theta, TWO_PI); // modulo: bring to -2pi to 2pi range - if(theta < 0) theta += M_TWOPI; // 0-2pi range - uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / M_TWOPI)); + if(theta < 0) theta += TWO_PI; // 0-2pi range + uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / TWO_PI)); int32_t result = sin16_t(scaled_theta); float sin = float(result) / 0x7FFF; return sin; @@ -110,28 +110,23 @@ float tan_approx(float x) { #define ATAN2_CONST_A 0.1963f #define ATAN2_CONST_B 0.9817f -// fast atan2() approximation source: public domain +// atan2_t approximation, with the idea from https://gist.github.com/volkansalma/2972237?permalink_comment_id=3872525#gistcomment-3872525 float atan2_t(float y, float x) { - if (x == 0.0f) return (y > 0.0f) ? M_PI_2 : (y < 0.0f) ? -M_PI_2 : 0.0f; - - float abs_y = (y < 0.0f) ? -y : y + 1e-10f; // make sure y is not zero to prevent division by 0 - float z = abs_y / x; - float atan_approx; - - if (z < 1.0f) { - atan_approx = z / (1.0f + ATAN2_CONST_A * z * z); - if (x < 0.0f) { - return (y >= 0.0f) ? atan_approx + PI : atan_approx - PI; - } + float abs_y = fabs(y); + float abs_x = fabs(x); + float r = (abs_x - abs_y) / (abs_y + abs_x + 1e-10f); // avoid division by zero by adding a small nubmer + float angle; + if(x < 0) { + r = -r; + angle = M_PI/2.0f + M_PI/4.f; } - else { - z = x / abs_y; - atan_approx = M_PI_2 - z / (1.0f + ATAN2_CONST_A * z * z); - if (y < 0.0f) { - return -atan_approx; - } - } - return atan_approx; + else + angle = M_PI/2.0f - M_PI/4.f; + + float add = (ATAN2_CONST_A * (r * r) - ATAN2_CONST_B) * r; + angle += add; + angle = y < 0 ? -angle : angle; + return angle; } //https://stackoverflow.com/questions/3380628