-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdemocapsid.min.js
6 lines (6 loc) · 22 KB
/
democapsid.min.js
1
2
3
4
5
6
/*!
* democapsid v2.2.2 - Render viral capsids in the browser and export SVG.
* MIT License
* Copyright (c) 2020 - 2024, Daniel Antonio Negrón (dnanto/remaindeer)
*/
const e="2.2.2",t=Math.sqrt(3),r=Math.sqrt(5),o=(1+r)/2,a=100,n=1e-15,s=1e-5;function mmul(e,t){const[r,o,a]=[e.length,e[0].length,t[0].length];for(var n=new Array(r),s=0;s<r;s++)n[s]=new Array(a).fill(0);for(s=0;s<r;s++)for(var c=0;c<a;c++)for(var i=0;i<o;i++)n[s][c]+=e[s][i]*t[i][c];return n}function det2(e){return e[0][0]*e[1][1]-e[0][1]*e[1][0]}function det3(e){return e[0][0]*(e[1][1]*e[2][2]-e[1][2]*e[2][1])-e[0][1]*(e[1][0]*e[2][2]-e[1][2]*e[2][0])+e[0][2]*(e[1][0]*e[2][1]-e[1][1]*e[2][0])}function inv2(e){const t=det2(e);return[[e[1][1],-e[0][1]].div(t),[-e[1][0],e[0][0]].div(t)]}function inv3(e){const[t,r,o,a,n,s,c,i,l]=[e[0][0],e[0][1],e[0][2],e[1][0],e[1][1],e[1][2],e[2][0],e[2][1],e[2][2]],d=this.det3(e);return[[(n*l-s*i)/d,-(r*l-o*i)/d,(r*s-o*n)/d],[-(a*l-s*c)/d,(t*l-o*c)/d,-(t*s-o*a)/d],[(a*i-n*c)/d,-(t*i-r*c)/d,(t*n-r*a)/d]]}function T(e){for(var t=Array.from({length:e[0].length},(()=>Array.from({length:e.length},(()=>[])))),r=0;r<t.length;r++)t[r]=new Array(e.length);for(r=0;r<e.length;r++)for(var o=0;o<e[0].length;o++)t[o][r]=e[r][o];return t}function rotmat3(e,t,r){const[o,a,n,s,c,i]=[Math.sin(e),Math.sin(t),Math.sin(r),Math.cos(e),Math.cos(t),Math.cos(r)];return[[s*c,s*a*n-o*i,s*a*i+o*n],[o*c,o*a*n+s*i,o*a*i-s*n],[-a,c*n,c*i]]}function camera(e,t,r,o=[0,0,0]){const a=rotmat3(e,t,r),n=[[1,0,0,-o[0]],[0,1,0,-o[1]],[0,0,1,-o[2]]];return mmul(mmul([[1,0,0],[0,1,0],[0,0,1]],a),n)}function*brackets(e,t,r,o){const a=r/o;let n=Math.sign(e(t));for(let s=0;s<o;s++){let r=t+s*a,o=Math.sign(e(r));n!=o&&(yield[t+(s-1)*a,r],n=o)}}function bisection(e,t,r,o,a){let n=1,s=(t+r)/2,c=e(s);for(;n<=a&&(s=(t+r)/2,c=e(s),!(0==c||(r-t)/2<o));n++)Math.sign(c)==Math.sign(e(t))?t=s:r=s;return[n,c,s]}function degrees(e){return 180*e/Math.PI}function radians(e){return e*Math.PI/180}function calc_tile(e,r){const o=r*(t/2);let a;if("hex"===e)a={basis:[[2*o,0],[o,t*o]],tile:e=>[new paper.Path.RegularPolygon({center:e.coor,sides:6,radius:r,data:{mer:1}})],radius:r};else if("trihex"===e)a={basis:[[2*r,0],[r,r*t]],tile:e=>[new paper.Path.RegularPolygon({center:e.coor,sides:6,radius:r,data:{mer:1}}).rotate(30),...Array.from({length:2},((t,a)=>new paper.Path.RegularPolygon({center:e.coor.add([r,-1/3*o]),sides:3,radius:2/3*o,data:{mer:2}}).rotate(180).rotate(60*a,e.coor)))],radius:2*o};else if("snubhex"===e)a={basis:[[2.5*r,o],[.5*r,3*o]],tile:e=>[new paper.Path.RegularPolygon({center:e.coor,sides:6,radius:r,data:{mer:1}}).rotate(30),...Array.from({length:6},((t,r)=>new paper.Path.RegularPolygon({center:e.coor.add([0,-o-1/3*o]),sides:3,radius:2/3*o,data:{mer:2}}).rotate(60*r,e.coor))),new paper.Path.RegularPolygon({center:e.coor.add([1.5*r,-1/3*o]),sides:3,radius:2/3*o,data:{mer:2}}),new paper.Path.RegularPolygon({center:e.coor.add([-1.5*r,2/3*o]),sides:3,radius:2/3*o,data:{mer:2}}).rotate(180)],radius:2*o};else if("rhombitrihex"===e)a={basis:[[r+o+.5*r,.5*r+o],[0,2*o+r]],tile:e=>[new paper.Path.RegularPolygon({center:e.coor,sides:6,radius:r,data:{mer:1}}).rotate(30),...Array.from({length:3},((o,a)=>new paper.Path.RegularPolygon({center:e.coor.add([0,r+r*(t/3)]),sides:3,radius:r/t,data:{mer:2}}).rotate(-60*a-30,e.coor))),...Array.from({length:3},((t,a)=>new paper.Path.RegularPolygon({center:e.coor.add([0,-o-.5*r]),sides:4,radius:Math.sqrt(2*r*r)/2,data:{mer:3}}).rotate(60*a,e.coor)))],radius:Math.sqrt(Math.pow(o+r,2)+Math.pow(r/2,2))};else if("dualhex"===e)a={basis:[[1.5*r,o],[0,2*o]],tile:e=>Array.from({length:6},((a,n)=>new paper.Path.RegularPolygon({center:e.coor.add([0,o-r*t/6]),sides:3,radius:r/t,data:{mer:1}}).rotate(60*n,e.coor))),radius:r};else if("dualtrihex"===e)a={basis:[[2*o,0],[o,t*o]],tile:e=>[...Array.from({length:6},((t,a)=>new paper.Path({segments:[[0,0],[.5*o,-.25*r*Math.sin(Math.PI/6)/Math.cos(Math.PI/3)],[o,0],[.5*o,.25*r*Math.sin(Math.PI/6)/Math.cos(Math.PI/3)]].map((t=>e.coor.add(t))),closed:!0,data:{mer:1}}).rotate(60*a,e.coor))),...Array.from({length:6},((t,a)=>new paper.Path({segments:[[-.5*o,.5*r+.25*r*Math.sin(Math.PI/6)/Math.cos(Math.PI/3)],[0,.5*r],[o-.5*o,.5*r+.25*r*Math.sin(Math.PI/6)/Math.cos(Math.PI/3)],[0,.5*r+.25*r*Math.sin(Math.PI/6)*2/Math.cos(Math.PI/3)]].map((t=>e.coor.add(t))),closed:!0,data:{mer:2}}).rotate(60*a,e.coor)))],radius:r};else if("dualsnubhex"===e)a={basis:[[2.5*r,o],[.5*r,2*o+r*t/3*2-r*t/6]],tile:e=>Array.from({length:6},((a,n)=>new paper.Path({segments:[[0,0],[0,o+r*t/6],[.5*r,o+r*t/3],[r,o+r*t/6],[r,r*t/3]].map((t=>e.coor.add(t))),closed:!0,data:{mer:1}}).rotate(60*n,e.coor))),radius:o+r*t/3};else if("dualrhombitrihex"===e)a={basis:[[1.5*r,o],[0,2*o]],tile:e=>Array.from({length:6},((a,n)=>new paper.Path({segments:[[0,0],[0,o],[.5*r,o],[t/2*o,.5*o]].map((t=>e.coor.add(t))),closed:!0,data:{mer:1}}).rotate(60*n,e.coor))),radius:r};else if("pinwheel-1"===e)a={basis:[[1.5*o,.75*r],[0,1.5*r]],tile:e=>Array.from({length:6},((t,a)=>new paper.Path({segments:[[0,0],[0,r],[-o/2,.75*r],[-o/2,.25*r]].map((t=>e.coor.add(t))),closed:!0,data:{mer:1}}).rotate(60*a,e.coor))),radius:o};else{if("pinwheel-2"!==e)throw new Error("incorrect tile mode");a={basis:[[1.5*o,.75*r],[0,1.5*r]],tile:e=>Array.from({length:6},((t,a)=>new paper.Path({segments:[[0,0],[0,r],[o/2,.75*r],[o/2,.25*r]].map((t=>e.coor.add(t))),closed:!0,data:{mer:1}}).rotate(60*a,e.coor))),radius:o}}return a}function*tile_grid(e,t){const r=e.map((e=>mmul(T(inv2(t)),[e,1].flat().T()).flat())).map((e=>e.map(Math.round))),[o,a,n,s]=[...[0,1].map(((e,t)=>Math.min(...r.map((e=>e[t]))))),...[0,1].map(((e,t)=>Math.max(...r.map((e=>e[t])))))];for(let c=o;c<n+1;c++)for(let e=a;e<s+1;e++)yield{index:[c,e],coor:t[0].mul(c).add(t[1].mul(e)),is_vertex:r.has([c,e])}}function ck_vectors(e,t,r,o,a,n){const[s,c]=e,i=c.rot(Math.PI/3);return n?[s.mul(t).add(c.mul(r)),c.mul(o).add(i.mul(a)),i.mul(t).add(s.mul(-r)),s.mul(r).add(i.mul(-t))]:[s.mul(t).add(i.mul(-r)),c.mul(o).add(s.mul(a)),i.mul(t).add(c.mul(r)),s.mul(t).add(i.mul(-r)).rot(-Math.PI/3)]}function triangle_circumcircle_center(e,t,r){const[o,a]=[e.sub(r),t.sub(r)],n=o.cross(a);return a.mul(o.norm()**2).sub(o.mul(a.norm()**2)).cross(n).div(2*n.norm()**2).add(r)}function tetrahedron_circumsphere_center(e,t,r,o){const[a,n,s]=[t,r,o].map((t=>t.sub(e)));return e.add(a.cross(n).mul(s.norm()**2).add(s.cross(a).mul(n.norm()**2)).add(n.cross(s).mul(a.norm()**2)).div(2*det3([a,n,s])))}function body_radius(e){return e[6].sub([0,0,e[6][2]]).norm()}function height(e){return e[0][2]-e[19][2]}function body_height(e){return e[4][2]-e[6][2]}function sd_sphere(e,t){return e.norm()-t}function spherize(e,t,r){return e.uvec().mul(Math.abs(sd_sphere(e,t))*r).add(e)}function cylinderize(e,t,r,o){const[a,n]=[body_radius(t),body_height(t)/2];let s,c;if(5===r)s=[0,0,n-a/2],c=t[0][2]+a/2-n;else if(3===r){const[e,r]=[t[0],t[3]];s=triangle_circumcircle_center(e,r,[r[0],-r[1],r[2]]),c=e.sub(s).norm()}else 2===r&&(p1=t[0],s=tetrahedron_circumsphere_center(p1,...[1,4,5].map((e=>t[e]))),c=p1.sub(s).norm());const[i,l,d,u]=[[0,0,s[2]],[0,0,-s[2]],[0,0,n],[0,0,-n]];if(n<e[2]){const t=Math.abs(sd_sphere(e.sub(i),c));return e.sub(d).uvec().mul(t*o).add(e)}if(e[2]<-n){const t=Math.abs(sd_sphere(e.sub(l),c));return e.sub(u).uvec().mul(t*o).add(e)}return e.sub([0,0,e[2]]).uvec().mul((a-e.slice(0,2).norm())*o).add(e)}function ico_config(e){let t;if(5===e)t=[[1,1,2,2],["T1-▲","T1-▼","T2-▲","T2-▼"],[[0,1,2],[6,11,7],[2,1,6],[6,7,2]],[5,5,5,5],[[1,2,3,4,5],[0,2,5,6,10],[0,1,3,6,7],[0,2,4,7,8],[0,3,5,8,9],[0,1,4,9,10],[1,2,7,10,11],[2,3,6,8,11],[3,4,7,9,11],[4,5,8,10,11],[1,5,6,9,11],[6,7,8,9,10]]];else if(3===e)t=[[1,1,1,1,2,2,3,3],["T1-▔","T1-▲","T1-▼","T1-▁","T2-▼","T2-▲","T3-▼","T3-▲"],[[0,2,1],[1,2,3],[6,9,11],[9,10,11],[1,3,6],[9,6,3],[1,6,5],[11,5,6]],[1,3,3,1,3,3,3,3],[[1,2,4,5,8],[0,2,3,5,6],[0,1,3,4,7],[1,2,6,7,9],[0,2,7,8,10],[0,1,6,8,11],[1,3,5,9,11],[2,3,4,9,10],[0,4,5,10,11],[3,6,7,10,11],[4,7,8,9,11],[5,6,8,9,10]]];else{if(2!==e)throw new Error("a must be 2, 3, or 5");t=[[1,1,1,1,2,2,2,2,3,3],["T1-▔","T1-▔","T1▁","T1▁","T2-▼","T2-▲","T2-▼","T2-▲","T3-▼","T3-▲"],[[0,1,2],[2,1,4],[9,10,6],[9,11,10],[0,2,6],[9,6,2],[2,4,9],[11,9,4],[0,6,5],[10,5,6]],[2,2,2,2,2,2,2,2,2,2],[[1,2,3,5,6],[0,2,3,4,7],[0,1,4,6,9],[0,1,5,7,8],[1,2,7,9,11],[0,3,6,8,10],[0,2,5,9,10],[1,3,4,8,11],[3,5,7,10,11],[2,4,6,10,11],[5,6,8,9,11],[4,7,8,9,10]]]}return Object.fromEntries(["t_idx","t_id","v_idx","t_rep","v_con"].map(((e,r)=>[e,t[r]])))}function ico_axis_5(e){const[t,o]=[e[0].norm(),e[1].norm()],a=t*Math.sqrt((5+r)/10),n=[0,0,(1+r)*t/(2*Math.sqrt(5+2*r))],s=[-a,0,0].roro([0,0,1],.3*Math.PI),c=s.add([t,0,0]),i=e[0].angle(e[1]),l=c.add([o,0,0].roro([0,1,0],-Math.PI-i)),d=s.add(l.sub(s).proj(c.sub(s))),u=[d[0],-Math.abs(d[1])*Math.sqrt(a*a*d[1]*d[1]-(d[0]*d[1])**2)/(d[1]*d[1]),0];if(Number.isNaN(u[1]))throw new Error("impossible construction!");const p=u.add([0,0,-Math.sqrt(l[2]*l[2]-(d[1]-u[1])**2)]);return[n,s,c].concat([1,2,3].map((e=>c.roro([0,0,1],2*e/5*Math.PI)))).concat([p]).concat([1,2,3,4].map((e=>p.roro([0,0,1],2*e/5*Math.PI)))).concat([[0,0,p[2]-n[2]]]).map((e=>e.add([0,0,-p[2]/2])))}function ico_axis_3(e,r=a,o=n){const[s,c,i]=[e[0].norm(),e[1].norm(),e[2].sub(e[1]).norm()],l=[0,s*(1/t),0],d=[s/2,-s*(t/6),0],u=[-s/2,-s*(t/6),0],p=[0,-s*(2*t/3),0];function fold(a){let[n,l]=[p.uvec().mul(s*(t/2)),d.sub(u).uvec()];const m=[0,-s*(t/6),0].add(n.roro(l,a)),h=m.roro([0,0,1],2/3*Math.PI);a=e[0].angle(e[1]),[n,l]=[m.sub(d).uvec().mul(c),m.cross(d).uvec()];const _=n.roro(l,a),[g,y]=[d.add(_.proj(n)),d.add(_)];[n,l]=[y.sub(g),d.sub(m).uvec()];const f=e=>i-g.add(n.roro(l,e)).sub(h).norm();a=bisection(f,...brackets(f,0,2*Math.PI,r).next().value,o,r).slice(-1);const b=g.add(n.roro(l,a));return[m,h,b,Math.abs(m[1])-b.sub([0,0,b[2]]).norm()]}const m=Math.PI/180/10;let h=0;for(let t=0;t*m<Math.PI/2;t++){h=t*m;try{fold(h);break}catch(P){}}let obj=e=>fold(e).slice(-1)[0];try{h=bisection(obj,...brackets(obj,h,Math.PI/4,r).next().value,o,r).slice(-1)}catch(P){throw new Error("impossible construction!")}const[_,g,y]=fold(h).slice(0,-1);if(Number.isNaN(_[0]))throw new Error("impossible construction!");const b=[0,0,1];h=2*Math.PI/3;const M=y.roro(b,-h),w=M.sub([0,0,M[2]]).roro(b,Math.PI/3).uvec().mul(l[1]).add([0,0,M[2]+_[2]-l[2]]);let v=[l,d,u,_,g.roro(b,h),g,y,M,M.roro(b,-h),w,w.roro(b,-h),w.roro(b,-2*h)];return v.map((e=>e.add([0,0,(v[0][2]-v.slice(-1)[0][2])/2])))}function ico_axis_2(e,t=a,r=n){const[s,c,i]=[e[0].norm(),e[1].norm(),e[2].sub(e[1]).norm()],l=[s/2,0,0],d=[-s/2,0,0],u=[0,-s*o/2,-(s*o-s)/2],p=[0,s*o/2,-(s*o-s)/2];function fold(o){let a=d.add(u).div(2),[n,s]=[a.sub(l),u.sub(d).uvec()];const p=a.add(n.roro(s,o)),m=p.roro([0,0,1],Math.PI);o=e[0].angle(e[1]),[n,s]=[u.sub(l).uvec().mul(c),u.cross(l).uvec()];const h=n.roro(s,o);a=l.add(h.proj(n));const _=l.add(h);[n,s]=[_.sub(a),l.sub(u).uvec()];const f=e=>i-a.add(n.roro(s,e)).sub(m).norm();o=bisection(f,...brackets(f,0,2*Math.PI,t).next().value,r,t).slice(-1);const g=a.add(n.roro(s,o));return[p,m,g,p.sub([0,0,p[2]]).norm()-g.sub([0,0,g[2]]).norm()]}const m=Math.PI/180/10;let h=0;for(let o=0;o*m<Math.PI/2;o++){h=o*m;try{fold(h);break}catch(w){}}let obj=e=>fold(e).slice(-1)[0];try{h=bisection(obj,...brackets(obj,h,Math.PI/4,t).next().value,r,t).slice(-1)}catch(w){throw new Error("impossible construction!")}const[_,g,y]=fold(h).slice(0,-1);if(Number.isNaN(_[0]))throw new Error("impossible construction!");obj=e=>l.roro([0,0,1],e).add([0,0,y[2]+_[2]]).sub(g).norm()-c;try{h=bisection(obj,...brackets(obj,0,2*Math.PI,t).next().value,r,t).slice(-1)}catch(w){throw new Error("impossible construction!")}const b=l.roro([0,0,1],h).add([0,0,y[2]+_[2]]),M=b.sub([0,0,b[2]]).uvec().roro([0,0,1],Math.PI/2).mul(p[1]).add([0,0,y[2]+_[2]-p[2]]);return coor=[l,d,u,p,_,g,y,y.roro([0,0,1],Math.PI),M,M.roro([0,0,1],Math.PI),b,b.roro([0,0,1],Math.PI)],coor.map((e=>e.add([0,0,(coor[0][2]-coor.slice(-1)[0][2])/2])))}function model_sa_error(e){try{const t=ck_vectors(calc_tile(e.t,e.R).basis,e.h,e.k,e.H,e.K,e.c),r=[[t[3],t[0]],[t[0],t[1]],[t[1],t[2]]],o=["","",ico_axis_2,ico_axis_3,"",ico_axis_5][e.a](t,a,n),s=ico_config(e.a),c=s.t_id.map((e=>parseInt(e[1]))).reduce(((e,t)=>e<t?t:e)),i=Array.from({length:c}).fill(0);s.t_id.forEach(((e,t)=>i[e[1]-1]+=s.t_rep[t]));const l=r.slice(0,c).map(((e,t)=>[...e[0],0].cross([...e[1],0]).norm()/2*i[t])).sum();return(l-s.v_idx.map((e=>e.map((e=>o[e])))).map(((e,t)=>e[1].sub(e[0]).cross(e[2].sub(e[0])).norm()/2*s.t_rep[t])).sum())/l}catch(t){return NaN}}function lattice_config(e,t,r,o,a,s,c){const i=calc_tile(c,s),l=ck_vectors(i.basis,e,t,r,o,a),d=Array.from(tile_grid(l,i.basis)),u=d.map(i.tile),p=d.filter((e=>e.is_vertex)).map((e=>e.coor)).concat([[0,0]]);return u.flat().forEach((e=>{e.data.offset=e.data.mer+(p.some((t=>[e.position.x,e.position.y].sub(t).norm()-i.radius<n))?0:3),e.data.centroid=e.segments.map((e=>e.point)).reduce(((e,t)=>e.add(t))).divide(e.segments.length)})),{tile:i,ck:l,lattice:u}}function calc_facets(e,t){const r=[[3,0],[0,1],[1,2]].map((t=>[e.ck[t[0]],e.ck[t[1]]])).map((e=>new paper.Path({segments:[[0,0],...e],closed:!0,data:{vectors:[[0,0],...e]}}))),o=r.map((r=>new paper.Group({children:e.lattice.flatMap((e=>e.map((e=>{const o=e.curves.map((e=>[e.segment1.point,e.segment2.point])),a=e.intersect(r,{insert:!1});return a.data.has_centroid=r.contains(a.data.centroid),a.data.centroid_on_vertex=a.segments.findIndex((e=>e.point.getDistance(a.data.centroid)<1e-5))>-1,a.style.fillColor=t["mer_color_"+a.data.offset]+t["mer_alpha_"+a.data.offset],a.data.strokes=a.curves.map((e=>[e.segment1.point,e.segment2.point])).map(((e,t)=>o.some((t=>[0,1].every((r=>t[0].subtract(e[r]).cross(t[1].subtract(e[r]))<1e-5))&&t[0].subtract(t[1]).isCollinear(e[0].subtract(e[1]))))?t:-1)).split(-1).map((e=>(e.push((e[e.length-1]+1)%a.curves.length),e))),a})))).sort(((e,t)=>e.data.offset-t.data.offset)).filter((e=>e.segments.length>0)),data:r.data})));return r.forEach((e=>e.remove())),o}function draw_lattice(e){const[t,r,o,a,n,s,c]=["h","k","H","K","c","R","t"].map((t=>e[t])),i=lattice_config(t,r,o,a,n,s,c);return i.lattice.flat().forEach((t=>t.style.fillColor=e["mer_color_"+t.data.offset]+e["mer_alpha_"+t.data.offset])),new paper.Group(new paper.Group({children:i.lattice.flat(),position:paper.view.center,style:{strokeColor:e.line_color+e.line_alpha,strokeWidth:e.line_size,strokeCap:"round",strokeJoin:"round"}})).scale(1,-1)}function draw_facets(e){const[t,r,o,a,n,s,c]=["h","k","H","K","c","R","t"].map((t=>e[t])),i=lattice_config(t,r,o,a,n,s,c),l=new paper.Group({children:calc_facets(i,e),position:paper.view.center}).scale(1,-1);return i.lattice.forEach((e=>e.forEach((e=>e.remove())))),e.facet_toggle?(l.style.strokeColor=e.line_color+e.line_alpha,l.style.strokeWidth=e.line_size,l.style.strokeCap="round",l.style.strokeJoin="round",l):(l.remove(),new paper.Group({children:l.children.map((t=>new paper.Group(t.children.map((t=>{const r=t.segments.map((e=>e.point)),o=new paper.Group(t.data.strokes.map((t=>new paper.Path({segments:t.map((e=>r[e])),closed:!1,style:{strokeColor:e.line_color,strokeWidth:e.line_size}}))));return new paper.Group([t.clone(),o])}))))),style:{strokeCap:"round",strokeJoin:"round"}}))}function draw_net(e){const[t,r,o,a,n,s,c]=["h","k","H","K","c","R","t"].map((t=>e[t])),i=lattice_config(t,r,o,a,n,s,c),l=i.ck,d=calc_facets(i,e);let u;if(5==e.a){const e=new paper.Group(d.slice(0,2).map((e=>e.clone()))),t=e.clone().rotate(180,l[0]).translate(l[1].sub(l[0].mul(2)));u=new paper.Group({children:[e,t].flatMap((e=>Array.from({length:5},((t,r)=>e.clone().translate(l[0].mul(r)))))).flatMap((e=>e.children)),position:paper.view.center}).rotate(-degrees(Math.atan2(l[0].dot([0,1]),1*l[0][0]-0*l[0][1]))),[e,t].forEach((e=>e.remove()))}else if(3==e.a){const e=[[0,0],l[0],l[3]].centroid(),t=new paper.Group(d.slice(0,1).map((e=>e.clone()))),r=new paper.Group(d.slice(0,3).map((e=>e.clone()))).translate(l[0]).rotate(-60,l[0]),o=new paper.Group([t.clone(),...Array.from({length:3},((t,o)=>r.clone().rotate(120*o,e)))]),a=l[0].add(l[1].rot(Math.PI/3).rot(4*Math.PI/3));u=new paper.Group({children:[o.clone(),o.clone().translate(l[0].add(a)).rotate(60,a)].flatMap((e=>e.children)).flatMap((e=>e.children)),position:paper.view.center}).rotate(-degrees(Math.atan2(l[0].dot([0,1]),1*l[0][0]-0*l[0][1]))-30),[t,r,o].forEach((e=>e.remove()))}else if(2==e.a){const e=new paper.Group(d.slice(0,3).map((e=>e.clone()))),t=new paper.Group([...e.clone().children,e.children[0].clone().rotate(60,l[0]),e.children[2].clone().translate(l[0])]),r=new paper.Group([t.clone(),t.clone().rotate(180,l[3]).translate(l[3].mul(-1))]);u=new paper.Group({children:[r.clone(),r.clone().translate(l[1].mul(-1).add(l[0].mul(-2)).add(l[3]))].flatMap((e=>e.children)).flatMap((e=>e.children)),position:paper.view.center}).rotate(-degrees(Math.atan2(l[0].dot([0,1]),1*l[0][0]-0*l[0][1]))-30),[e,t,r].forEach((e=>e.remove()))}return d.forEach((e=>e.remove())),i.lattice.forEach((e=>e.forEach((e=>e.remove())))),e.facet_toggle?(u.style.strokeColor=e.line_color+e.line_alpha,u.style.strokeWidth=e.line_size,u.style.strokeCap="round",u.style.strokeJoin="round",u.scale(1,-1)):(u.remove(),new paper.Group({children:u.children.flatMap((t=>new paper.Group(t.children.map((t=>{const r=t.segments.map((e=>e.point)),o=new paper.Group(t.data.strokes.map((t=>new paper.Path({segments:t.map((e=>r[e])),closed:!1,style:{strokeColor:e.line_color,strokeWidth:e.line_size}}))));return new paper.Group([t.clone(),o])}))))),style:{strokeCap:"round",strokeJoin:"round"}}).scale(1,-1))}function draw_capsid(e){const[t,r,o,c,i,l,d]=["h","k","H","K","c","R","t"].map((t=>e[t])),u=lattice_config(t,r,o,c,i,l,d),p=calc_facets(u,e),m=ico_config(e.a),h=["","",ico_axis_2,ico_axis_3,"",ico_axis_5][e.a](u.ck,a,n),_=2*Math.PI/e.a,g=t==o&&r==c?t=>spherize(t,h[0].norm(),e.s):t=>cylinderize(t,h,e.a,e.s),y=camera(...[e.θ,e.ψ,e.φ].map(radians));let b=[];for(let a=0,n=0;a<m.t_idx.length;a++){const e=p[m.t_idx[a]-1],t=inv3(T(e.data.vectors.map((e=>e.concat(1))))),r=[0,1,2].map((e=>h[m.v_idx[a][e]]));for(let o=0;o<m.t_rep[a];o++,n++){const a=r.map((e=>e.roro([0,0,1],o*_))),s=mmul(T(a),t),c=e.children.map((e=>{const t=e.segments.map((e=>[e.point.x,e.point.y,1])).map((e=>mmul(s,e.T()).flat())).map((e=>g(e))).map((e=>mmul(y,e.concat(1).T()).flat())),r=mmul(y,g(mmul(s,[e.data.centroid.x,e.data.centroid.y,1].T()).flat()).concat(1).T()).flat();return new paper.Path({segments:t.map((e=>e.slice(0,2))),closed:e.closed,data:Object.assign({},e.data,{id:n,centroid:r,segments_3D:t,normal:t[1].sub(t[0]).cross(t[2].sub(t[0])).uvec()}),style:e.style})}));b=b.concat(new paper.Group({children:c,data:{type:"facet",centroid:mmul(y,g(a.centroid()).concat(1).T()).flat()}}))}}const M=h.map((e=>mmul(y,e.concat(1).T()).flat()));let w=e.penton_fiber_toggle?m.v_con.map((e=>e.map((e=>M[e])).reduce(((e,t)=>e.add(t)),[0,0,0]).uvec())).map(((t,r)=>[M[r],M[r].add(t.mul(e.fiber_length))])):[];w=w.concat(b.flatMap((e=>e.children)).filter((t=>e["mer_toggle_"+t.data.offset]&&t.data.has_centroid)).map((t=>{const r=t.data.centroid;return[r,r.add(t.data.normal.mul(e.fiber_length))]})));let v=[];w.forEach((e=>{let t=0;for(let r of v)e[0].sub(r[0][0]).norm()<s&&(t=r.push(e));0===t&&v.push([e])})),w=v.map((e=>[e[0][0],e.map((e=>e[1])).reduce(((e,t)=>e.add(t)),[0,0,0]).div(e.length)])).map((e=>new paper.Path.Line({from:e[0],to:e[1],data:{centroid:e[1].mul(2)}})));const P=e.knob_toggle?w.map((t=>new paper.Path.Circle({center:t.segments[1].point,radius:e.knob_size,data:{centroid:t.data.centroid}}))):[];b=b.concat(w).concat(P),b.sort(((e,t)=>e.data.centroid[2]-t.data.centroid[2]));const k=new paper.Group({children:b,position:paper.view.center,style:{strokeWidth:e.line_size,strokeCap:"round",strokeJoin:"round"}});return P.forEach((t=>{t.style.strokeColor=e.line_color+e.line_alpha,t.style.fillColor=e.knob_color+e.knob_alpha})),w.forEach((t=>{t.style.strokeColor=e.fiber_color+e.fiber_alpha,t.style.strokeWidth=e.fiber_size})),p.forEach((e=>e.remove())),u.lattice.forEach((e=>e.forEach((e=>e.remove())))),e.facet_toggle?(k.children.filter((e=>"facet"===e.data.type)).forEach((t=>{t.style.strokeColor=e.line_color+e.line_alpha,t.style.strokeWidth=e.line_size})),k.style.strokeCap="round",k.style.strokeJoin="round",k.scale(-1,1)):(k.remove(),new paper.Group({children:k.children.map((t=>Object.hasOwn(t.data,"type")&&"facet"===t.data.type?new paper.Group(t.children.map((t=>{const r=t.segments.map((e=>e.point)),o=new paper.Group(t.data.strokes.map((t=>new paper.Path({segments:t.map((e=>r[e])),closed:!1,style:{strokeColor:e.line_color+e.line_alpha,strokeWidth:e.line_size}}))));return new paper.Group([t.clone(),o])}))):t)),style:{strokeCap:"round",strokeJoin:"round"}}).scale(-1,1))}Array.prototype.mul=function(e){return this.map((t=>t*e))},Array.prototype.div=function(e){return this.map((t=>t/e))},Array.prototype.add=function(e){return this.map(((t,r)=>t+e[r]))},Array.prototype.sub=function(e){return this.map(((t,r)=>t-e[r]))},Array.prototype.dot=function(e){return this.map(((t,r)=>t*e[r])).reduce(((e,t)=>e+t))},Array.prototype.sum=function(e=0){return this.reduce(((e,t)=>e+t),e)},Array.prototype.centroid=function(){return this.reduce(((e,t)=>e.add(t))).div(this.length)},Array.prototype.cross=function(e){return[this[1]*e[2]-this[2]*e[1],this[2]*e[0]-this[0]*e[2],this[0]*e[1]-this[1]*e[0]]},Array.prototype.rot=function(e){const[t,r]=[Math.cos(e),Math.sin(e)];return mmul([[t,-r],[r,t]],this.T()).flat()},Array.prototype.roro=function(e,t){return this.mul(Math.cos(t)).add(e.cross(this).mul(Math.sin(t))).add(e.mul(e.dot(this)).mul(1-Math.cos(t)))},Array.prototype.norm=function(){return Math.sqrt(this.map((e=>e*e)).sum())},Array.prototype.uvec=function(){return this.div(this.norm())},Array.prototype.angle=function(e){return Math.acos(this.dot(e)/(this.norm()*e.norm()))},Array.prototype.proj=function(e){return e.mul(this.dot(e)/e.dot(e))},Array.prototype.T=function(){return this.map((e=>[e]))},Array.prototype.distance=function(e){return this.sub(e).norm()},Array.prototype.has=function(e,t=n){return this.some((r=>r.length===e.length&&r.distance(e)<t))},Array.prototype.split=function(e){return this.reduce((function(e,t){return-1===t?e.push([]):e[e.length-1].push(t),e}),[[]]).filter((e=>e.length))},"undefined"!=typeof exports&&(module.exports={ico_axis_2:ico_axis_2,ico_axis_3:ico_axis_3,ico_axis_5:ico_axis_5});