shithub: slug

Download patch

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