merge math functions

This commit is contained in:
2025-01-28 22:41:00 -06:00
parent 9982dadd58
commit b561217073
7 changed files with 457 additions and 306 deletions

View File

@@ -1,5 +1,5 @@
var render = use('render')
var vector = use('vector')
var math = use('math')
var draw = {}
@@ -22,9 +22,9 @@ draw.cross = function render_cross(pos, size, color = Color.red, thickness = 1,
};
draw.arrow = function render_arrow(start, end, color = Color.red, wingspan = 4, wingangle = 10, pipe = sprite_pipeline) {
var dir = vector.norm(end.sub(start))
var wing1 = [vector.rotate(dir, wingangle).scale(wingspan).add(end), end];
var wing2 = [vector.rotate(dir, -wingangle).scale(wingspan).add(end), end];
var dir = math.norm(end.sub(start))
var wing1 = [math.rotate(dir, wingangle).scale(wingspan).add(end), end];
var wing2 = [math.rotate(dir, -wingangle).scale(wingspan).add(end), end];
render.line([start, end], color);
render.line(wing1, color);
render.line(wing2, color);

View File

@@ -1,5 +1,5 @@
var geometry = this
var vector = use('vector')
var math = use('math')
var shape = {};
shape.box = {};
@@ -56,7 +56,7 @@ shape.arc = function (radius, angle, n, start = 0) {
angle = Math.deg2rad(angle);
var arclen = angle / n;
for (var i = 0; i < n; i++) points.push(vector.rotate([radius, 0], start + arclen * i));
for (var i = 0; i < n; i++) points.push(math.rotate([radius, 0], start + arclen * i));
return points;
};
@@ -73,4 +73,33 @@ shape.corners2points = function (ll, ur) {
for (var i in geometry)
shape[i] = geometry[i]
shape.sortpointsccw = function (points) {
var cm = points2cm(points);
var cmpoints = points.map(function (x) {
return x.sub(cm);
});
var ccw = cmpoints.sort(function (a, b) {
var aatan = Math.atan2(a.y, a.x);
var batan = Math.atan2(b.y, b.x);
return aatan - batan;
});
return ccw.map(function (x) {
return x.add(cm);
});
};
shape.points2cm = function(points)
{
var x = 0;
var y = 0;
var n = points.length;
points.forEach(function (p) {
x = x + p[0];
y = y + p[1];
});
return [x / n, y / n];
}
return shape

11
scripts/math.js Normal file
View File

@@ -0,0 +1,11 @@
var math = this
math.TAU = Math.PI * 2;
math.deg2rad = function (deg) { return deg * 0.0174533; };
math.rad2deg = function (rad) { return rad / 0.0174533; };
math.turn2rad = function (x) { return x * Math.TAU; };
math.rad2turn = function (x) { return x / Math.TAU; };
math.turn2deg = function (x) { return x * 360; };
math.deg2turn = function (x) { return x / 360; };
return math

View File

@@ -1,76 +0,0 @@
var pmath = {}
var vector = use('vector')
pmath.rand_int = function (max = 9007199254740991) {
return Math.floor(Math.random() * max);
};
pmath.snap = function (val, grid) {
if (!grid || grid === 1) return Math.round(val);
var rem = val % grid;
var d = val - rem;
var i = Math.round(rem / grid) * grid;
return d + i;
};
pmath.TAU = Math.PI * 2;
pmath.deg2rad = function (deg) {
return deg * 0.0174533;
};
pmath.rad2deg = function (rad) {
return rad / 0.0174533;
};
pmath.turn2rad = function (x) {
return x * Math.TAU;
};
pmath.rad2turn = function (x) {
return x / Math.TAU;
};
pmath.turn2deg = function (x) {
return x * 360;
};
pmath.deg2turn = function (x) {
return x / 360;
};
pmath.randomint = function (max) {
return Math.clamp(Math.floor(Math.random() * max), 0, max - 1);
};
pmath.variate = vector.variate;
pmath.sortpointsccw = function (points) {
var cm = points2cm(points);
var cmpoints = points.map(function (x) {
return x.sub(cm);
});
var ccw = cmpoints.sort(function (a, b) {
var aatan = Math.atan2(a.y, a.x);
var batan = Math.atan2(b.y, b.x);
return aatan - batan;
});
return ccw.map(function (x) {
return x.add(cm);
});
};
pmath.sign = function (n) {
return n >= 0 ? 1 : -1;
};
pmath.points2cm = function(points)
{
var x = 0;
var y = 0;
var n = points.length;
points.forEach(function (p) {
x = x + p[0];
y = y + p[1];
});
return [x / n, y / n];
}
return pmath

View File

@@ -1,6 +1,6 @@
var render = {}
var config = use('config.js')
var vector = use('vector')
var math = use('math')
var io = use('io')
var os = use('os')
var util = use('util')
@@ -848,9 +848,9 @@ render.cross = function render_cross(pos, size, color = Color.red, thickness = 1
};
render.arrow = function render_arrow(start, end, color = Color.red, wingspan = 4, wingangle = 10, pipe = sprite_pipeline) {
var dir = vector.norm(end.sub(start))
var wing1 = [vector.rotate(dir, wingangle).scale(wingspan).add(end), end];
var wing2 = [vector.rotate(dir, -wingangle).scale(wingspan).add(end), end];
var dir = math.norm(end.sub(start))
var wing1 = [math.rotate(dir, wingangle).scale(wingspan).add(end), end];
var wing2 = [math.rotate(dir, -wingangle).scale(wingspan).add(end), end];
render.line([start, end], color);
render.line(wing1, color);
render.line(wing2, color);
@@ -978,7 +978,7 @@ render.mask = function mask(image, pos, scale, rotation = 0, ref = 1)
var tex = image.texture;
if (scale) scale = sacle.div([tex.width,tex.height]);
else scale = vector.v3one;
else scale = [1,1,1]
var pipe = stencil_writer(ref);
render.use_shader('sprite.cg', pipe);

View File

@@ -1,41 +0,0 @@
/* VECTORS */
var vector = this
vector.random = function () {
var vec = [Math.random() - 0.5, Math.random() - 0.5];
return vector.norm(vec);
};
vector.direction = function (from, to) {
return vector.norm(to.sub(from));
};
vector.equal = function (v1, v2, tol) {
if (!tol) return v1.equal(v2);
var eql = true;
var c = v1.sub(v2);
c.forEach(function (x) {
if (!eql) return;
if (Math.abs(x) > tol) eql = false;
});
return eql;
};
vector.reflect = function (vec, plane) {
var p = vector.norm(plane);
return vec.sub(p.scale(2 * vector.dot(vec, p)));
};
vector.reflect_point = function (vec, point) {
return point.add(vec.sub(point).scale(-1));
};
vector.v2one = [1,1];
vector.v3one = [1,1,1];
vector.v2zero = [0,0];
vector.v3zero = [0,0,0];
return vector

View File

@@ -53,6 +53,69 @@ typedef struct rtree rtree;
//#include <cblas.h>
#endif
#define STATE_VECTOR_LENGTH 624
#define STATE_VECTOR_M 397 /* changes to STATE_VECTOR_LENGTH also require changes to this */
typedef struct tagMTRand {
uint32_t mt[STATE_VECTOR_LENGTH];
int32_t index;
} MTRand;
static MTRand mrand;
#define UPPER_MASK 0x80000000
#define LOWER_MASK 0x7fffffff
#define TEMPERING_MASK_B 0x9d2c5680
#define TEMPERING_MASK_C 0xefc60000
inline static void m_seedRand(MTRand* rand, uint32_t seed) {
/* set initial seeds to mt[STATE_VECTOR_LENGTH] using the generator
* from Line 25 of Table 1 in: Donald Knuth, "The Art of Computer
* Programming," Vol. 2 (2nd Ed.) pp.102.
*/
rand->mt[0] = seed & 0xffffffff;
for(rand->index=1; rand->index<STATE_VECTOR_LENGTH; rand->index++) {
rand->mt[rand->index] = (6069 * rand->mt[rand->index-1]) & 0xffffffff;
}
}
uint32_t genRandLong(MTRand* rand) {
uint32_t y;
static uint32_t mag[2] = {0x0, 0x9908b0df}; /* mag[x] = x * 0x9908b0df for x = 0,1 */
if(rand->index >= STATE_VECTOR_LENGTH || rand->index < 0) {
/* generate STATE_VECTOR_LENGTH words at a time */
int32_t kk;
if(rand->index >= STATE_VECTOR_LENGTH+1 || rand->index < 0) {
m_seedRand(rand, 4357);
}
for(kk=0; kk<STATE_VECTOR_LENGTH-STATE_VECTOR_M; kk++) {
y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk+1] & LOWER_MASK);
rand->mt[kk] = rand->mt[kk+STATE_VECTOR_M] ^ (y >> 1) ^ mag[y & 0x1];
}
for(; kk<STATE_VECTOR_LENGTH-1; kk++) {
y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk+1] & LOWER_MASK);
rand->mt[kk] = rand->mt[kk+(STATE_VECTOR_M-STATE_VECTOR_LENGTH)] ^ (y >> 1) ^ mag[y & 0x1];
}
y = (rand->mt[STATE_VECTOR_LENGTH-1] & UPPER_MASK) | (rand->mt[0] & LOWER_MASK);
rand->mt[STATE_VECTOR_LENGTH-1] = rand->mt[STATE_VECTOR_M-1] ^ (y >> 1) ^ mag[y & 0x1];
rand->index = 0;
}
y = rand->mt[rand->index++];
y ^= (y >> 11);
y ^= (y << 7) & TEMPERING_MASK_B;
y ^= (y << 15) & TEMPERING_MASK_C;
y ^= (y >> 18);
return y;
}
double genRand(MTRand* rand) {
return((double)genRandLong(rand) / (uint32_t)0xffffffff);
}
static JSAtom width_atom;
static JSAtom height_atom;
static JSAtom l_atom;
@@ -1754,40 +1817,182 @@ shader_globals camera_globals(JSContext *js, JSValue camera)
return data;
}
static JSValue floats2array(JSContext *js, float *vals, size_t len) {
JSValue arr = JS_NewArray(js);
for (size_t i = 0; i < len; i++) {
JS_SetPropertyUint32(js, arr, i, number2js(js, vals[i]));
}
return arr;
}
JSValue js_vector_dot(JSContext *js, JSValue self, int argc, JSValue *argv) {
JSValue js_math_dot(JSContext *js, JSValue self, int argc, JSValue *argv) {
size_t alen, blen;
float *a = js2floats(js,argv[0], &alen);
float *b = js2floats(js,argv[1], &blen);
// JSValue ret = number2js(js, cblas_sdot(alen, a, 1, b,1));
float dot = 0;
size_t len = alen < blen? alen : blen;
for (size_t i = 0; i < len; i++)
dot += a[i] * b[i];
free(a);
free(b);
return JS_UNDEFINED;
return number2js(js,dot);
};
JSC_CCALL(vector_project, ret = vec22js(js,HMM_ProjV2(js2vec2(js,argv[0]), js2vec2(js,argv[1]))))
JSValue js_math_project(JSContext *js, JSValue self, int argc, JSValue *argv) {
size_t alen, blen;
float *a = js2floats(js, argv[0], &alen);
float *b = js2floats(js, argv[1], &blen);
JSC_CCALL(vector_midpoint,
HMM_Vec2 a = js2vec2(js,argv[0]);
HMM_Vec2 b = js2vec2(js,argv[1]);
// HMM_Vec2 c = HMM_AddV2(a,b);
// c = HMM_Div2VF(c, 2);
return vec22js(js,(HMM_Vec2){(a.x+b.x)/2, (a.y+b.y)/2});
)
if (!a || !b) {
free(a);
free(b);
return JS_UNDEFINED;
}
JSC_CCALL(vector_distance,
HMM_Vec2 a = js2vec2(js,argv[0]);
HMM_Vec2 b = js2vec2(js,argv[1]);
ret = number2js(js,HMM_DistV2(a,b));
)
// We'll work up to the smaller length
size_t len = (alen < blen) ? alen : blen;
if (len == 0) {
free(a);
free(b);
return JS_UNDEFINED;
}
JSC_CCALL(vector_angle,
HMM_Vec2 a = js2vec2(js,argv[0]);
ret= angle2js(js,atan2(a.y,a.x));
)
// Compute dot products: a·b and b·b
float ab = 0, bb = 0;
for (size_t i = 0; i < len; i++) {
ab += a[i] * b[i];
bb += b[i] * b[i];
}
// Build the result array
float *proj = (float*)malloc(sizeof(float) * len);
if (!proj) {
free(a);
free(b);
return JS_EXCEPTION; // or some error
}
float scale = (bb != 0.0f) ? (ab / bb) : 0.0f;
for (size_t i = 0; i < len; i++)
proj[i] = scale * b[i];
JSValue ret = floats2array(js, proj, len);
free(a);
free(b);
free(proj);
return ret;
}
// ---------------------------
// math_midpoint(a, b)
// midpoint = (a + b) / 2
// returns new vector (array)
// dimension = min(alen, blen)
// ---------------------------
JSValue js_math_midpoint(JSContext *js, JSValue self, int argc, JSValue *argv) {
size_t alen, blen;
float *a = js2floats(js, argv[0], &alen);
float *b = js2floats(js, argv[1], &blen);
if (!a || !b) {
free(a);
free(b);
return JS_UNDEFINED;
}
size_t len = (alen < blen) ? alen : blen;
if (len == 0) {
free(a);
free(b);
return JS_UNDEFINED;
}
float *m = (float*)malloc(sizeof(float) * len);
if (!m) {
free(a);
free(b);
return JS_EXCEPTION;
}
for (size_t i = 0; i < len; i++)
m[i] = (a[i] + b[i]) * 0.5f;
JSValue ret = floats2array(js, m, len);
free(a);
free(b);
free(m);
return ret;
}
// ---------------------------
// math_distance(a, b)
// Euclidean distance = sqrt( Σ (b[i]-a[i])^2 )
// dimension = min(alen, blen)
// returns scalar (number)
// ---------------------------
JSValue js_math_distance(JSContext *js, JSValue self, int argc, JSValue *argv) {
size_t alen, blen;
float *a = js2floats(js, argv[0], &alen);
float *b = js2floats(js, argv[1], &blen);
if (!a || !b) {
free(a);
free(b);
return JS_UNDEFINED;
}
size_t len = (alen < blen) ? alen : blen;
if (len == 0) {
free(a);
free(b);
return JS_UNDEFINED;
}
float distSq = 0.0f;
for (size_t i = 0; i < len; i++) {
float diff = b[i] - a[i];
distSq += diff * diff;
}
float dist = sqrtf(distSq);
free(a);
free(b);
return number2js(js, dist);
}
// ---------------------------
// math_angle(a)
// In 2D: angle from x-axis via atan2(y, x).
// For higher dimensions, there's no single "angle" in the usual sense.
// We'll only return angle if len >= 2, using first two coords.
// Or strictly require len==2, your call.
// ---------------------------
JSValue js_math_angle(JSContext *js, JSValue self, int argc, JSValue *argv) {
size_t alen;
float *a = js2floats(js, argv[0], &alen);
if (!a || alen < 2) {
free(a);
return JS_UNDEFINED;
}
// If you want to be strict, require alen == 2
// if (alen != 2) {
// free(a);
// return JS_UNDEFINED;
// }
float angle = atan2f(a[1], a[0]);
free(a);
return number2js(js, angle);
}
/* Given a series of points p, computes a new series with them expanded on either side by d */
/*
HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n)
{
if (d == 0) {
@@ -1830,7 +2035,7 @@ HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n)
return ret;
}
JSC_CCALL(vector_inflate,
JSC_CCALL(math_inflate,
HMM_Vec2 *p = js2cpvec2arr(js,argv[0]);
double d = js2number(js,argv[1]);
HMM_Vec2 *infl = inflatepoints(p,d, js_arrlen(js,argv[0]));
@@ -1838,8 +2043,8 @@ JSC_CCALL(vector_inflate,
arrfree(infl);
arrfree(p);
)
JSC_CCALL(vector_rotate,
*/
JSC_CCALL(math_rotate,
HMM_Vec2 vec = js2vec2(js,argv[0]);
double angle = js2angle(js, argv[1]);
HMM_Vec2 pivot = JS_IsUndefined(argv[2]) ? v2zero : js2vec2(js,argv[2]);
@@ -1865,28 +2070,8 @@ JSC_CCALL(vector_rotate,
// Convert back to JS and return
return vec22js(js, vec);
)
/*
JSC_CCALL(vector_rotate,
HMM_Vec2 vec = js2vec2(js,argv[0]);
double angle = js2angle(js,argv[1]);
HMM_Vec2 pivot = JS_IsUndefined(argv[2]) ? v2zero : js2vec2(js,argv[2]);
vec = HMM_SubV2(vec,pivot);
float r = HMM_LenV2(vec);
angle += atan2(vec.y,vec.x);
vec.x = r*cos(angle);
vec.y = r*sin(angle);
return vec22js(js,HMM_AddV2(vec,pivot));
)
*/
JSC_CCALL(vector_add,
HMM_Vec4 a = js2vec4(js,argv[0]);
HMM_Vec4 b = js2vec4(js,argv[1]);
HMM_Vec4 c = HMM_AddV4(a,b);
ret = vec42js(js,c);
)
JSC_CCALL(vector_norm,
JSC_CCALL(math_norm,
int len = js_arrlen(js,argv[0]);
switch(len) {
@@ -1904,17 +2089,17 @@ JSC_CCALL(vector_norm,
ret = newarr;
)
JSC_CCALL(vector_angle_between,
JSC_CCALL(math_angle_between,
int len = js_arrlen(js,argv[0]);
switch(len) {
case 2: return angle2js(js,HMM_AngleV2(js2vec2(js,argv[0]), js2vec2(js,argv[1])));
case 3: return angle2js(js,HMM_AngleV3(js2vec3(js,argv[0]), js2vec3(js,argv[1])));
case 4: return angle2js(js,HMM_AngleV4(js2vec4(js,argv[0]), js2vec4(js,argv[1])));
}
ret = angle2js(js,0);
return JS_ThrowReferenceError(js, "Input array must have a length between 2 and 4.");
)
JSC_CCALL(vector_lerp,
JSC_CCALL(math_lerp,
double s = js2number(js,argv[0]);
double f = js2number(js,argv[1]);
double t = js2number(js,argv[2]);
@@ -1928,24 +2113,22 @@ int gcd(int a, int b) {
return gcd(b, a % b);
}
JSC_CCALL(vector_gcd,
ret = number2js(js,gcd(js2number(js,argv[0]), js2number(js,argv[1])));
)
JSC_CCALL(math_gcd, ret = number2js(js,gcd(js2number(js,argv[0]), js2number(js,argv[1]))); )
JSC_CCALL(vector_lcm,
JSC_CCALL(math_lcm,
double a = js2number(js,argv[0]);
double b = js2number(js,argv[1]);
ret = number2js(js,(a*b)/gcd(a,b));
)
JSC_CCALL(vector_clamp,
JSC_CCALL(math_clamp,
double x = js2number(js,argv[0]);
double l = js2number(js,argv[1]);
double h = js2number(js,argv[2]);
return number2js(js,x > h ? h : x < l ? l : x);
)
JSC_CCALL(vector_angledist,
JSC_CCALL(math_angledist,
double a1 = js2number(js,argv[0]);
double a2 = js2number(js,argv[1]);
a1 = fmod(a1,1);
@@ -1962,29 +2145,21 @@ JSC_CCALL(vector_angledist,
return number2js(js,dist);
)
JSC_CCALL(vector_length,
return number2js(js,arr_vec_length(js,argv[0]));
)
JSC_CCALL(math_length, return number2js(js,arr_vec_length(js,argv[0])); )
double r2()
double rand_range(double min, double max)
{
return (double)rand() / (double)RAND_MAX ;
return genRand(&mrand) * (max-min)+min;
}
double rand_range(double min, double max) {
return r2() * (max-min) + min;
}
JSC_CCALL(vector_variate,
JSC_CCALL(math_jitter,
double n = js2number(js,argv[0]);
double pct = js2number(js,argv[1]);
return number2js(js,n + (rand_range(-pct,pct)*n));
)
JSC_CCALL(vector_random_range, return number2js(js,rand_range(js2number(js,argv[0]), js2number(js,argv[1]))))
JSC_CCALL(vector_mean,
JSC_CCALL(math_mean,
double len = js_arrlen(js,argv[0]);
double sum = 0;
for (int i = 0; i < len; i++)
@@ -1993,7 +2168,7 @@ JSC_CCALL(vector_mean,
return number2js(js,sum/len);
)
JSC_CCALL(vector_sum,
JSC_CCALL(math_sum,
double sum = 0.0;
int len = js_arrlen(js,argv[0]);
for (int i = 0; i < len; i++)
@@ -2002,15 +2177,7 @@ JSC_CCALL(vector_sum,
return number2js(js,sum);
)
JSC_CCALL(vector_fastsum,
float sum = 0.0;
// size_t len;
// float *a = get_typed_buffer(js, argv[0], &len);
// sum = cblas_sasum(len, a,1);
ret = number2js(js,sum);
)
JSC_CCALL(vector_sigma,
JSC_CCALL(math_sigma,
int len = js_arrlen(js,argv[0]);
double sum = 0;
for (int i = 0; i < len; i++)
@@ -2030,7 +2197,7 @@ JSC_CCALL(vector_sigma,
return number2js(js,sqrt(variance));
)
JSC_CCALL(vector_median,
JSC_CCALL(math_median,
int len = js_arrlen(js,argv[0]);
double arr[len];
double temp;
@@ -2052,16 +2219,7 @@ JSC_CCALL(vector_median,
return number2js(js,arr[len/2]);
)
int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
JSC_CCALL(vector_fib,
int n = js2number(js,argv[0]);
int fib = fibonacci(n);
)
JSC_CCALL(vector_from_to,
JSC_CCALL(math_from_to,
HMM_Vec2 from = js2vec2(js,argv[0]);
HMM_Vec2 to = js2vec2(js,argv[1]);
float space = js2number(js,argv[2]);
@@ -2084,46 +2242,165 @@ JSC_CCALL(vector_from_to,
JS_SetPropertyUint32(js, ret, steps+1, vec22js(js,to));
)
JSC_CCALL(vector_float32add,
size_t len;
float *vec_a = get_typed_buffer(js,self, &len);
// float *vec_b = get_typed_buffer(js,argv[0], &len);
// cblas_saxpy(len,1.0f,vec_b,1,vec_a,1);
JSValue tstack[3];
tstack[0] = JS_NewArrayBufferCopy(js,vec_a,sizeof(float)*4);
tstack[1] = JS_UNDEFINED;
tstack[2] = JS_UNDEFINED;
ret = JS_NewTypedArray(js, 3, tstack, JS_TYPED_ARRAY_FLOAT32);
JS_FreeValue(js,tstack[0]);
JSC_CCALL(math_rand, return JS_NewFloat64(js, genRand(&mrand)))
JSC_CCALL(math_randi, return JS_NewUint32(js, genRandLong(&mrand)))
JSC_CCALL(math_srand,
if (argc < 1)
m_seedRand(&mrand, time(NULL));
else
m_seedRand(&mrand, js2number(js,argv[0]));
)
static const JSCFunctionListEntry js_vector_funcs[] = {
MIST_FUNC_DEF(vector, dot,2),
MIST_FUNC_DEF(vector, project,2),
MIST_FUNC_DEF(vector, inflate, 2),
MIST_FUNC_DEF(vector, rotate, 3),
MIST_FUNC_DEF(vector, add, 2),
MIST_FUNC_DEF(vector, midpoint, 2),
MIST_FUNC_DEF(vector, distance, 2),
MIST_FUNC_DEF(vector, angle, 1),
MIST_FUNC_DEF(vector, norm, 1),
MIST_FUNC_DEF(vector, angle_between, 2),
MIST_FUNC_DEF(vector, lerp, 3),
MIST_FUNC_DEF(vector, gcd, 2),
MIST_FUNC_DEF(vector, lcm, 2),
MIST_FUNC_DEF(vector, clamp, 3),
MIST_FUNC_DEF(vector, angledist, 2),
MIST_FUNC_DEF(vector, variate, 2),
MIST_FUNC_DEF(vector, random_range, 2),
MIST_FUNC_DEF(vector, mean, 1),
MIST_FUNC_DEF(vector, sum, 1),
MIST_FUNC_DEF(vector, fastsum, 1),
MIST_FUNC_DEF(vector, sigma, 1),
MIST_FUNC_DEF(vector, median, 1),
MIST_FUNC_DEF(vector, length, 1),
MIST_FUNC_DEF(vector, fib, 1),
MIST_FUNC_DEF(vector, from_to, 5),
MIST_FUNC_DEF(vector, float32add, 2),
JSValue js_math_direction(JSContext *js, JSValue self, int argc, JSValue *argv) {
size_t alen, blen;
float *a = js2floats(js, argv[0], &alen);
float *b = js2floats(js, argv[1], &blen);
if (!a || !b) {
free(a);
free(b);
return JS_UNDEFINED;
}
size_t len = (alen < blen) ? alen : blen;
if (len == 0) {
free(a);
free(b);
return JS_UNDEFINED;
}
float *dir = (float*)malloc(sizeof(float) * len);
if (!dir) {
free(a);
free(b);
return JS_EXCEPTION; // or some error
}
// Compute (b - a)
for (size_t i = 0; i < len; i++)
dir[i] = b[i] - a[i];
// Compute magnitude of dir
float mag = 0.0f;
for (size_t i = 0; i < len; i++)
mag += dir[i] * dir[i];
mag = sqrtf(mag);
// Normalize if possible
if (mag > 0.0f) {
for (size_t i = 0; i < len; i++)
dir[i] /= mag;
} else {
// Optional: if a == b, direction is zero
// you might want to do something else here
// (like return all zeros).
}
JSValue ret = floats2array(js, dir, len);
free(a);
free(b);
free(dir);
return ret;
}
JSValue js_math_reflect(JSContext *js, JSValue self, int argc, JSValue *argv) {
size_t vlen, nlen;
float *vec = js2floats(js, argv[0], &vlen);
float *norm = js2floats(js, argv[1], &nlen);
if (!vec || !norm) {
free(vec);
free(norm);
return JS_UNDEFINED;
}
size_t len = (vlen < nlen) ? vlen : nlen;
if (len == 0) {
free(vec);
free(norm);
return JS_UNDEFINED;
}
// 1) Normalize the planeNormal
// p = planeNormal / |planeNormal|
float mag = 0.0f;
for (size_t i = 0; i < len; i++)
mag += norm[i] * norm[i];
mag = sqrtf(mag);
// If the plane normal is zero-length, no reflection is well-defined
if (mag == 0.0f) {
// Return original vec or undefined, your choice.
// Here, let's just return a copy of the original vec.
JSValue retNoReflect = floats2array(js, vec, vlen);
free(vec);
free(norm);
return retNoReflect;
}
float *pnorm = (float*)malloc(sizeof(float) * len);
if (!pnorm) {
free(vec);
free(norm);
return JS_EXCEPTION;
}
for (size_t i = 0; i < len; i++)
pnorm[i] = norm[i] / mag;
// 2) Compute dot = vec•pnorm
float dot = 0.0f;
for (size_t i = 0; i < len; i++)
dot += vec[i] * pnorm[i];
// 3) reflect = vec - 2*dot*pnorm
float *ref = (float*)malloc(sizeof(float) * len);
if (!ref) {
free(vec);
free(norm);
free(pnorm);
return JS_EXCEPTION;
}
for (size_t i = 0; i < len; i++)
ref[i] = vec[i] - 2.0f * dot * pnorm[i];
// Now return 'ref' as an array
JSValue ret = floats2array(js, ref, len);
free(vec);
free(norm);
free(pnorm);
free(ref);
return ret;
}
static const JSCFunctionListEntry js_math_funcs[] = {
MIST_FUNC_DEF(math, dot,2),
MIST_FUNC_DEF(math, project,2),
MIST_FUNC_DEF(math, rotate, 3),
MIST_FUNC_DEF(math, midpoint, 2),
MIST_FUNC_DEF(math, reflect, 0),
MIST_FUNC_DEF(math, distance, 2),
MIST_FUNC_DEF(math, direction, 2),
MIST_FUNC_DEF(math, angle, 1),
MIST_FUNC_DEF(math, norm, 1),
MIST_FUNC_DEF(math, angle_between, 2),
MIST_FUNC_DEF(math, lerp, 3),
MIST_FUNC_DEF(math, gcd, 2),
MIST_FUNC_DEF(math, lcm, 2),
MIST_FUNC_DEF(math, clamp, 3),
MIST_FUNC_DEF(math, angledist, 2),
MIST_FUNC_DEF(math, jitter, 2),
MIST_FUNC_DEF(math, mean, 1),
MIST_FUNC_DEF(math, sum, 1),
MIST_FUNC_DEF(math, sigma, 1),
MIST_FUNC_DEF(math, median, 1),
MIST_FUNC_DEF(math, length, 1),
MIST_FUNC_DEF(math, from_to, 5),
MIST_FUNC_DEF(math, rand, 0),
MIST_FUNC_DEF(math, randi, 0),
MIST_FUNC_DEF(math, srand,0),
};
#define JS_HMM_FN(OP, HMM, SIGN) \
@@ -2154,53 +2431,6 @@ JSC_CCALL(array_##OP, \
return arr; \
) \
/*JSC_CCALL(array_add,
int len = js_arrlen(js,self);
if (!JS_IsArray(js, argv[0])) {
double n = js2number(js,argv[0]);
JSValue arr = JS_NewArray(js);
for (int i = 0; i < len; i++)
JS_SetPropertyUint32(js, arr, i, number2js(js,js_getnum_uint32(js, self,i) + n));
return arr;
}
JSValue arr = JS_NewArray(js);
size_t len_a, len_b;
float *a = js2floats(js,self, &len_a);
float *b = js2floats(js,argv[0], &len_b);
cblas_saxpy(len_a, 1.0, a, 1, b, 1);
for (int i = 0; i < len; i++)
JS_SetPropertyUint32(js, arr, i, number2js(js,b[i]));
ret = arr;
free(a);
free(b);
return arr;
) */
/*JSC_CCALL(array_add,
int len = js_arrlen(js,self);
if (!JS_IsArray(js,argv[0])) {
double n = js2number(js,argv[0]);
JSValue arr = JS_NewArray(js);
for (int i = 0; i < len; i++)
JS_SetPropertyUint32(js,arr,i,number2js(js,js_getnum_uint32(js,self,i) + n));
return arr;
}
float *vec_a = js2floatarray(js,self);
float *vec_b = js2floatarray(js,argv[0]);
cblas_saxpy(len,1.0f,vec_b,1,vec_a,1);
JSValue tstack[3];
tstack[0] = JS_NewArrayBuffer(js,vec_a,sizeof(float)*2,free_gpu_buffer, NULL, 0);
tstack[1] = JS_UNDEFINED;
tstack[2] = JS_UNDEFINED;
ret = JS_NewTypedArray(js, 3, tstack, JS_TYPED_ARRAY_FLOAT32);
JS_FreeValue(js,tstack[0]);
free(vec_b);
)
*/
JS_HMM_FN(add, Add, +)
JS_HMM_FN(sub, Sub, -)
JS_HMM_FN(div, Div, /)
@@ -7300,13 +7530,9 @@ static ModuleEntry module_registry[] = {
MISTLINE(os),
MISTLINE(input),
MISTLINE(time),
// MISTLINE(profile),
// MISTLINE(debug),
MISTLINE(vector),
MISTLINE(math),
MISTLINE(spline),
// MISTLINE(performance),
MISTLINE(geometry),
// MISTLINE(camera),
};
JSC_SCALL(os_use_embed,
@@ -7780,5 +8006,7 @@ void ffi_load(JSContext *js) {
signal(SIGABRT, signal_handler);
atexit(exit_handler);
m_seedRand(&mrand, time(NULL));
JS_FreeValue(js,globalThis);
}