Lucas Kent e39465ad2f Changes to be committed:
new file:   Files/flashplayer_32_sa.exe
	new file:   favicon.ico
	new file:   globe.gif
	new file:   imgs/download.png
	new file:   imgs/zuck.jpg
	new file:   index.html
	new file:   other.ico
	new file:   script.js
	new file:   site.webmanifest
	new file:   sitemap.html
	new file:   styles/backround.css
	new file:   styles/border.css
	new file:   styles/fonts/Titillium_Web/OFL.txt
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Black.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Bold.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-BoldItalic.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-ExtraLight.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-ExtraLightItalic.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Italic.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Light.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-LightItalic.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Regular.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-SemiBold.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-SemiBoldItalic.ttf
	new file:   styles/fonts/webfontkit-20221027-163353/generator_config.txt
	new file:   styles/fonts/webfontkit-20221027-163353/specimen_files/grid_12-825-55-15.css
	new file:   styles/fonts/webfontkit-20221027-163353/specimen_files/specimen_stylesheet.css
	new file:   styles/fonts/webfontkit-20221027-163353/stylesheet.css
	new file:   styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-demo.html
	new file:   styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-webfont.woff
	new file:   styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-webfont.woff2
	new file:   styles/fonts/webfontkit-20221027-165950/generator_config.txt
	new file:   styles/fonts/webfontkit-20221027-165950/specimen_files/grid_12-825-55-15.css
	new file:   styles/fonts/webfontkit-20221027-165950/specimen_files/specimen_stylesheet.css
	new file:   styles/fonts/webfontkit-20221027-165950/stylesheet.css
	new file:   styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-demo.html
	new file:   styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-webfont.woff
	new file:   styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-webfont.woff2
	new file:   styles/style.css
	new file:   tools/2048/.gitignore
	new file:   tools/2048/.jshintrc
	new file:   tools/2048/CONTRIBUTING.md
	new file:   tools/2048/LICENSE.txt
	new file:   tools/2048/README.md
	new file:   tools/2048/Rakefile
	new file:   tools/2048/favicon.ico
	new file:   tools/2048/index.html
	new file:   tools/2048/js/animframe_polyfill.js
	new file:   tools/2048/js/application.js
	new file:   tools/2048/js/bind_polyfill.js
	new file:   tools/2048/js/classlist_polyfill.js
	new file:   tools/2048/js/game_manager.js
	new file:   tools/2048/js/grid.js
	new file:   tools/2048/js/html_actuator.js
	new file:   tools/2048/js/keyboard_input_manager.js
	new file:   tools/2048/js/local_storage_manager.js
	new file:   tools/2048/js/tile.js
    new file:   tools/2048/meta/apple-touch-icon.png
	new file:   tools/webretro/cores/neocd_libretro.js
	new file:   tools/webretro/cores/neocd_libretro.wasm
	new file:   tools/webretro/cores/nestopia_libretro.js
	new file:   tools/webretro/cores/nestopia_libretro.wasm
	new file:   tools/webretro/cores/o2em_libretro.js
	new file:   tools/webretro/cores/o2em_libretro.wasm
	new file:   tools/webretro/cores/opera_libretro.js
	new file:   tools/webretro/cores/opera_libretro.wasm
2022-11-02 08:40:01 -04:00

646 lines
23 KiB
JavaScript

