ref: 307ba8a8d9d7c0088462bc4e947639b4593ce597
parent: fdf4c12f78354d0886bc1ff29f7605bb671f4a91
author: phil9 <telephil9@gmail.com>
date: Tue Dec 6 03:06:56 EST 2022
implement more math functions and expose them in the lua math library added functions are: - dist() - mag() - constrain() - map() - norm() - lerp()
--- a/a.h
+++ b/a.h
@@ -30,6 +30,9 @@
int registerpixels(lua_State*);
void lpushpixels(lua_State*);
+double dist(int, int, int, int);
+double map(double, double, double, double, double);
+double lerp(double, double, double);
double randomgaussian(double, double);
extern int drawing;
--- a/api.c
+++ b/api.c
@@ -477,7 +477,6 @@
if(!nostroke)
poly(canvas, p, 5, strokecap, strokecap, strokeweight, stroke, ZP);
return 0;
-
}
int
@@ -635,6 +634,114 @@
}
int
+cconstrain(lua_State *L)
+{
+ double fa, fm, fM;
+ int ia, im, iM;
+
+ if(lua_isinteger(L, 1)){
+ ia = luaL_checkinteger(L, 1);
+ im = luaL_checkinteger(L, 2);
+ iM = luaL_checkinteger(L, 3);
+ if(ia < im)
+ ia = im;
+ else if(ia > iM)
+ ia = iM;
+ lua_pushinteger(L, ia);
+ }else{
+ fa = luaL_checknumber(L, 1);
+ fm = luaL_checknumber(L, 2);
+ fM = luaL_checknumber(L, 3);
+ if(fa < fm)
+ fa = fm;
+ else if(fa > fM)
+ fa = fM;
+ lua_pushnumber(L, fa);
+ }
+ return 1;
+}
+
+int
+cmap(lua_State *L)
+{
+ double v, s1, e1, s2, e2;
+ int n;
+
+ n = lua_gettop(L);
+ if(n != 5)
+ return luaL_error(L, "invalid argument count (expected 5 but got %d)", n);
+ v = luaL_checknumber(L, 1);
+ s1 = luaL_checknumber(L, 2);
+ e1 = luaL_checknumber(L, 3);
+ s2 = luaL_checknumber(L, 4);
+ e2 = luaL_checknumber(L, 5);
+ lua_pushnumber(L, map(v, s1, e1, s2, e2));
+ return 1;
+}
+
+int
+cnorm(lua_State *L)
+{
+ double v, s1, e1;
+ int n;
+
+ n = lua_gettop(L);
+ if(n != 3)
+ return luaL_error(L, "invalid argument count (expected 3 but got %d)", n);
+ v = luaL_checknumber(L, 1);
+ s1 = luaL_checknumber(L, 2);
+ e1 = luaL_checknumber(L, 3);
+ lua_pushnumber(L, map(v, s1, e1, 0.0, 1.0));
+ return 1;
+}
+
+int
+cdist(lua_State *L)
+{
+ int n, x1, y1, x2, y2;
+
+ n = lua_gettop(L);
+ if(n != 4)
+ return luaL_error(L, "invalid argument count (expected 4 but got %d)", n);
+ x1 = luaL_checkinteger(L, 1);
+ y1 = luaL_checkinteger(L, 2);
+ x2 = luaL_checkinteger(L, 3);
+ y2 = luaL_checkinteger(L, 4);
+ lua_pushnumber(L, dist(x1, y1, x2, y2));
+ return 1;
+}
+
+int
+cmag(lua_State *L)
+{
+ int n, x, y;
+
+ n = lua_gettop(L);
+ if(n != 2)
+ return luaL_error(L, "invalid argument count (expected 2 but got %d)", n);
+ x = luaL_checkinteger(L, 1);
+ y = luaL_checkinteger(L, 2);
+ lua_pushnumber(L, dist(0, 0, x, y));
+ return 1;
+}
+
+int
+clerp(lua_State *L)
+{
+ double r, a, b;
+ int n;
+
+ n = lua_gettop(L);
+ if(n != 3)
+ return luaL_error(L, "invalid argument count (expected 3 but got %d)", n);
+ a = luaL_checknumber(L, 1);
+ b = luaL_checknumber(L, 2);
+ r = luaL_checknumber(L, 3);
+ lua_pushnumber(L, lerp(a, b, r));
+ return 1;
+}
+
+int
crandomgaussian(lua_State *L)
{
double m, s, g;
@@ -667,6 +774,14 @@
}
void
+registermathfunc(lua_State *L, const char *name, lua_CFunction f)
+{
+ lua_getglobal(L, "math");
+ lua_pushcfunction(L, f);
+ lua_setfield(L, 1, name);
+}
+
+void
registerapi(lua_State *L)
{
lset(L, "RGB", Crgb);
@@ -709,6 +824,11 @@
registerfunc(L, "lerpColor", clerpcolor);
registerfunc(L, "loadPixels", cloadpixels);
registerfunc(L, "updatePixels", cupdatepixels);
- registerfunc(L, "randomGaussian", crandomgaussian);
+ registermathfunc(L, "dist", cdist);
+ registermathfunc(L, "mag", cmag);
+ registermathfunc(L, "constrain", cconstrain);
+ registermathfunc(L, "map", cmap);
+ registermathfunc(L, "norm", cnorm);
+ registermathfunc(L, "lerp", clerp);
+ registermathfunc(L, "randomGaussian", crandomgaussian);
}
-
--- a/math.c
+++ b/math.c
@@ -1,6 +1,33 @@
#include "a.h"
double
+lerp(double a, double b, double r)
+{
+ if(r < 0.0)
+ r = 0.0;
+ else if(r > 1.0)
+ r = 1.0;
+ return r * (b - a) + a;
+}
+
+double
+dist(int x1, int y1, int x2, int y2)
+{
+ int dx = x1 - x2;
+ int dy = y1 - y2;
+ return sqrt(dx*dx + dy*dy);
+}
+
+double
+map(double v, double s1, double e1, double s2, double e2)
+{
+ double r;
+
+ r = (v - s1) / (e1 - s1) * (e2 - s2) + s2;
+ return r;
+}
+
+double
randomgaussian(double mean, double sd)
{
static int prev = 0;
--- a/samples/gaussian.lua
+++ b/samples/gaussian.lua
@@ -4,7 +4,7 @@
size(400, 400)
background(200)
for y = 0, 399 do
- x = math.floor(randomGaussian() * 60)
+ x = math.floor(math.randomGaussian() * 60)
line(200, y, 200 + x, y)
end
end
--- a/slug.man
+++ b/slug.man
@@ -310,14 +310,70 @@
\f5mouseY
Global variable containing the vertical coordinate of the mouse.
.SS Math
+Following functions extend the standard lua
+.I math
+library.
.TP
-\f5randomGaussian()
+\f5math.dist(\f2x1\fP, \f2y1\fP, \f2x2\fP, \f2y2\fP)
+Computes the distance between points
+.I (x1,y1)
+and
+.I (x2, y2)
+\&.
+.TP
+\f5math.map(\f2x\fP, \f2y\fP)
+Computes the magnitude of the vector
+.I (x,y)
+\&. This is equivalent to the distance of point
+.I (x,y)
+to the origin
+.I (0,0)
+.TP
+\f5math.constrain(\f2v\fP, \f2min\fP, \f2max\fP)
+Constrains the value
+.I v
+to the range
+.I [min;max]
+\&.
+.TP
+\f5math.map(\f2v\fP, \f2s1\fP, \f2e1\fP, \f2s2\fP, \f2e2\fP)
+Maps the number
+.I v
+from the range
+.I [s1;e1]
+to the range
+.I [s2;e2]
+\&. Note that the result is not constrained to the target range which, if needed, can be achieved by a call to
+.IR constrain()
+\&.
+.TP
+\f5math.norm(\f2v\fP, \f2s\fP, \f2e\fP)
+Normalizes the value
+.I v
+from range
+.I [s;e]
+to a value in the range
+.I [0;1]
+\&. This is equivalent to:
+.I math.map(v, s, e, 0.0, 1.0)
+\&.
+.TP
+\f5math.lerp(\f2a\fP, \f2b\fP, \f2r\fP)
+Computes a linear interpolation between numbers
+.I a
+and
+.I b
+using an interpolation value of
+.I r
+\&.
+.TP
+\f5math.randomGaussian()
.PD 0
.TP
-\f5randomGaussian(\f2mean\fP)
+\f5math.randomGaussian(\f2mean\fP)
.PD 0
.TP
-\f5randomGaussian(\f2mean\fP, \f2stddev\fP)
+\f5math.randomGaussian(\f2mean\fP, \f2stddev\fP)
Returns a random number fitting a Gaussian (or normal) distribution. The arguments are the mean and the standard deviation which defaults to 0.0 and 1.0 respectively.
.SH AUTHOR