suvadityamuk HF Staff
Add author citations and refine the interactive article figures
85f6652 verified Download src/lib/math.mjs from suvadityamuk/3d-representations-guide: direct link, hf CLI and curl.
- Browser
- Download file 3.87 kB
-
https://huggingface.co/spaces/suvadityamuk/3d-representations-guide/resolve/main/src/lib/math.mjs
- Command line
-
hf download hf://spaces/suvadityamuk/3d-representations-guide/src/lib/math.mjs
-
curl -L -o math.mjs https://huggingface.co/spaces/suvadityamuk/3d-representations-guide/resolve/main/src/lib/math.mjs
3.87 kB
| export const clamp=(x,a,b)=>Math.max(a,Math.min(b,x)); | |
| export const add=(a,b)=>a.map((x,i)=>x+b[i]); | |
| export const sub=(a,b)=>a.map((x,i)=>x-b[i]); | |
| export const mul=(a,s)=>a.map(x=>x*s); | |
| export const dot=(a,b)=>a.reduce((s,x,i)=>s+x*b[i],0); | |
| export const cross=(a,b)=>[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]; | |
| export const norm=a=>mul(a,1/(Math.hypot(...a)||1)); | |
| export function rotate(p,a){const c=Math.cos(a),s=Math.sin(a);return[c*p[0]-s*p[1],s*p[0]+c*p[1],p[2]];} | |
| export function pose(p,g,t,joints,jointOffset=0,normal=false){let q=[...p];for(const j of [...joints].reverse())if(g>=j.part){const a=j.amplitude*Math.sin(2*Math.PI*t)+(j.part===2?jointOffset:0);q=normal?rotate(q,a):add(j.pivot,rotate(sub(q,j.pivot),a));}return q;} | |
| export function camera(yaw=35,pitch=12,distance=5.2){const a=yaw*Math.PI/180,b=pitch*Math.PI/180;const eye=[distance*Math.sin(a)*Math.cos(b),.2+distance*Math.sin(b),distance*Math.cos(a)*Math.cos(b)];const forward=norm(sub([0,.2,0],eye)),right=norm(cross(forward,[0,1,0])),up=cross(right,forward);return {eye,forward,right,up};} | |
| export function project(p,cam,w,h){const d=sub(p,cam.eye),z=dot(d,cam.forward),k=h/(2*Math.tan(42*Math.PI/360));return{x:w/2+dot(d,cam.right)*k/z,y:h/2-dot(d,cam.up)*k/z,z,k:k/z};} | |
| export function covariance(normal,scale,angle=0){const n=norm(normal),u=norm(cross(n,Math.abs(n[1])<.9?[0,1,0]:[1,0,0])),v=cross(n,u);const ca=Math.cos(angle),sa=Math.sin(angle);const a=add(mul(u,ca),mul(v,sa)),b=sub(mul(v,ca),mul(u,sa));return [a,b,n].map((axis,i)=>({axis,variance:(scale*[1,.5,.18][i])**2}));} | |
| export function projectCovariance(p,components,cam,w,h){const d=sub(p,cam.eye),z=dot(d,cam.forward),x=dot(d,cam.right),y=dot(d,cam.up),f=h/(2*Math.tan(42*Math.PI/360));const jx=mul(sub(mul(cam.right,z),mul(cam.forward,x)),f/(z*z)),jy=mul(sub(mul(cam.up,-z),mul(cam.forward,-y)),f/(z*z));let a=0,b=0,c=0;for(const e of components){const u=dot(jx,e.axis),v=dot(jy,e.axis);a+=u*u*e.variance;b+=u*v*e.variance;c+=v*v*e.variance;}const dlt=Math.sqrt((a-c)**2+4*b*b);return {rx:Math.sqrt(Math.max(.02,(a+c+dlt)/2)),ry:Math.sqrt(Math.max(.02,(a+c-dlt)/2)),angle:.5*Math.atan2(2*b,a-c),a,b,c};} | |
| export function integrate(samples,delta){let t=1,color=[0,0,0];const weights=[];for(const s of samples){const alpha=1-Math.exp(-Math.max(0,s.density)*delta),weight=t*alpha;weights.push(weight);color=color.map((x,i)=>x+weight*s.color[i]);t*=1-alpha;}return {color,transmittance:t,weights};} | |
| export const storageBytes=(side,dimensions,channels=3,bits=8)=>side**dimensions*channels*bits/8; | |
| export function voxelize(samples,res=16,slice=1){const size=3.4/res,m=new Map();for(const s of samples){const cell=s.p.map(v=>Math.floor((v+1.6)/size));if((cell[1]+.5)/res>slice)continue;const key=cell.join(',');if(!m.has(key))m.set(key,{p:cell.map(v=>(v+.5)*size-1.6),c:s.c,g:s.g});}return [...m.values()];} | |
| export function sampleTime(time,mode){if(mode==='frames')return Math.floor(time*8)/8;if(mode==='keyframes'){const a=Math.floor(time*4)/4,b=a+.25,f=(time-a)*4;return {a,b,f};}return time;} | |
| // One shared occupancy mask for both views. Sparse leaves partition the same domain. | |
| export function quadtreeComparison(depth){ | |
| const n=2**depth; | |
| const occupied=(x,y)=>{const u=(x+.5)/n,v=(y+.5)/n;return (v>.85&&u>.2&&u<.75)||(Math.abs(u-(.4-.2*(.85-v)/.4))<.04&&v>.45&&v<.85)||(Math.abs(u-(.2+.35*(.45-v)/.25))<.04&&v>.2&&v<.45)||(Math.hypot((u-.6)*1.6,v-.2)<.13);}; | |
| const dense=Array.from({length:n*n},(_,i)=>({x:i%n,y:Math.floor(i/n),size:1,occupied:occupied(i%n,Math.floor(i/n))})),sparse=[]; | |
| const visit=(x,y,size)=>{let count=0;for(let j=y;j<y+size;j++)for(let i=x;i<x+size;i++)if(dense[j*n+i].occupied)count++;if(count&&size>1){for(const [dx,dy]of [[0,0],[size/2,0],[0,size/2],[size/2,size/2]])visit(x+dx,y+dy,size/2);}else sparse.push({x,y,size,occupied:count>0});};visit(0,0,n);return {n,dense,sparse}; | |
| } | |