var w,h,ratio,el,g,drag,dragIndex,dragging,dots,my={} function geomoblique3dMain(mode){my.version='0.622';mode=typeof mode!=='undefined'?mode:'cyl';console.log("mode",mode);w=360;h=300;my.lt=100;my.bt=h-50 my.midx=w/2 my.midy=h/2+20 my.modes=[{id:"cone",name:"Cone",fn:pseudoCone,obq:true,pts:[[w/2+80,80,"A"],[w/2+60,my.bt,"B"]]},{id:"cyl",name:"Cylinder",fn:pseudoCyl,obq:true,pts:[[w/2+50,80,"A"],[w/2+70,my.bt,"B"]]},{id:"cylh",name:"Horizontal Cylinder",fn:pseudoCylHz,obq:false,pts:[[w/2+50,80,"A"],[w/2+70,my.bt,"B"]]},{id:"pyr4",name:"Pyramid",fn:pseudoPyr,sideN:4,obq:true,pts:[[w/2+50,80,"A"],[w/2+70,my.bt-40,"B"]]},{id:"pyrn",name:"Pyramid",fn:pseudoPyrN,sideN:0,obq:true,pts:[[w/2,80,"A"],[w/2+110,my.bt-40,"B"]]},{id:"pri4",name:"Prism",fn:pseudoPrism,sideN:4,obq:true,pts:[[w/2+80,80,"A"],[w/2+70,my.bt-40,"B"]]},{id:"prin",name:"Prism",fn:pseudoPrismN,sideN:0,obq:true,pts:[[w/2,80,"A"],[w/2+70,my.bt-40,"B"]]},{id:"sphere",name:"Sphere",fn:pseudoSphere,sideN:1,obq:false,pts:[[my.midx+80,my.midy,"A"]]},] my.mode=my.modes[0];for(var i=0;i';s+='';s+='
 
';s+='
 
';if(my.mode.sideN==0){s+='
' s+='';s+='
' s+='
';s+='
Sides:
' s+='';s+='
'+my.sideN+'
';s+='
';} s+='
© 2018 MathsIsFun.com v'+my.version+'
';s+='';document.write(s);el=document.getElementById('canvasId');ratio=2;el.width=w*ratio;el.height=h*ratio;el.style.width=w+"px";el.style.height=h+"px";g=el.getContext("2d");g.setTransform(ratio,0,0,ratio,0,0);my.dotRad=10 dragging=false;drag={hold:{x:0,y:0}} my.prevTgt={typ:'',a:0,b:0};dotsMake() update() el.addEventListener("mousedown",onMouseDown,false);el.addEventListener('touchstart',onTouchStart,false);el.addEventListener("mousemove",doPointer,false);} function chgSides(v){my.sideN=v document.getElementById('sides').innerHTML=v update()} function restart(){dotsMake() update()} function update(){var dx=dots[0].x-my.midx var title=my.mode.name if(my.mode.obq){if(Math.abs(dx)<6){dx=0 title='Right '+title}else{title='Oblique '+title}} document.getElementById('title').innerHTML=title g.clearRect(0,0,el.width,el.height);my.mode.fn() dotsDraw()} function ptsDraw(pts){for(var i=0;i2 ≈ '+area s+='
' var vol=(4/3)*Math.PI*shaper*shaper*shaper vol=Math.round(vol*10)/10 s+='Volume = (4/3) × π × '+shaper+'3 ≈ '+vol document.getElementById('descr').innerHTML=s}} function pseudoCone(){var factor=4 dots[0].y=Math.min(my.bt-40,dots[0].y) dots[1].x=Math.max(my.midx,dots[1].x) dots[1].y=my.bt var r=dots[1].x-my.midx g.strokeStyle='#aaaaaa' g.beginPath();g.strokeStyle='hsla(240,100%,50%,1)';g.fillStyle='hsla(240,100%,90%,0.6)';g.lineWidth=0.5;drawEllipseRadius(g,my.midx,my.bt,r,r/factor);g.stroke();g.fill();g.beginPath();g.setLineDash([5,5]) g.moveTo(dots[0].x,dots[0].y);g.lineTo(dots[0].x,my.bt);g.stroke();g.beginPath();g.moveTo(dots[0].x-20,my.bt);g.lineTo(dots[0].x+20,my.bt);g.stroke() g.setLineDash([]) if(false){g.beginPath();g.fillStyle='red';var slantHt=Math.round(dist(dots[0].x-dots[1].x,dots[0].y-dots[1].y))/10 console.log('slantHt',slantHt) g.beginPath();g.fillText(slantHt,(dots[0].x+dots[1].x)/2,(dots[0].y+dots[1].y)/2+16) g.fill();} g.beginPath();g.moveTo(my.midx,my.bt);g.lineTo(my.midx+r,my.bt);g.stroke();g.beginPath();g.setLineDash([]) var m=((my.midx-r)-dots[0].x)/(my.bt-dots[0].y) var grd=g.createLinearGradient(dots[0].x,dots[0].y,dots[0].x+r,dots[0].y-r*m);grd.addColorStop(0,"hsla(240,100%,80%,1)");grd.addColorStop(0.5,'hsla(240,100%,80%,0.3)');grd.addColorStop(0.6,'hsla(240,100%,80%,0.2)');grd.addColorStop(1,'hsla(60,100%,80%,0.2)');g.fillStyle=grd;g.moveTo(dots[0].x,dots[0].y);var ang=Math.atan2(my.midx-dots[0].x,my.bt-dots[0].y) var fudge=ang*0.5 drawEllipseRadius(g,my.midx,my.bt,r,r/factor,-fudge,Math.PI-fudge);g.closePath() g.fill();g.stroke();if(my.volQ){g.font="14px Arial";g.fillStyle='black';var shaper=Math.round(r)/10 g.beginPath();g.fillText(shaper,my.midx+r/2,my.bt) g.fill();var shapeHt=Math.round(my.bt-dots[0].y)/10 g.beginPath();g.fillText(shapeHt,dots[0].x,dots[0].y+(my.bt-dots[0].y)/2+16) g.fill();var vol=Math.PI*shaper*shaper*shapeHt/3 vol=Math.round(vol*10)/10 var s='Volume = 1/3 × π × '+shaper+'2 × '+shapeHt+' ≈ '+vol document.getElementById('descr').innerHTML=s}} function pseudoCylHz(){var factor=4 dots[1].x=Math.max(my.midx,dots[1].x) dots[1].y=my.bt dots[0].x=dots[1].x var r=100 dots[0].y=Math.max(my.bt-2*r,Math.min(dots[0].y,my.bt)) g.beginPath();g.strokeStyle='hsla(240,100%,50%,1)';g.fillStyle='hsla(240,100%,90%,0.6)';g.lineWidth=0.5;drawEllipseRadius(g,my.midx+(my.midx-dots[1].x),my.bt-r,r/factor,r);g.stroke();g.fill();var pts=getArcPts(dots[1].x,my.bt-r,r/factor,r) console.log('pts',pts) my.walls=[] for(var i=0;i0){ang1-=Math.PI*2 console.log('ang1',ang1,ang1-Math.PI*2)} var ltPts=getArcPts(ell.x,ell.y,r/factor,r,-Math.PI/2,ang1) console.log('ltPts',ltPts,-Math.PI/2,ang1) for(var i=0;i2 × '+shapeHt+' ≈ '+vol document.getElementById('descr').innerHTML=s}} function pseudoPyrN(){console.log('pseudoPyrN') dots[1].y=my.bt dots[0].y=Math.min(my.bt-20,dots[0].y) g.strokeStyle='hsla(190,0%,20%,1)' g.lineWidth=0.5 var n=my.sideN var angStt=0.08 var smidge=2 g.fillStyle='hsla(240,100%,80%,0.6)';g.beginPath();var pts=ptsRegular(0,0,dots[1].x-my.midx,angStt,n) pts=ptsSquish(pts,1,0.25) pts=ptsTrans(pts,my.midx,my.bt-smidge) ptsDraw(pts) g.closePath() g.fill();g.stroke();var pt2s=ptsClone(pts) pt2s=ptsTrans(pt2s,dots[0].x-my.midx,dots[0].y-(my.bt-smidge)) for(var i=n-1;i>=0;i--){g.fillStyle='hsla(240,100%,80%,0.3)';if(n>2){switch(Math.round(i-n/3)){case 0:g.fillStyle='hsla(60,100%,90%,0.6)';break case-1:case 1:g.fillStyle='hsla(60,100%,80%,0.3)';break}} g.beginPath() var i0=i var i1=loop(i0,0,n-1,1) g.moveTo(pts[i0].x,pts[i0].y) g.lineTo(pts[i1].x,pts[i1].y) g.lineTo(dots[0].x,dots[0].y) g.closePath() g.fill() g.stroke();}} function pseudoPrismN(){console.log('pseudoPrismN') dots[1].y=my.bt dots[0].y=Math.min(my.bt-20,dots[0].y) g.strokeStyle='rgba(0,0,255,0.5)';var n=my.sideN var angStt=0.08 var smidge=2 g.fillStyle='hsla(240,100%,80%,0.8)';g.beginPath();var pts=ptsRegular(0,0,dots[1].x-my.midx,angStt,n) pts=ptsSquish(pts,1,0.25) pts=ptsTrans(pts,my.midx,my.bt-smidge) ptsDraw(pts) g.closePath() g.fill();g.stroke();var pt2s=ptsClone(pts) pt2s=ptsTrans(pt2s,dots[0].x-my.midx,dots[0].y-(my.bt-smidge)) for(var i=n-1;i>=0;i--){g.fillStyle='hsla(240,100%,80%,0.3)';if(n>4){switch(Math.round(i-n/3)){case 0:g.fillStyle='hsla(60,100%,90%,0.6)';break case-1:case 1:g.fillStyle='hsla(60,100%,80%,0.3)';break}} g.beginPath() var i0=i var i1=loop(i0,0,n-1,1) g.moveTo(pts[i0].x,pts[i0].y) g.lineTo(pts[i1].x,pts[i1].y) g.lineTo(pt2s[i1].x,pt2s[i1].y) g.lineTo(pt2s[i0].x,pt2s[i0].y) g.closePath() g.fill() g.stroke();} g.fillStyle='hsla(60,100%,80%,0.6)';g.beginPath();ptsDraw(pt2s) g.closePath() g.fill();g.stroke();} function pseudoPrism(){dots[1].y=Math.min(my.bt,dots[1].y) var ht=dots[1].y-my.bt var backX=-ht*1.5 dots[1].x=Math.max(my.midx+backX/2,dots[1].x) var wd=dots[1].x-my.midx var backY=ht wd-=backX/2 var baseMidy=my.bt+backY/2 dots[0].y=Math.min(baseMidy,dots[0].y) var xLtFt=my.midx-wd-backX/2 var xLtBk=xLtFt+backX;var xRtFt=my.midx+wd-backX/2 var xRtBk=xRtFt+backX;var yUpFt=dots[0].y-backY/2 var yUpBk=yUpFt+backY var yDnFt=my.bt;var yDnBk=yDnFt+backY var offx=dots[0].x-(xLtFt+xRtBk)/2 g.strokeStyle='rgba(0,0,255,1)';g.lineWidth=1;g.beginPath();g.setLineDash([5,5]) g.moveTo(dots[0].x,dots[0].y);g.lineTo(dots[0].x,baseMidy);g.stroke();g.beginPath();g.moveTo(dots[0].x-20,baseMidy);g.lineTo(dots[0].x+20,baseMidy);g.stroke() g.setLineDash([]) g.fillStyle='hsla(240,100%,80%,0.8)';g.beginPath();g.moveTo(xLtFt,yDnFt);g.lineTo(xRtFt,yDnFt);g.lineTo(xRtBk,yDnBk);g.lineTo(xLtBk,yDnBk);g.closePath() g.stroke();g.beginPath();g.fillStyle='hsla(240,100%,90%,0.6)';g.moveTo(xLtBk,yDnBk);g.lineTo(xRtBk,yDnBk);g.lineTo(xRtBk+offx,yUpBk);g.lineTo(xLtBk+offx,yUpBk);g.closePath() g.fill();g.stroke();g.beginPath();g.fillStyle='hsla(240,100%,90%,0.5)';g.moveTo(xLtFt,yDnFt);g.lineTo(xLtBk,yDnBk);g.lineTo(xLtBk+offx,yUpBk);g.lineTo(xLtFt+offx,yUpFt);g.closePath() g.fill();g.stroke();g.beginPath();g.fillStyle='hsla(240,100%,90%,0.6)';g.lineTo(xRtFt,yDnFt);g.lineTo(xRtFt+offx,yUpFt);g.lineTo(xLtFt+offx,yUpFt);g.lineTo(xLtFt,yDnFt);g.beginPath();g.fillStyle='hsla(60,100%,90%,0.6)';g.moveTo(xLtFt+offx,yUpFt);g.lineTo(xRtFt+offx,yUpFt);g.lineTo(xRtBk+offx,yUpBk);g.lineTo(xLtBk+offx,yUpBk);g.closePath() g.fill();g.stroke();g.beginPath();g.fillStyle='hsla(240,100%,80%,0.6)';g.lineTo(xRtFt,yDnFt);g.lineTo(xRtBk,yDnBk);g.lineTo(xRtBk+offx,yUpBk);g.lineTo(xRtFt+offx,yUpFt);g.closePath() g.fill();g.stroke();if(my.volQ){g.font="14px Arial";g.fillStyle='black';var shapeWd=Math.round(xRtFt-xLtFt)/10 g.beginPath();g.fillText(shapeWd,xLtFt+(xRtFt-xLtFt)/2,yDnFt+16) g.fill();var shapeHt=Math.round(baseMidy-dots[0].y)/10 g.beginPath();g.fillText(shapeHt,dots[0].x,dots[0].y+(baseMidy-dots[0].y)/2+16) g.fill();var shapeDp=Math.round(dist(xRtFt-xRtBk,yDnFt-yDnBk))/10 g.beginPath();g.fillText(shapeDp,xRtFt-(xRtFt-xRtBk)/2+8,yDnFt-(yDnFt-yDnBk)/2+8) g.fill();var vol=shapeWd*shapeDp*shapeHt vol=Math.round(vol*10)/10 var s='Volume = '+shapeWd+' × '+shapeDp+' × '+shapeHt+' ≈ '+vol document.getElementById('descr').innerHTML=s}} function pseudoPyr(){dots[1].y=Math.min(my.bt,dots[1].y) var ht=dots[1].y-my.bt var backX=-ht*1.5 dots[1].x=Math.max(my.midx+backX/2,dots[1].x) var wd=dots[1].x-my.midx var backY=ht wd-=backX/2 var xLtFt=my.midx-wd-backX/2 var xLtBk=xLtFt+backX;var xRtFt=my.midx+wd-backX/2 var xRtBk=xRtFt+backX;var yDnFt=my.bt;var yDnBk=yDnFt+backY;var baseMidy=my.bt+backY/2 dots[0].y=Math.min(baseMidy,dots[0].y) var xTp=dots[0].x var yTp=dots[0].y g.strokeStyle='rgba(0,0,255,1)';g.lineWidth=1;g.beginPath();g.setLineDash([5,5]) g.moveTo(xTp,yTp);g.lineTo(xTp,baseMidy);g.stroke();g.beginPath();g.moveTo(xTp-20,baseMidy);g.lineTo(xTp+20,baseMidy);g.stroke() g.setLineDash([]) g.fillStyle='hsla(240,100%,80%,0.8)';g.beginPath();g.moveTo(xLtFt,yDnFt);g.lineTo(xRtFt,yDnFt);g.lineTo(xRtBk,yDnBk);g.lineTo(xLtBk,yDnBk);g.closePath() g.stroke();g.beginPath();g.fillStyle='hsla(240,100%,90%,0.6)';g.moveTo(xLtBk,yDnBk);g.lineTo(xRtBk,yDnBk);g.lineTo(xTp,yTp);g.closePath() g.fill();g.stroke();g.beginPath();g.fillStyle='hsla(240,100%,90%,0.5)';g.moveTo(xLtFt,yDnFt);g.lineTo(xLtBk,yDnBk);g.lineTo(xTp,yTp);g.closePath() g.fill();g.stroke();g.beginPath();g.fillStyle='hsla(60,100%,90%,0.6)';g.moveTo(xLtFt,yDnFt);g.lineTo(xRtFt,yDnFt);g.lineTo(xTp,yTp);g.closePath() g.fill();g.stroke();g.beginPath();g.fillStyle='hsla(240,100%,80%,0.6)';g.moveTo(xRtFt,yDnFt);g.lineTo(xRtBk,yDnBk);g.lineTo(xTp,yTp);g.closePath() g.fill();g.stroke();if(my.volQ){g.font="14px Arial";g.fillStyle='black';var shapeWd=Math.round(xRtFt-xLtFt)/10 g.beginPath();g.fillText(shapeWd,xLtFt+(xRtFt-xLtFt)/2,yDnFt+16) g.fill();var shapeHt=Math.round(baseMidy-yTp)/10 g.beginPath();g.fillText(shapeHt,xTp,yTp+(baseMidy-yTp)/2+16) g.fill();var shapeDp=Math.round(dist(xRtFt-xRtBk,yDnFt-yDnBk))/10 g.beginPath();g.fillText(shapeDp,xRtFt-(xRtFt-xRtBk)/2+8,yDnFt-(yDnFt-yDnBk)/2+8) g.fill();var vol=shapeWd*shapeDp*shapeHt/3 vol=Math.round(vol*10)/10 var s='Volume = 1/3 × '+shapeWd+' × '+shapeDp+' × '+shapeHt+' ≈ '+vol document.getElementById('descr').innerHTML=s}} function drawEllipseRadius(g,x,y,rx,ry,angFrom,angTo,sgm){angFrom=typeof angFrom!=='undefined'?angFrom:0 angTo=typeof angTo!=='undefined'?angTo:2*Math.PI sgm=typeof sgm!=='undefined'?sgm:8;var sgmAngle=(angTo-angFrom)/sgm;var cRangle=sgmAngle/2;var cRx=rx/Math.cos(cRangle);var cRy=ry/Math.cos(cRangle);for(var i=0;i<=sgm;i++){var angle=angFrom+i*sgmAngle var cX=x+Math.cos(angle-cRangle)*cRx;var cY=y+Math.sin(angle-cRangle)*cRy;var pX=x+Math.cos(angle)*rx;var pY=y+Math.sin(angle)*ry;if(i==0){g.lineTo(pX,pY);}else{g.quadraticCurveTo(cX,cY,pX,pY);}}} function getArcPts(midX,midY,radiusX,radiusY,fromAngle,toAngle,segN){if(typeof fromAngle=='undefined'){fromAngle=0 toAngle=2*Math.PI segN=20}else{segN=typeof segN!=='undefined'?segN:8;if(radiusX!=radiusY){fromAngle=Math.atan2(Math.sin(fromAngle)*radiusX/radiusY,Math.cos(fromAngle));toAngle=Math.atan2(Math.sin(toAngle)*radiusX/radiusY,Math.cos(toAngle));console.log("getArcPts:",fromAngle,toAngle);}} var pts=[];var steps=segN;for(var i=0;i<=steps;i++){var radians=fromAngle+(toAngle-fromAngle)*(i/steps);console.log('>>',i,radians) var thisX=midX+(Math.cos(radians)*radiusX);var thisY=midY-(Math.sin(radians)*radiusY);pts.push(new Pt(thisX,thisY));} return pts;} function dotsMake(){var i;dots=[];for(i=0;ihighestIndex){drag.hold.x=mouseX-dots[i].x;drag.hold.y=mouseY-dots[i].y;highestIndex=i;dragIndex=i;}}} if(dragging){if(evt.touchQ){window.addEventListener('touchmove',onTouchMove,false);}else{window.addEventListener("mousemove",onMouseMove,false);}} if(evt.touchQ){el.removeEventListener("touchstart",onTouchStart,false);window.addEventListener("touchend",onTouchEnd,false);}else{el.removeEventListener("mousedown",onMouseDown,false);window.addEventListener("mouseup",onMouseUp,false);} if(evt.preventDefault){evt.preventDefault();} else if(evt.returnValue){evt.returnValue=false;} return false;} function onMouseUp(){if(my.playQ)return el.addEventListener("mousedown",onMouseDown,false);window.removeEventListener("mouseup",onMouseUp,false);if(dragging){dragging=false;window.removeEventListener("mousemove",onMouseMove,false);}} function onMouseMove(evt){if(my.playQ)return var posX;var posY;var minX=my.dotRad;var maxX=el.width-my.dotRad;var minY=my.dotRad;var maxY=el.height-my.dotRad;var bRect=el.getBoundingClientRect();var mouseX=(evt.clientX-bRect.left)*(el.width/ratio/bRect.width);var mouseY=(evt.clientY-bRect.top)*(el.height/ratio/bRect.height);posX=mouseX-drag.hold.x;posX=(posXmaxX)?maxX:posX);posY=mouseY-drag.hold.y;posY=(posYmaxY)?maxY:posY);if(dragging){dots[dragIndex].x=posX;dots[dragIndex].y=posY;} update();} function hitTest(shape,x,y){var dx;var dy;dx=x-shape.x;dy=y-shape.y;return(dx*dx+dy*dymaxNo){currNo=minNo+(currNo-minNo)%range;} return currNo;} function Line(pt1,pt2){this.a=pt1;this.b=pt2;} Line.prototype.getIntersection=function(ln,asSegmentsQ){var A=this.a;var B=this.b;var E=ln.a;var F=ln.b;var a1=B.y-A.y;var b1=A.x-B.x;var c1=B.x*A.y-A.x*B.y;var a2=F.y-E.y;var b2=E.x-F.x;var c2=F.x*E.y-E.x*F.y;var denom=a1*b2-a2*b1;if(denom==0){return null;} var ip={x:(b1*c2-b2*c1)/denom,y:(a2*c1-a1*c2)/denom} if(asSegmentsQ){if(Math.pow(ip.x-B.x,2)+Math.pow(ip.y-B.y,2)>Math.pow(A.x-B.x,2)+Math.pow(A.y-B.y,2)){return null;} if(Math.pow(ip.x-A.x,2)+Math.pow(ip.y-A.y,2)>Math.pow(A.x-B.x,2)+Math.pow(A.y-B.y,2)){return null;} if(Math.pow(ip.x-F.x,2)+Math.pow(ip.y-F.y,2)>Math.pow(E.x-F.x,2)+Math.pow(E.y-F.y,2)){return null;} if(Math.pow(ip.x-E.x,2)+Math.pow(ip.y-E.y,2)>Math.pow(E.x-F.x,2)+Math.pow(E.y-F.y,2)){return null;}} return ip;}