let my={}
function init(){let version='0.94'
my.drag={n:0,onQ:false,holdX:0,holdY:0}
my.mode=getJSQueryVar('mode','pent-pyramid')
this.curvyQ=['cone','cylinder','sphere','hemisphere'].indexOf(my.mode)>=0
this.flatyQ=['plane','coplanar'].indexOf(my.mode)>=0
my.pointsQ=false
my.wd=450
my.ht=450
let s=''
s+='<canvas id="canvasId" style="z-index:1;"></canvas>'
s+='<button id="dragBtn" onclick="toggleDrag()" style="z-index:2; position: absolute; top: 3px; left: 3px;" class="btn lo" >Spin</button>'
if(this.curvyQ||this.flatyQ){}else{s+='<button id="explodeBtn" onclick="toggleExplode()" style="z-index:2; position: absolute; top: 3px; left: 70px;" class="btn lo" >Explode</button>'
s+='<div style="position: absolute; top: 3px; right: 5px; font: 18px Arial;">'
s+='Coloring: '
s+=getDropdownHTML(['Multi','Shaded','Two','Glass','PureGlass','Beams'],'clrChg','clrType')
s+='</div>'}
if(my.mode=='coplanar'){my.pointsQ=true
my.mode='3 points'
s+='<div style="position: absolute; top: 3px; right: 5px; font: 18px Arial;">'
s+='Type: '
s+=getDropdownHTML(['3 points','4 coplanar points','4 points','6 coplanar points','6 points'],'coplanarChg','coplanarType')
s+='</div>'}
s+=wrap({cls:'copyrt',pos:'abs',style:'left:5px; bottom:3px'},`&copy; 2022 Rod Pierce v${version}`)
s=wrap({cls:'js',style:'width:'+my.wd+'px; height:'+my.ht+'px;'},s)
docInsert(s)
my.can=new Can('canvasId',my.wd,my.ht,2)
this.transMat=[[1,0,0],[0,1,0],[0,0,1],[0,0,0],]
this.f=500
this.shapes=[]
this.clrs=['#ff0000','#0000ff','#ff9900','#00ff00','#ffff00','#660066','#99ff00','#0099ff','#00ff99','#9900ff','#ff0099','#006666','#666600','#990000','#009999','#999900','#003399','#ff00ff','#993333','#330099']
this.explodeQ=false
my.dragModeQ=false
my.drag.onQ=false
my.drag.holdX=0
my.drag.holdY=0
this.poly=new Poly()
xAngle=2
yAngle=4
zAngle=0
let el=my.can.el
el.addEventListener('touchstart',ontouchstart,false)
el.addEventListener('touchmove',ontouchmove,false)
el.addEventListener('mousedown',onmouseDown,false)
el.addEventListener('mousemove',onmouseMove,false)
el.addEventListener('mouseup',onmouseUp,false)
stt()}
function ontouchstart(ev){my.drag.onQ=true
let touch=ev.targetTouches[0]
let[mouseX,mouseY]=my.can.mousePos(ev)
my.drag.holdX=mouseX
my.drag.holdY=mouseY}
function ontouchmove(ev){let touch=ev.targetTouches[0]
ev.clientX=touch.clientX
ev.clientY=touch.clientY
ev.touchQ=true
onmouseMove(ev)
ev.preventDefault()}
function onmouseDown(ev){my.drag.onQ=true
let[mouseX,mouseY]=my.can.mousePos(ev)
my.drag.holdX=mouseX
my.drag.holdY=mouseY}
function onmouseUp(ev){my.drag.onQ=false}
function onmouseMove(ev){let[mouseX,mouseY]=my.can.mousePos(ev)
if(my.dragModeQ){if(my.drag.onQ){settransMat(-(my.drag.holdY-mouseY)*3,(my.drag.holdX-mouseX)*3,0,transMat)
my.drag.holdX=mouseX
my.drag.holdY=mouseY
update()}}else{yAngle=-(mouseX-my.wd/2)/25
xAngle=(mouseY-my.ht/2)/25}}
function toggleDrag(){my.dragModeQ=!my.dragModeQ
toggleBtn('dragBtn',my.dragModeQ)
if(my.dragModeQ){document.getElementById('dragBtn').innerHTML='Drag'}else{document.getElementById('dragBtn').innerHTML='Spin'}}
function toggleExplode(){this.explodeQ=!this.explodeQ
toggleBtn('explodeBtn',this.explodeQ)
restart()}
function toggleBtn(btn,onq){if(onq){document.getElementById(btn).classList.add('hi')
document.getElementById(btn).classList.remove('lo')}else{document.getElementById(btn).classList.add('lo')
document.getElementById(btn).classList.remove('hi')}}
function getDropdownHTML(opts,funcName,id){let s=''
s+='<select id="'+id+'" style="font: 18px Arial; color: #6600cc; background: rgba(200,220,256,0.7); padding: 1px;" autocomplete="off" onchange="'+funcName+'()">'
for(let i=0;i<opts.length;i++){let idStr=id+i
let chkStr=i==99?'checked':''
s+='<option id="'+idStr+'" value="'+opts[i]+'" style="height:18px;" '+chkStr+' >'+opts[i]+'</option>'}
s+='</select>'
return s}
function clrChg(){let el=document.getElementById('clrType')
if(el.selectedIndex==-1)return null
let t=el.options[el.selectedIndex].text
setClrs(t)
update()}
function coplanarChg(){let el=document.getElementById('coplanarType')
if(el.selectedIndex==-1)return null
let t=el.options[el.selectedIndex].text
my.mode=t
restart()}
function getClrType(){if(this.curvyQ||this.flatyQ){if(my.mode=='plane'){return 'Glass'}else{return 'Shaded'}}else{let div=document.getElementById('clrType')
if(div.selectedIndex==-1)return 'Multi'
return div.options[div.selectedIndex].text}}
function stt(){shapes=[]
poly.shapeType=my.mode
setShapesFromPoly()
settransMat(200,50,0,transMat)
my.can.clear()
drawShapes()
this.frameNo=0
animate()}
function restart(){shapes=[]
poly.shapeType=my.mode
setShapesFromPoly()
update()}
function animate(){this.frameNo++
if(my.dragModeQ){}else{settransMat(xAngle,yAngle,zAngle,transMat)
update()}
if(this.frameNo<1e8){requestAnimationFrame(animate)}}
function update(){my.can.clear()
drawShapes()}
function drawShapes(){let prevDepth=0
let sortNeededQ=false
for(let i=0,len=shapes.length;i<len;i++){let shape=shapes[i]
shape.drawsurface(false,'N')
if(i>0){if(shape.depth<prevDepth){sortNeededQ=true}}
prevDepth=shape.depth}
if(sortNeededQ){shapes.sort(compareDepth)}}
function compareDepth(a,b){if(a.depth<b.depth)return-1
return 1}
function setShapesFromPoly(){let C=poly.getSolid()
let i=0
while(i<C.length){let surf=C[i]
addShape3D('surface',coords2Lines(surf,poly.scale),1,'#ffffff','rgba(0,0,255,0.3)')
i++}
setClrs(getClrType())}
function coords2Lines(surf,Scale){let P=[]
let midPt=[0,0,0]
for(let i=0;i<surf.length;i++){if(i<surf.length-1){let tonum=i+1}else{tonum=0}
P[i]=[]
if(surf[i]==undefined){console.log('Error surface ='+i,surf[i])}else{for(let j=0;j<3;j++){P[i][j]=surf[i][j]*Scale
if(explodeQ)midPt[j]+=P[i][j]}}}
if(explodeQ){for(let j=0;j<3;j++){midPt[j]/=surf.length}
for(let i=0;i<surf.length;i++){for(let j=0;j<3;j++){P[i][j]+=midPt[j]/2}}}
return P}
function addShape3D(shapeType,pointarray,lineweight,lineClr,fillClr){let shape=new Shape3D()
shape.transMat=transMat
shape.f=this.f
shape.setPts(pointarray)
shape.shapeType=shapeType
shape.lineweight=lineweight
shape.lineClr=lineClr
shape.fillClr=fillClr
shapes.push(shape)}
function settransMat(x,y,z,M){let vectorLength=Math.sqrt(x*x+y*y+z*z)
if(vectorLength>0.0001){x/=vectorLength
y/=vectorLength
z/=vectorLength
let Theta=vectorLength/500
let cosT=Math.cos(Theta)
let sinT=Math.sin(Theta)
let tanT=1-cosT
let T=[[],[],[]]
T[0][0]=tanT*x*x+cosT
T[0][1]=tanT*x*y-sinT*z
T[0][2]=tanT*x*z+sinT*y
T[1][0]=tanT*x*y+sinT*z
T[1][1]=tanT*y*y+cosT
T[1][2]=tanT*y*z-sinT*x
T[2][0]=tanT*x*z-sinT*y
T[2][1]=tanT*y*z+sinT*x
T[2][2]=tanT*z*z+cosT
transMat=matMatMult(T,M)}}
function matMatMult(A,B){let C=[[],[],[]]
C[0][0]=A[0][0]*B[0][0]+A[0][1]*B[1][0]+A[0][2]*B[2][0]
C[0][1]=A[0][0]*B[0][1]+A[0][1]*B[1][1]+A[0][2]*B[2][1]
C[0][2]=A[0][0]*B[0][2]+A[0][1]*B[1][2]+A[0][2]*B[2][2]
C[1][0]=A[1][0]*B[0][0]+A[1][1]*B[1][0]+A[1][2]*B[2][0]
C[1][1]=A[1][0]*B[0][1]+A[1][1]*B[1][1]+A[1][2]*B[2][1]
C[1][2]=A[1][0]*B[0][2]+A[1][1]*B[1][2]+A[1][2]*B[2][2]
C[2][0]=A[2][0]*B[0][0]+A[2][1]*B[1][0]+A[2][2]*B[2][0]
C[2][1]=A[2][0]*B[0][1]+A[2][1]*B[1][1]+A[2][2]*B[2][1]
C[2][2]=A[2][0]*B[0][2]+A[2][1]*B[1][2]+A[2][2]*B[2][2]
return C}
function setClrs(clrMethod){for(let i=0;i<shapes.length;i++){let shape=shapes[i]
shape.clrMethod=clrMethod
switch(clrMethod){case 'Multi':shape.fillClr=convertHexClr(clrs[i%clrs.length],0.7)
break
case 'Two':shape.fillClr=convertHexClr(clrs[i%2],0.8)
break
case 'Smooth':let FromMiddle=parseInt(Math.abs(shapes.length/2-i))
let blu=FromMiddle*8+1
let ccc=rgb2hex([blu,128,blu])
shape.fillClr=ccc
break
case 'Glass':case 'PureGlass':shape.doShading()
break
case 'Shaded':shape.doShading()
break
default:}}}
class Poly{constructor(){this.shapeType='cube'
this.shapeSource='calc'
this.scale=90}
getSolid(){let C=[]
switch(this.shapeSource){case 'file':case 'data':C=[]
for(let i=0;i<solidFaces.length;i++){let faceVerts=[]
for(let j=0;j<solidFaces[i].length;j++){faceVerts.push(vertices[solidFaces[i][j]])}
C.push(faceVerts)}
clrMethod='Glass'
break
case 'calc':C=this.getCalcSolid()
break
default:}
return C}
getCalcSolid(){let C=[]
this.scale=90
let i
let j
let a,b,c,d
let phi
let clrMethod='Glass'
switch(this.shapeType.toLowerCase()){case 'net':C=[[[0,0,0],[0,1,0],[1,1,0],[1,0,0],],[[1,0,0],[2,0,0],[2,1,0],[1,1,0],],[[2,0,0],[3,0,0],[3,1,0],[2,1,0],],]
clrMethod='Glass'
this.scale=100
break
case 'sphere':C=this.createNSphere(3)
clrMethod='Alternating'
this.scale=110
break
case 'hemisphere':C=CreateNSphere(3,true)
clrMethod='Shaded'
this.scale=110
break
case 'cone':C=this.createNCone(60,1.3)
this.scale=140
clrMethod='Smooth'
break
case 'cylinder':C=this.createNCylinder(60)
clrMethod='Smooth'
this.scale=110
break
case 'square-pyramid':C=this.createNCone(4,0.5)
this.scale=180
break
case 'pent-pyramid':C=this.createNCone(5,0.7)
this.scale=180
break
case 'tetrahedron':C=[[[1,1,1],[-1,1,-1],[1,-1,-1],],[[-1,1,-1],[-1,-1,1],[1,-1,-1],],[[1,1,1],[1,-1,-1],[-1,-1,1],],[[1,1,1],[-1,-1,1],[-1,1,-1],],]
break
case 'irr-tetrahedron':C=[[[2,1,-0.2],[-1,1,-1],[1,-1,-1],],[[-1,1,-1],[-1,-1,1],[1,-1,-1],],[[2,1,-0.2],[1,-1,-1],[-1,-1,1],],[[2,1,-0.2],[-1,-1,1],[-1,1,-1],],]
this.scale=80
break
case 'cube':C=[[[-1,-1,-1],[1,-1,-1],[1,-1,1],[-1,-1,1],],[[-1,-1,-1],[-1,-1,1],[-1,1,1],[-1,1,-1],],[[-1,-1,1],[1,-1,1],[1,1,1],[-1,1,1],],[[-1,1,-1],[-1,1,1],[1,1,1],[1,1,-1],],[[1,-1,-1],[1,1,-1],[1,1,1],[1,-1,1],],[[-1,-1,-1],[-1,1,-1],[1,1,-1],[1,-1,-1],],]
break
case '3 points':C=[[[-1,-1,-1],[1,-1,-1],[1,-1,1],],]
this.scale=80
break
case '4 coplanar points':C=[[[-1.5,-1,-1],[1,-1,-1],[0.3,-1,1],[-1.5,-1,1],],]
this.scale=80
break
case '4 points':C=[[[-1.1,-2,-2],[1,-1,-1],[0.8,2,1],],[[1,-1,-1],[0.8,2,1],[1.5,-1,1],],]
this.scale=60
break
case '6 points':C=[[[-1.1,-2,-2]],[[1,-0.5,-1]],[[0.7,2,1]],[[1.6,-1,-1.3]],[[0.5,1.4,1.2]],[[-1.5,-1.4,1.3]]]
this.scale=60
break
case '6 coplanar points':C=[[[-1.1,-1,0.3]],[[0.2,-1,-0.3]],[[-1.5,-1,-1],[1,-1,-1],[0.3,-1,1],[-1.5,-1,1],],]
this.scale=60
break
case 'plane':a=0.5
b=0.5
c=0.5
d=-3
C=[]
for(i=0;i<6;i++){for(j=0;j<6;j++){C.push([[a,-b+d+i,-c+d+j],[a,b+d+i,-c+d+j],[a,b+d+i,c+d+j],[a,-b+d+i,c+d+j],])}}
this.scale=80
break
case 'cuboid':case 'rect-prism':a=1.2
b=0.7
c=0.7
C=[[[-a,-b,-c],[a,-b,-c],[a,-b,c],[-a,-b,c],],[[-a,-b,-c],[-a,-b,c],[-a,b,c],[-a,b,-c],],[[-a,-b,c],[a,-b,c],[a,b,c],[-a,b,c],],[[-a,b,-c],[-a,b,c],[a,b,c],[a,b,-c],],[[a,-b,-c],[a,b,-c],[a,b,c],[a,-b,c],],[[-a,-b,-c],[-a,b,-c],[a,b,-c],[a,-b,-c],],]
break
case 'pent-prism':a=1.2
b=0.7
c=0.73
d=0.16
let e=0.44
C=[[[-a,0,b],[-a,c,d],[-a,e,-b],[-a,-e,-b],[-a,-c,d],],[[a,0,b],[a,c,d],[a,e,-b],[a,-e,-b],[a,-c,d],],[[-a,0,b],[-a,c,d],[a,c,d],[a,0,b],],[[-a,c,d],[-a,e,-b],[a,e,-b],[a,c,d],],[[-a,e,-b],[-a,-e,-b],[a,-e,-b],[a,e,-b],],[[-a,-e,-b],[-a,-c,d],[a,-c,d],[a,-e,-b],],[[-a,-c,d],[-a,0,b],[a,0,b],[a,-c,d],],]
break
case 'oct-prism':a=1.1
b=0.33
c=0.79
C=[[[-a,b,c],[-a,c,b],[-a,c,-b],[-a,b,-c],[-a,-b,-c],[-a,-c,-b],[-a,-c,b],[-a,-b,c],],[[a,b,c],[a,c,b],[a,c,-b],[a,b,-c],[a,-b,-c],[a,-c,-b],[a,-c,b],[a,-b,c],],]
for(i=0;i<8;i++){j=Maths.loop(i,0,7,1)
C.push([[C[0][i][0],C[0][i][1],C[0][i][2]],[C[0][j][0],C[0][j][1],C[0][j][2]],[C[1][j][0],C[1][j][1],C[1][j][2]],[C[1][i][0],C[1][i][1],C[1][i][2]],])}
break
case 'irr-pent-prism':a=1.2
b=0.7
c=0.73
d=0.16
e=0.9
C=[[[-a,0,b],[-a,c,d],[-a,e,-b],[-a,-e,-b],[-a,-c,d],],[[a,0,b],[a,c,d],[a,e,-b],[a,-e,-b],[a,-c,d],],[[-a,0,b],[-a,c,d],[a,c,d],[a,0,b],],[[-a,c,d],[-a,e,-b],[a,e,-b],[a,c,d],],[[-a,e,-b],[-a,-e,-b],[a,-e,-b],[a,e,-b],],[[-a,-e,-b],[-a,-c,d],[a,-c,d],[a,-e,-b],],[[-a,-c,d],[-a,0,b],[a,0,b],[a,-c,d],],]
break
case 'tri-prism-n':C=CreateNCylinder(3)
this.scale=100
break
case 'tri-prism':a=1.2
b=0.7
c=0.7
d=0.6
C=[[[-a,-b,-c],[-a,-b,c],[-a,d,0],],[[a,-b,-c],[a,-b,c],[a,d,0],],[[-a,-b,-c],[a,-b,-c],[a,-b,c],[-a,-b,c],],[[-a,-b,c],[a,-b,c],[a,d,0],[-a,d,0],],[[-a,-b,-c],[-a,d,0],[a,d,0],[a,-b,-c],],]
break
case 'strange-prism':a=1.2
b=0.7
c=0.7
C=[[[-a,-b,-c],[a,-b,-c],[a,-b,c],],[[-a,-b,-c],[-a,-b,c],[-a,b,c],],[[-a,-b,c],[a,-b,c],[a,b,c],],[[-a,b,-c],[-a,b,c],[a,b,c],],[[a,-b,-c],[a,b,-c],[a,b,c],],[[-a,-b,-c],[-a,b,-c],[a,b,-c],],]
break
case 'octahedron':a=3/(2*Math.sqrt(2))
b=3/2
C=[[[-a,0,a],[-a,0,-a],[0,b,0],],[[-a,0,-a],[a,0,-a],[0,b,0],],[[a,0,-a],[a,0,a],[0,b,0],],[[a,0,a],[-a,0,a],[0,b,0],],[[a,0,-a],[-a,0,-a],[0,-b,0],],[[-a,0,-a],[-a,0,a],[0,-b,0],],[[a,0,a],[a,0,-a],[0,-b,0],],[[-a,0,a],[a,0,a],[0,-b,0],],]
break
case 'dodecahedron':phi=(1+Math.sqrt(5))/2
a=1
b=1/phi
c=2-phi
a*=1.5
b*=1.5
c*=1.5
C=[[[c,0,a],[-c,0,a],[-b,b,b],[0,a,c],[b,b,b],],[[-c,0,a],[c,0,a],[b,-b,b],[0,-a,c],[-b,-b,b],],[[c,0,-a],[-c,0,-a],[-b,-b,-b],[0,-a,-c],[b,-b,-b],],[[-c,0,-a],[c,0,-a],[b,b,-b],[0,a,-c],[-b,b,-b],],[[0,a,-c],[0,a,c],[b,b,b],[a,c,0],[b,b,-b],],[[0,a,c],[0,a,-c],[-b,b,-b],[-a,c,0],[-b,b,b],],[[0,-a,-c],[0,-a,c],[-b,-b,b],[-a,-c,0],[-b,-b,-b],],[[0,-a,c],[0,-a,-c],[b,-b,-b],[a,-c,0],[b,-b,b],],[[a,c,0],[a,-c,0],[b,-b,b],[c,0,a],[b,b,b],],[[a,-c,0],[a,c,0],[b,b,-b],[c,0,-a],[b,-b,-b],],[[-a,c,0],[-a,-c,0],[-b,-b,-b],[-c,0,-a],[-b,b,-b],],[[-a,-c,0],[-a,c,0],[-b,b,b],[-c,0,a],[-b,-b,b],],]
break
case 'icosahedron-intersected':phi=(1+Math.sqrt(5))/2
a=1
b=1/phi
c=2-phi
a*=1.5
b*=1.5
c*=1.5
C=[[[0,b,-a],[b,a,0],[-b,a,0],],[[0,0,0],[-b,a,0],[b,a,0],],[[0,0,0],[0,-b,a],[-a,0,b],],[[0,0,0],[a,0,b],[0,-b,a],],[[0,b,-a],[0,0,0],[a,0,-b],],[[0,b,-a],[-a,0,-b],[0,0,0],],[[0,-b,a],[b,-a,0],[-b,-a,0],],[[0,0,0],[-b,-a,0],[b,-a,0],],[[-b,a,0],[-a,0,b],[-a,0,-b],],[[-b,-a,0],[-a,0,-b],[-a,0,b],],[[b,a,0],[a,0,-b],[a,0,b],],[[b,-a,0],[a,0,b],[a,0,-b],],[[0,0,0],[-a,0,b],[-b,a,0],],[[0,0,0],[b,a,0],[a,0,b],],[[0,b,-a],[-b,a,0],[-a,0,-b],],[[0,b,-a],[a,0,-b],[b,a,0],],[[0,0,0],[-a,0,-b],[-b,-a,0],],[[0,0,0],[b,-a,0],[a,0,-b],],[[0,-b,a],[-b,-a,0],[-a,0,b],],[[0,-b,a],[a,0,b],[b,-a,0],],]
break
case 'icosahedron':phi=(1+Math.sqrt(5))/2
a=1/2
b=1/(2*phi)
a*=3
b*=3
C=[[[0,b,-a],[b,a,0],[-b,a,0],],[[0,b,a],[-b,a,0],[b,a,0],],[[0,b,a],[0,-b,a],[-a,0,b],],[[0,b,a],[a,0,b],[0,-b,a],],[[0,b,-a],[0,-b,-a],[a,0,-b],],[[0,b,-a],[-a,0,-b],[0,-b,-a],],[[0,-b,a],[b,-a,0],[-b,-a,0],],[[0,-b,-a],[-b,-a,0],[b,-a,0],],[[-b,a,0],[-a,0,b],[-a,0,-b],],[[-b,-a,0],[-a,0,-b],[-a,0,b],],[[b,a,0],[a,0,-b],[a,0,b],],[[b,-a,0],[a,0,b],[a,0,-b],],[[0,b,a],[-a,0,b],[-b,a,0],],[[0,b,a],[b,a,0],[a,0,b],],[[0,b,-a],[-b,a,0],[-a,0,-b],],[[0,b,-a],[a,0,-b],[b,a,0],],[[0,-b,-a],[-a,0,-b],[-b,-a,0],],[[0,-b,-a],[b,-a,0],[a,0,-b],],[[0,-b,a],[-b,-a,0],[-a,0,b],],[[0,-b,a],[a,0,b],[b,-a,0],],]
this.scale=80
break
default:}
return C}
createNCone(ngon,ht){let D=[]
D[0]=[]
let sumx=0
let sumy=0
for(let i=0;i<ngon;i++){let Angle=(Math.PI*2*i)/ngon
D[0][i]=[]
D[0][i][0]=Math.sin(Angle)*0.8
D[0][i][1]=Math.cos(Angle)*0.8
D[0][i][2]=-ht/2
sumx=sumx+D[0][i][0]
sumy=sumy+D[0][i][1]}
let apexx=sumx/ngon
let apexy=sumy/ngon
for(let i=0;i<ngon;i++){let n=i+1
D[n]=[]
D[n][0]=[]
D[n][0][0]=apexx
D[n][0][1]=apexy
D[n][0][2]=ht
D[n][1]=[]
D[n][1][0]=D[0][i][0]
D[n][1][1]=D[0][i][1]
D[n][1][2]=D[0][i][2]
let i1=i+1
if(i1==ngon)i1=0
D[n][2]=[]
D[n][2][0]=D[0][i1][0]
D[n][2][1]=D[0][i1][1]
D[n][2][2]=D[0][i1][2]}
return D}
createNCylinder(ngon){let D=[]
D[0]=[]
for(let i=0;i<ngon;i++){let ang=(Math.PI*2*i)/ngon
D[0][i]=[]
D[0][i][0]=Math.sin(ang)*0.8
D[0][i][1]=Math.cos(ang)*0.8
D[0][i][2]=1.4}
D[1]=[]
for(let i=0;i<ngon;i++){let ang=(Math.PI*2*i)/ngon
D[1][i]=[]
D[1][i][0]=Math.sin(ang)*0.8
D[1][i][1]=Math.cos(ang)*0.8
D[1][i][2]=-1.1}
for(let i=0;i<ngon;i++){let n=i+2
D[n]=[]
let i1=i+1
if(i1==ngon)i1=0
D[n][0]=[]
D[n][0][0]=D[0][i][0]
D[n][0][1]=D[0][i][1]
D[n][0][2]=D[0][i][2]
D[n][1]=[]
D[n][1][0]=D[0][i1][0]
D[n][1][1]=D[0][i1][1]
D[n][1][2]=D[0][i1][2]
D[n][2]=[]
D[n][2][0]=D[1][i1][0]
D[n][2][1]=D[1][i1][1]
D[n][2][2]=D[1][i1][2]
D[n][3]=[]
D[n][3][0]=D[1][i][0]
D[n][3][1]=D[1][i][1]
D[n][3][2]=D[1][i][2]}
return D}
sphereNormalise(p){let vectorLength=Math.sqrt(p[0]*p[0]+p[1]*p[1]+p[2]*p[2])
if(vectorLength!=0){p[0]/=vectorLength
p[1]/=vectorLength
p[2]/=vectorLength}else{p[0]=0
p[1]=0
p[2]=0}}}
function Shape3D(){let rotSelfMatrix=[[1,0,0],[0,1,0],[0,0,1],[0,0,0],]
let rotSelfQ=false
this.velQ=false
this.lt=my.wd/2
this.tp=my.ht/2
this.eye=new Pt3d()
this.eye.setMe(0,0,400)
this.pts=[]
this.lineweight
this.lineClr='white'
this.fillClr='rgba(255,0,0,0.9)'
this.shapeType='surf'
this.clrMethod='None'
this.depth=0
this.showPtsQ=false
this.centroid=new Pt3d()
this.vel3d=new Pt3d()
this.hideCount=0}
Shape3D.prototype.setPts=function(apts){this.pts=[]
for(let i=0;i<apts.length;i++){let p3d=new Pt3d()
p3d.setMe(apts[i][0],apts[i][1],apts[i][2])
this.pts.push(p3d)}
this.calcCentroid()}
Shape3D.prototype.doShading=function(){let alpha=0.8
switch(this.clrMethod){case 'Glass':case 'PureGlass':alpha=0.5
break
default:}
let angle=this.getNormalAngle(this.pts,0)
let dark=1-angle/Math.PI
let red=((dark*255)>>0)+1
let grn=((dark*255)>>0)+1
angle=this.getNormalAngle(this.pts,1)
dark=1-angle/Math.PI
let blu=((dark*255)>>0)+1
this.fillClr='rgba('+red+','+grn+','+blu+','+alpha+')'}
Shape3D.prototype.getNormalAngle=function(pts,dimN){if(pts.length<3)return 0
let a=[pts[1].x-pts[0].x,pts[1].y-pts[0].y,pts[1].z-pts[0].z]
let b=[pts[2].x-pts[1].x,pts[2].y-pts[1].y,pts[2].z-pts[1].z]
let cross=[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]
let mag=Math.sqrt(cross[0]*cross[0]+cross[1]*cross[1]+cross[2]*cross[2])
let theta=Math.acos(cross[dimN]/mag)
return theta}
Shape3D.prototype.calcCentroid=function(){centroid=new Pt3d()
for(let i=0;i<this.pts.length;i++){centroid.addPtMe(this.pts[i])}
if(this.pts.length>0){centroid.x/=this.pts.length
centroid.y/=this.pts.length
centroid.z/=this.pts.length}}
Shape3D.prototype.drawsurface=function(aboutEyeQ,viewType){let g=my.can.g
g.lineJoin='round'
let xsum=0
let ysum=0
let zsum=0
let clips=[]
let zMin=Number.MAX_VALUE
let zMax=-Number.MAX_VALUE
let i=0
let ptRot
while(i<this.pts.length){let pt3d=this.pts[i]
if(this.aboutEyeQ){}else{ptRot=this.matPtMult(transMat,pt3d)
clips.push(ptRot)}
zMin=Math.min(zMin,ptRot.z)
zMax=Math.max(zMax,ptRot.z)
xsum+=ptRot.x
ysum+=ptRot.y
zsum+=ptRot.z
i++}
let pt2s=[]
i=0
while(i<clips.length){let p3d=clips[i]
let pt=new Pt()
pt.x=this.lt+(this.eye.z*p3d.x)/(this.eye.z+p3d.z)
pt.y=this.tp+(this.eye.z*p3d.y)/(this.eye.z+p3d.z)
pt2s.push(pt)
i++}
let fillQ=true
let strokeQ=true
switch(this.clrMethod){case 'Glass':g.lineWidth=1
g.strokeStyle='#000000'
g.fillStyle=this.fillClr
break
case 'PureGlass':g.lineWidth=3
g.strokeStyle='#ffffff'
g.fillStyle=this.fillClr
break
case 'Beams':g.lineWidth=18
g.strokeStyle='#444444'
g.fillStyle='rgba(250,250,250,0.2)'
g.lineJoin='round'
break
case 'Shaded':g.fillStyle=this.fillClr
strokeQ=false
break
default:g.lineWidth=1
g.strokeStyle=this.lineClr
g.fillStyle=this.fillClr}
if(pt2s.length>2){g.beginPath()
for(i=0,len=pt2s.length;i<len;i++){pt=pt2s[i]
if(i==0){g.moveTo(pt.x,pt.y)}else{g.lineTo(pt.x,pt.y)}}
g.closePath()
if(strokeQ)g.stroke()
if(fillQ)g.fill()}
if(my.pointsQ){for(i=0,len=pt2s.length;i<len;i++){pt=pt2s[i]
g.beginPath()
g.fillStyle='rgba(0,0,255,0.3)'
g.arc(pt.x,pt.y,4,0,2*Math.PI)
g.closePath()
g.stroke()
g.fill()}}
let iRecip=1/(pt2s.length+1)
xsum*=iRecip
ysum*=iRecip
zsum=f-zsum*iRecip
this.depth=(xsum*xsum+ysum*ysum+zsum*zsum)/10000}
Shape3D.prototype.matPtMult=function(A,B){let C=new Pt3d()
C.x=A[0][0]*B.x+A[0][1]*B.y+A[0][2]*B.z
C.y=A[1][0]*B.x+A[1][1]*B.y+A[1][2]*B.z
C.z=A[2][0]*B.x+A[2][1]*B.y+A[2][2]*B.z
return C}
function Pt(){this.x=0
this.y=0}
function Pt3d(){this.x=0
this.y=0
this.z=0}
Pt3d.prototype.setMe=function(x,y,z){this.x=x
this.y=y
this.z=z}
Pt3d.prototype.addPtMe=function(pt3d,factor){factor=typeof factor!=='undefined'?factor:1
if(factor==1){this.x+=pt3d.x
this.y+=pt3d.y
this.z+=pt3d.z}else{this.x+=pt3d.x*factor
this.y+=pt3d.y*factor
this.z+=pt3d.z*factor}}
function convertHexClr(hex,opacity){hex=hex.replace('#','')
let r=parseInt(hex.substring(0,2),16)
let g=parseInt(hex.substring(2,4),16)
let b=parseInt(hex.substring(4,6),16)
return 'rgba('+r+','+g+','+b+','+opacity+')'}
function rgb2hex(color){let hex=[]
for(let i=0;i<3;i++){hex.push(color[i].toString(16))
if(hex[i].length<2){hex[i]='0'+hex[i]}}
return '#'+hex[0]+hex[1]+hex[2]}
function docInsert(s){let div=document.createElement('div')
div.innerHTML=s
let script=document.currentScript
script.parentElement.insertBefore(div,script)}
function getJSQueryVar(varName,defaultVal){let scripts=document.getElementsByTagName('script')
let lastScript=scripts[scripts.length-1]
let scriptName=lastScript.src
let bits=scriptName.split('?')
if(bits.length<2)return defaultVal
let query=bits[1]
console.log('query: ',query)
let vars=query.split('&')
for(let i=0;i<vars.length;i++){let pair=vars[i].split('=')
if(pair[0]==varName){return pair[1]}}
return defaultVal}
class Can{constructor(id,wd,ht,ratio){this.id=id
this.ratio=ratio
this.el=document.getElementById(id)
this.g=this.el.getContext('2d')
this.resize(wd,ht)
return this}
resize(wd,ht){this.wd=wd
this.ht=ht
this.el.width=wd*this.ratio
this.el.style.width=wd+'px'
this.el.height=ht*this.ratio
this.el.style.height=ht+'px'
this.g.setTransform(this.ratio,0,0,this.ratio,0,0)}
clear(){this.g.clearRect(0,0,this.wd,this.ht)}
mousePos(ev){let bRect=this.el.getBoundingClientRect()
let mouseX=(ev.clientX-bRect.left)*(this.el.width/this.ratio/bRect.width)
let mouseY=(ev.clientY-bRect.top)*(this.el.height/this.ratio/bRect.height)
return[mouseX,mouseY]}}
function wrap({id='',cls='',pos='rel',style='',txt='',tag='div',lbl='',fn='',opts=[]},...mores){let s=''
s+='\n'
txt+=mores.join('')
s+={btn:()=>{if(cls.length==0)cls='btn'
return '<button onclick="'+fn+'"'},can:()=>'<canvas',div:()=>{let s='<div'
s+=fn.length>0?' onclick="'+fn+'" ':''
style+=fn.length>0?' cursor:pointer;':''
return s},edit:()=>{let s=''
s+=lbl.length>0?'<label class="label">'+lbl+' ':''
s+='<textarea onkeyup="'+fn+'" onchange="'+fn+'"'
return s},inp:()=>{if(cls.length==0)cls='input'
let s=''
s+=lbl.length>0?'<label class="label">'+lbl+' ':''
s+='<input value="'+txt+'"'
s+=fn.length>0?' oninput="'+fn+'" onchange="'+fn+'"':''
return s},out:()=>{pos='dib'
if(cls.length==0)cls='output'
let s=''
s+=lbl.length>0?'<label class="label">'+lbl+' ':''
s+='<span '
return s},radio:()=>{if(cls.length==0)cls='radio'
return '<div '},sel:()=>{if(cls.length==0)cls='select'
let s=''
s+=lbl.length>0?'<label class="label">'+lbl+' ':''
s+='<select '
s+=fn.length>0?' onchange="'+fn+'"':''
return s},sld:()=>{s+=lbl.length>0?'<label class="label">'+lbl+' ':''
s+='<input type="range" '+txt+' oninput="'+fn+'" onchange="'+fn+'"'
return s},}[tag]()||''
if(id.length>0)s+=' id="'+id+'"'
if(cls.length>0)s+=' class="'+cls+'"'
if(pos=='dib')s+=' style="position:relative; display:inline-block;'+style+'"'
if(pos=='rel')s+=' style="position:relative; '+style+'"'
if(pos=='abs')s+=' style="position:absolute; '+style+'"'
s+={btn:()=>'>'+txt+'</button>',can:()=>'></canvas>',div:()=>' >'+txt+'</div>',edit:()=>' >'+txt+'</textarea>',inp:()=>'>'+(lbl.length>0?'</label>':''),out:()=>' >'+txt+'</span>'+(lbl.length>0?'</label>':''),radio:()=>{let s=''
s+='>\n'
for(let i=0;i<opts.length;i++){let chk=''
if(i==0)chk='checked'
let idi=id+i
let lbl=opts[i]
s+='<input id="'+idi+'" type="radio" name="'+id+'" value="'+lbl.name+'" onclick="'+fn+'('+i+');" '+chk+' >'
s+='<label for="'+idi+'">'+lbl.name+' </label>'}
s+='</div>'
return s},sel:()=>{let s=''
s+='>\n'
for(let i=0;i<opts.length;i++){let opt=opts[i]
let idStr=id+i
let chkStr=opt.descr==txt?' selected ':''
s+='<option id="'+idStr+'" value="'+opt.name+'"'+chkStr+'>'+opt.descr+'</option>\n'}
s+='</select>'
if(lbl.length>0)s+='</label>'
return s},sld:()=>{let s='>'
if(lbl.length>0)s+='</label>'
if(lbl.length>0)s+='<span id="'+id+'0">0</span>'
return s},}[tag]()||''
s+='\n'
return s.trim()}
init()