functiontranslate(v)=let(u=is_list(v)?len(v)==2?[v.x,v.y,0]//! Generate a 4x4 translation matrix, ```v``` can be ```[x, y]```, ```[x, y, z]``` or ```z```
:v
:[0,0,v])
[[1,0,0,u.x],
[0,1,0,u.y],
[0,0,1,u.z],
[0,0,0,1]];
functionrotate(a,v)=//! Generate a 4x4 rotation matrix, ```a``` can be a vector of three angles or a single angle around ```z```, or around axis ```v```
is_undef(v)?let(av=is_list(a)?a:[0,0,a],
cx=cos(av[0]),
cy=cos(av[1]),
cz=cos(av[2]),
sx=sin(av[0]),
sy=sin(av[1]),
sz=sin(av[2]))
[
[cy*cz,cz*sx*sy-cx*sz,cx*cz*sy+sx*sz,0],
[cy*sz,cx*cz+sx*sy*sz,-cz*sx+cx*sy*sz,0],
[-sy,cy*sx,cx*cy,0],
[0,0,0,1]
]
:let(s=sin(a),
c=cos(a),
C=1-c,
m=sqr(v.x)+sqr(v.y)+sqr(v.z),// m used instead of norm to avoid irrational roots as much as possible
functionscale(v)=let(s=is_list(v)?v:[v,v,v])//! Generate a 4x4 matrix that scales by ```v```, which can be a vector of xyz factors or a scalar to scale all axes equally
[
[s.x,0,0,0],
[0,s.y,0,0],
[0,0,s.z,0],
[0,0,0,1]
];
functionvec3(v)=[v.x,v.y,v.z];//! Return a 3 vector with the first three elements of ```v```
functiontransform(v,m)=vec3(m*[v.x,v.y,v.z,1]);//! Apply 4x4 transform to a 3 vector by extending it and cropping it again
functiontransform_points(path,m)=[for(p=path)transform(p,m)];//! Apply transform to a path
functionunit(v)=let(n=norm(v))n?v/n:v;//! Convert ```v``` to a unit vector
functiontranspose(m)=[for(j=[0:len(m[0])-1])[for(i=[0:len(m)-1])m[i][j]]];//! Transpose an arbitrary size matrix
functionidentity(n,x=1)=[for(i=[0:n-1])[for(j=[0:n-1])i==j?x:0]];//! Construct an arbitrary size identity matrix
functionreverse(v)=let(n=len(v)-1)n<0?[]:[for(i=[0:n])v[n-i]];//! Reverse a vector