Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added integer based sin()/cos() functions, changed all trig functions to wled_math #4181

Merged
merged 8 commits into from
Nov 27, 2024
6 changes: 4 additions & 2 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
Expand Down
39 changes: 17 additions & 22 deletions wled00/wled_math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? Why not change M_PI below?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good question. I think this was auto-complete suggestion from co-pilot.
I will make it consistant to M_PI variants.
Also: the conversion of the angle using float is really not needed, I added that to fix a bug. but the actual fix is: cast a negative float to a int and NEVER to a unsigned type, as that behaviour is undefined and depends on the CPU/Compiler, hence the issues on the C3 which does (uint)(float) = 0

uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / TWO_PI));
int32_t result = sin16_t(scaled_theta);
float sin = float(result) / 0x7FFF;
return sin;
Expand All @@ -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
Expand Down