Add Vec2/3/4:angle(other)

Functions to calculate the angle between two vectors. Angle is always
positive. Implementations give the same result as this Lua code:

```lua
local function lua_angle(v1, v2)
  return math.acos(v1:dot(v2) / (v1:length() * v2:length()))
end
```

If either vector is zero-length, the pi/2 value is returned.
This commit is contained in:
Josip Miskovic 2022-02-18 20:05:02 +01:00 committed by Bjorn
parent 517b104c1e
commit ef41e06fc9
2 changed files with 82 additions and 6 deletions

View File

@ -253,7 +253,7 @@ static int l_lovrVec2Distance(lua_State* L) {
uvec[1] = luax_checkfloat(L, 3);
u = uvec;
} else {
u = luax_checkvector(L, 2, V_VEC2, NULL);
u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
}
float dx = v[0] - u[0];
float dy = v[1] - u[1];
@ -270,7 +270,7 @@ static int l_lovrVec2Dot(lua_State* L) {
uvec[1] = luax_checkfloat(L, 3);
u = uvec;
} else {
u = luax_checkvector(L, 2, V_VEC2, NULL);
u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
}
lua_pushnumber(L, v[0] * u[0] + v[1] * u[1]);
return 1;
@ -287,7 +287,7 @@ static int l_lovrVec2Lerp(lua_State* L) {
u = uvec;
t = luax_checkfloat(L, 4);
} else {
u = luax_checkvector(L, 2, V_VEC2, NULL);
u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
t = luax_checkfloat(L, 3);
}
v[0] = v[0] + (u[0] - v[0]) * t;
@ -296,6 +296,29 @@ static int l_lovrVec2Lerp(lua_State* L) {
return 1;
}
static int l_lovrVec2Angle(lua_State* L) {
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
float* u;
float uvec[2];
float dot, length_v, length_u;
if (lua_type(L, 2) == LUA_TNUMBER) {
uvec[0] = lua_tonumber(L, 2);
uvec[1] = luax_checkfloat(L, 3);
u = uvec;
} else {
u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
}
length_v = sqrtf(v[0] * v[0] + v[1] * v[1]);
length_u = sqrtf(u[0] * u[0] + u[1] * u[1]);
if ((length_v == 0.f) || (length_u == 0.f)) {
lua_pushnumber(L, (float) M_PI / 2);
} else {
dot = v[0] * u[0] + v[1] * u[1];
lua_pushnumber(L, acosf(dot / (length_v * length_u)));
}
return 1;
}
static int l_lovrVec2__add(lua_State* L) {
float* out = luax_newtempvector(L, V_VEC2);
if (lua_type(L, 1) == LUA_TNUMBER) {
@ -497,6 +520,7 @@ const luaL_Reg lovrVec2[] = {
{ "distance", l_lovrVec2Distance },
{ "dot", l_lovrVec2Dot },
{ "lerp", l_lovrVec2Lerp },
{ "angle", l_lovrVec2Angle },
{ "__add", l_lovrVec2__add },
{ "__sub", l_lovrVec2__sub },
{ "__mul", l_lovrVec2__mul },
@ -687,6 +711,22 @@ static int l_lovrVec3Lerp(lua_State* L) {
return 1;
}
static int l_lovrVec3Angle(lua_State* L) {
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
vec3 u;
float uvec[4];
if (lua_type(L, 2) == LUA_TNUMBER) {
uvec[0] = lua_tonumber(L, 2);
uvec[1] = luax_checkfloat(L, 3);
uvec[2] = luax_checkfloat(L, 4);
u = uvec;
} else {
u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
}
lua_pushnumber(L, vec3_angle(v, u));
return 1;
}
static int l_lovrVec3__add(lua_State* L) {
vec3 out = luax_newtempvector(L, V_VEC3);
if (lua_type(L, 1) == LUA_TNUMBER) {
@ -891,6 +931,7 @@ const luaL_Reg lovrVec3[] = {
{ "dot", l_lovrVec3Dot },
{ "cross", l_lovrVec3Cross },
{ "lerp", l_lovrVec3Lerp },
{ "angle", l_lovrVec3Angle },
{ "__add", l_lovrVec3__add },
{ "__sub", l_lovrVec3__sub },
{ "__mul", l_lovrVec3__mul },
@ -1039,7 +1080,7 @@ static int l_lovrVec4Distance(lua_State* L) {
uvec[3] = luax_checkfloat(L, 5);
u = uvec;
} else {
u = luax_checkvector(L, 2, V_VEC4, NULL);
u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
}
float dx = v[0] - u[0];
float dy = v[1] - u[1];
@ -1060,7 +1101,7 @@ static int l_lovrVec4Dot(lua_State* L) {
uvec[3] = luax_checkfloat(L, 5);
u = uvec;
} else {
u = luax_checkvector(L, 2, V_VEC4, NULL);
u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
}
lua_pushnumber(L, v[0] * u[0] + v[1] * u[1] + v[2] * u[2] + v[3] * u[3]);
return 1;
@ -1079,7 +1120,7 @@ static int l_lovrVec4Lerp(lua_State* L) {
u = uvec;
t = luax_checkfloat(L, 6);
} else {
u = luax_checkvector(L, 2, V_VEC4, NULL);
u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
t = luax_checkfloat(L, 3);
}
v[0] = v[0] + (u[0] - v[0]) * t;
@ -1090,6 +1131,31 @@ static int l_lovrVec4Lerp(lua_State* L) {
return 1;
}
static int l_lovrVec4Angle(lua_State* L) {
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
float* u;
float uvec[4];
float dot, length_v, length_u;
if (lua_type(L, 2) == LUA_TNUMBER) {
uvec[0] = lua_tonumber(L, 2);
uvec[1] = luax_checkfloat(L, 3);
uvec[2] = luax_checkfloat(L, 4);
uvec[3] = luax_checkfloat(L, 5);
u = uvec;
} else {
u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
}
length_v = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
length_u = sqrtf(u[0] * u[0] + u[1] * u[1] + u[2] * u[2] + u[3] * u[3]);
if ((length_v == 0.f) || (length_u == 0.f)) {
lua_pushnumber(L, (float) M_PI / 2);
} else {
dot = v[0] * u[0] + v[1] * u[1] + v[2] * u[2] + v[3] * u[3];
lua_pushnumber(L, acosf(dot / (length_v * length_u)));
}
return 1;
}
static int l_lovrVec4__add(lua_State* L) {
float* out = luax_newtempvector(L, V_VEC4);
if (lua_type(L, 1) == LUA_TNUMBER) {
@ -1329,6 +1395,7 @@ const luaL_Reg lovrVec4[] = {
{ "distance", l_lovrVec4Distance },
{ "dot", l_lovrVec4Dot },
{ "lerp", l_lovrVec4Lerp },
{ "angle", l_lovrVec4Angle },
{ "__add", l_lovrVec4__add },
{ "__sub", l_lovrVec4__sub },
{ "__mul", l_lovrVec4__mul },

View File

@ -122,6 +122,15 @@ MAF vec3 vec3_max(vec3 v, const vec3 u) {
return v;
}
MAF float vec3_angle(const vec3 v, const vec3 u) {
float denom = vec3_length(v) * vec3_length(u);
if (denom == 0.f) {
return (float) M_PI / 2;
} else {
return acosf(vec3_dot(v, u) / denom);
}
}
// quat
MAF quat quat_set(quat q, float x, float y, float z, float w) {