// created by florian berger (flockaroo) - 2018 // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. // utah teapot with truchet pattern // using slight adaptations of reinder's occlusion from "Cubic space division #2" // to enable culling/drawing of poly and to not-close poly Canvas.setpenopacity(1.); // Global code will be evaluated once. const turtle = new Turtle(); const polygonList = []; const quads = []; const nx=12; const ny=8; function walk(i) { return walkCull(i); } function walkCull(i) { var PatchNum = TeapotPatchNum; var num = nx*ny*PatchNum; if(i==0){ for(let j=0;j<num;j++) { var face = teapotFace(nx,ny,j); var p0=face[0]; var p1=face[1]; var p2=face[2]; var p3=face[3]; var c=scale3(add3(add3(add3(p0,p1),p2),p3),1.0/4.0); p0=transformAll(p0); p1=transformAll(p1); p2=transformAll(p2); p3=transformAll(p3); //if(cross(sub3(p1,p0),sub3(p2,p0))[2]<0.0) { insertQuad(p0,p2,p3,p1); } } } var p0=[quads[i*9+0],quads[i*9+1]]; var p1=[quads[i*9+2],quads[i*9+3]]; var p2=[quads[i*9+4],quads[i*9+5]]; var p3=[quads[i*9+6],quads[i*9+7]]; const p = new Polygon(); p.cp.push([p0[0], p0[1]]); p.cp.push([p1[0], p1[1]]); p.cp.push([p2[0], p2[1]]); p.cp.push([p3[0], p3[1]]); p.addOutline(0); var r=Math.random()*4.; if(drawPolygon(turtle, p, false, false)) { drawTruch([p0,p1,p2,p3],r); drawPolygon(turtle, p, false, true); } return i <= num; } // The walk function will be called until it returns false. function walkNoCull(i) { var PatchNum = TeapotPatchNum; var face = teapotFace(nx,ny,i); var p0=face[0]; var p1=face[1]; var p2=face[2]; var p3=face[3]; var c=scale3(add3(add3(add3(p0,p1),p2),p3),1.0/4.0); p0=add3(c,scale3(sub3(p0,c),1.)); p1=add3(c,scale3(sub3(p1,c),1.)); p2=add3(c,scale3(sub3(p2,c),1.)); p3=add3(c,scale3(sub3(p3,c),1.)); p0=transformAll(p0); p1=transformAll(p1); p2=transformAll(p2); p3=transformAll(p3); var r=Math.random()*4.; // draw front faces 3 times - not very efficent (at least for the turtle) if(cross(sub3(p1,p0),sub3(p2,p0))[2]<0.0) { drawTruch([p0,p1,p3,p2],r); } return i < nx*ny*PatchNum; } function drawTruch(pi,r) { var i0=Math.floor(0.0+r)%4; var i1=Math.floor(1.0+r)%4; var i2=Math.floor(3.0+r)%4; var i3=Math.floor(2.0+r)%4; for(var j=0;j<2;j++) { var d=.3+.4*j; var c01=mix3(pi[i0],pi[i1],d); var c23=mix3(pi[i2],pi[i3],d); var c02=mix3(pi[i0],pi[i2],d); var c13=mix3(pi[i1],pi[i3],d); var t1=scale3(sub3(c23,c01),.5*(d)); var t2=scale3(sub3(c13,c02),.5*(d)); var t3=scale3(sub3(c23,c01),.5*(1.-d)); var t4=scale3(sub3(c13,c02),.5*(1.-d)); p=[ c01, add3(c01,t1), add3(c02,t2), c02 ]; var po = new Polygon(); po.cp.push([p[0][0], p[0][1]]); for(var i=1;i<=6;i++) { var pa=bezierCurvePos(p, i/6.0); po.cp.push([pa[0], pa[1]]) } po.addOutline(0,1); drawPolygon(turtle, po, true, false); po = new Polygon(); p=[ c13, sub3(c13,t4), sub3(c23,t3), c23 ]; po.cp.push([p[0][0], p[0][1]]); for(var i=1;i<=6;i++) { var pa=bezierCurvePos(p, i/6.0); po.cp.push([pa[0], pa[1]]) } po.addOutline(0,1); drawPolygon(turtle, po, true, false); } } function transformAll(p) { p=add3(p,vec3(0,0,-1.2)); p=scale3(p,22.0); p=rotZ(2.7,p); p=rotX(-2.2,p); p=project(p); return p; } function insertQuad(p0,p1,p2,p3) { var z = p0[2]+p1[2]+p2[2]+p3[2]; var idx=0; for(idx=0;idx<quads.length && quads[idx+8]<z;idx+=9); // hmm, why is the one below not working... !? //for(var i=0;i<quads.length;i+=9) { // if(quads[i+8]>z) { idx=i; break; } //} quads.splice(idx, 0, p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], p3[0], p3[1], z); } function project(p) { p[2]+=180; return [p[0]/p[2]*180.,p[1]/p[2]*180.,p[2]]; } // cubic bezier curve in 2 dimensions // equivalent to the function above, just in a more intuitive form function bezierCurvePos(p, t) { // combination of 2 quadric beziers var q=[]; var r=[]; for(var i=0;i<3;i++) q.push(mix3(p[i],p[i+1],t)); for(var i=0;i<2;i++) r.push(mix3(q[i],q[i+1],t)); return mix3(r[0],r[1],t); } // cubic bezier patch in 3 dimensions function bezierPatchPos(p, uv) { var curve = []; // cubic interpolation of control points in 1st parameter for (var i = 0; i < 4; i++) { curve.push( bezierCurvePos([p[i*4],p[i*4+1],p[i*4+2],p[i*4+3]], uv[0]) ); } // actual cubic bezier in 2nd parameter return bezierCurvePos(curve, uv[1]); } function getTorusPoint(i,R,r,nph,nth) { th=i/nth*Math.PI*2.0; ph=th/nph; return[(R+r*mcos(th))*mcos(ph),(R+r*mcos(th))*msin(ph),r*msin(th)]; } function teapotFace(pnum_x, pnum_y, idx) { // only write data if index is smaller than total vertex count of teapot if(idx>TeapotPatchNum*pnum_x*pnum_y) return [[0,0,0],[0,0,0],[0,0,0],[0,0,0]]; var patchIdx = Math.floor(idx/(pnum_x*pnum_y)); // the actual patch of this vertex var vIdx = idx%(pnum_x*pnum_y); // the vertex id within this patch // get the control points var pIndices = getPatchIndices(patchIdx); if (!pIndices) return [[0,0,0],[0,0,0],[0,0,0],[0,0,0]]; var p = []; for(var i=0; i<16; i++) p.push(getTeapotPoint(pIndices[i]-1)); // construct the quad // ...first the 2D bezier parameters of each edge // (we give those back as uv-coords) var qIdx=vIdx; var qp=vec2(qIdx%pnum_x,Math.floor(qIdx/pnum_x)); var uv1 = div2(add2(qp,vec2(0,0)),vec2(pnum_x,pnum_y)); var uv2 = div2(add2(qp,vec2(1,0)),vec2(pnum_x,pnum_y)); var uv3 = div2(add2(qp,vec2(0,1)),vec2(pnum_x,pnum_y)); var uv4 = div2(add2(qp,vec2(1,1)),vec2(pnum_x,pnum_y)); // ...then get each edge point var p1=bezierPatchPos(p,uv1); var p2=bezierPatchPos(p,uv2); var p3=bezierPatchPos(p,uv3); var p4=bezierPatchPos(p,uv4); // use eps,eps and -eps,eps instead of eps,0 and 0,eps to avoid 0-normals /*var eps=.001; var n1=cross(sub3(p1,bezierPatchPos(p,add2(uv1,vec2(eps,eps)))),sub3(p1,bezierPatchPos(p,add2(uv1,vec2(-eps,eps))))); var n2=cross(sub3(p2,bezierPatchPos(p,add2(uv2,vec2(eps,eps)))),sub3(p2,bezierPatchPos(p,add2(uv2,vec2(-eps,eps))))); var n3=cross(sub3(p3,bezierPatchPos(p,add2(uv3,vec2(eps,eps)))),sub3(p3,bezierPatchPos(p,add2(uv3,vec2(-eps,eps))))); var n4=cross(sub3(p4,bezierPatchPos(p,add2(uv4,vec2(eps,eps)))),sub3(p4,bezierPatchPos(p,add2(uv4,vec2(-eps,eps))))); n1 = normalize3(n1); n2 = normalize3(n2); n3 = normalize3(n3); n4 = normalize3(n4);*/ /*var nph= pnum_x; var nth= pnum_y; return [ getTorusPoint(idx, 50,20,nph,nth), getTorusPoint(idx+1, 50,20,nph,nth), getTorusPoint(idx+nth, 50,20,nph,nth), getTorusPoint(idx+1+nth,50,20,nph,nth) ];*/ return [p1,p2,p3,p4/*, n1,n2,n3,n4, uv1,uv2,uv3,uv4*/]; } function mymix(a,b,f) { return a*(1.0-f)+b*f; } function mcos(x) { return Math.cos(x); } function msin(x) { return Math.sin(x); } function vec3(x,y,z) { return [x,y,z]; } function add3(a,b) { return [a[0]+b[0],a[1]+b[1],a[2]+b[2]]; } function sub3(a,b) { return [a[0]-b[0],a[1]-b[1],a[2]-b[2]]; } function div3(a,b) { return [a[0]/b[0],a[1]/b[1],a[2]/b[2]]; } function mul3(a,b) { return [a[0]*b[0],a[1]*b[1],a[2]*b[2]]; } function dot3(a,b) { return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; } function scale3(a,b) { return [a[0]*b,a[1]*b,a[2]*b]; } function length3(a) { return Math.sqrt(dot3(a,a)); } function normalize3(a) { return scale3(a,1.0/length3(a)); } function mix3(a,b,f) { return add3(scale3(a,(1.0-f)),scale3(b,f)); } function vec2(x,y) { return [x,y]; } function add2(a,b) { return [a[0]+b[0],a[1]+b[1]]; } function sub2(a,b) { return [a[0]-b[0],a[1]-b[1]]; } function div2(a,b) { return [a[0]/b[0],a[1]/b[1]]; } function mul2(a,b) { return [a[0]*b[0],a[1]*b[1]]; } function dot2(a,b) { return a[0]*b[0]+a[1]*b[1]; } function scale2(a,b) { return [a[0]*b,a[1]*b]; } function length2(a) { return Math.sqrt(dot2(a,a)); } function normalize2(a) { return scale2(a,1.0/length2(a)); } function mix2(a,b,f) { return add2(scale2(a,(1.0-f)),scale2(b,f)); } function cross(a,b) { return [ a[1]*b[2]-b[1]*a[2], a[2]*b[0]-b[2]*a[0], a[0]*b[1]-b[0]*a[1] ]; } function rotX(ph,v) { return [ v[0],v[1]*mcos(ph)+v[2]*msin(ph), v[2]*mcos(ph)-v[1]*msin(ph) ]; } function rotZ(ph,v) { return [ v[0]*mcos(ph)+v[1]*msin(ph), v[1]*mcos(ph)-v[0]*msin(ph), v[2] ]; } // teapot data.... const TeapotPatchNum=32 function getPatchIndices(pIdx) { return teapot_indices[pIdx]; } function getTeapotPoint(idx) { return teapot_points[idx]; } const teapot_indices = [ // the 32 teapot patches [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], [4,17,18,19,8,20,21,22,12,23,24,25,16,26,27,28], [19,29,30,31,22,32,33,34,25,35,36,37,28,38,39,40], [31,41,42,1,34,43,44,5,37,45,46,9,40,47,48,13], [13,14,15,16,49,50,51,52,53,54,55,56,57,58,59,60], [16,26,27,28,52,61,62,63,56,64,65,66,60,67,68,69], [28,38,39,40,63,70,71,72,66,73,74,75,69,76,77,78], [40,47,48,13,72,79,80,49,75,81,82,53,78,83,84,57], [57,58,59,60,85,86,87,88,89,90,91,92,93,94,95,96], [60,67,68,69,88,97,98,99,92,100,101,102,96,103,104,105], [69,76,77,78,99,106,107,108,102,109,110,111,105,112,113,114], [78,83,84,57,108,115,116,85,111,117,118,89,114,119,120,93], [121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136], [124,137,138,121,128,139,140,125,132,141,142,129,136,143,144,133], [133,134,135,136,145,146,147,148,149,150,151,152,69,153,154,155], [136,143,144,133,148,156,157,145,152,158,159,149,155,160,161,69], [162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177], [165,178,179,162,169,180,181,166,173,182,183,170,177,184,185,174], [174,175,176,177,186,187,188,189,190,191,192,193,194,195,196,197], [177,184,185,174,189,198,199,186,193,200,201,190,197,202,203,194], [204,204,204,204,207,208,209,210,211,211,211,211,212,213,214,215], [204,204,204,204,210,217,218,219,211,211,211,211,215,220,221,222], [204,204,204,204,219,224,225,226,211,211,211,211,222,227,228,229], [204,204,204,204,226,230,231,207,211,211,211,211,229,232,233,212], [212,213,214,215,234,235,236,237,238,239,240,241,242,243,244,245], [215,220,221,222,237,246,247,248,241,249,250,251,245,252,253,254], [222,227,228,229,248,255,256,257,251,258,259,260,254,261,262,263], [229,232,233,212,257,264,265,234,260,266,267,238,263,268,269,242], [270,270,270,270,279,280,281,282,275,276,277,278,271,272,273,274], [270,270,270,270,282,289,290,291,278,286,287,288,274,283,284,285], [270,270,270,270,291,298,299,300,288,295,296,297,285,292,293,294], [270,270,270,270,300,305,306,279,297,303,304,275,294,301,302,271] ]; teapot_points = [ // the 306 teapot points vec3(1.4,0.0,2.4 ), vec3(1.4,-0.784,2.4 ), vec3(0.784,-1.4,2.4 ), vec3(0.0,-1.4,2.4 ), vec3(1.3375,0.0,2.53125 ), vec3(1.3375,-0.749,2.53125 ), vec3(0.749,-1.3375,2.53125 ), vec3(0.0,-1.3375,2.53125 ), vec3(1.4375,0.0,2.53125 ), vec3(1.4375,-0.805,2.53125 ), vec3(0.805,-1.4375,2.53125 ), vec3(0.0,-1.4375,2.53125 ), vec3(1.5,0.0,2.4 ), vec3(1.5,-0.84,2.4 ), vec3(0.84,-1.5,2.4 ), vec3(0.0,-1.5,2.4 ), vec3(-0.784,-1.4,2.4 ), vec3(-1.4,-0.784,2.4 ), vec3(-1.4,0.0,2.4 ), vec3(-0.749,-1.3375,2.53125 ), vec3(-1.3375,-0.749,2.53125 ), vec3(-1.3375,0.0,2.53125 ), vec3(-0.805,-1.4375,2.53125 ), vec3(-1.4375,-0.805,2.53125 ), vec3(-1.4375,0.0,2.53125 ), vec3(-0.84,-1.5,2.4 ), vec3(-1.5,-0.84,2.4 ), vec3(-1.5,0.0,2.4 ), vec3(-1.4,0.784,2.4 ), vec3(-0.784,1.4,2.4 ), vec3(0.0,1.4,2.4 ), vec3(-1.3375,0.749,2.53125 ), vec3(-0.749,1.3375,2.53125 ), vec3(0.0,1.3375,2.53125 ), vec3(-1.4375,0.805,2.53125 ), vec3(-0.805,1.4375,2.53125 ), vec3(0.0,1.4375,2.53125 ), vec3(-1.5,0.84,2.4 ), vec3(-0.84,1.5,2.4 ), vec3(0.0,1.5,2.4 ), vec3(0.784,1.4,2.4 ), vec3(1.4,0.784,2.4 ), vec3(0.749,1.3375,2.53125 ), vec3(1.3375,0.749,2.53125 ), vec3(0.805,1.4375,2.53125 ), vec3(1.4375,0.805,2.53125 ), vec3(0.84,1.5,2.4 ), vec3(1.5,0.84,2.4 ), vec3(1.75,0.0,1.875 ), vec3(1.75,-0.98,1.875 ), vec3(0.98,-1.75,1.875 ), vec3(0.0,-1.75,1.875 ), vec3(2.0,0.0,1.35 ), vec3(2.0,-1.12,1.35 ), vec3(1.12,-2.0,1.35 ), vec3(0.0,-2.0,1.35 ), vec3(2.0,0.0,0.9 ), vec3(2.0,-1.12,0.9 ), vec3(1.12,-2.0,0.9 ), vec3(0.0,-2.0,0.9 ), vec3(-0.98,-1.75,1.875 ), vec3(-1.75,-0.98,1.875 ), vec3(-1.75,0.0,1.875 ), vec3(-1.12,-2.0,1.35 ), vec3(-2.0,-1.12,1.35 ), vec3(-2.0,0.0,1.35 ), vec3(-1.12,-2.0,0.9 ), vec3(-2.0,-1.12,0.9 ), vec3(-2.0,0.0,0.9 ), vec3(-1.75,0.98,1.875 ), vec3(-0.98,1.75,1.875 ), vec3(0.0,1.75,1.875 ), vec3(-2.0,1.12,1.35 ), vec3(-1.12,2.0,1.35 ), vec3(0.0,2.0,1.35 ), vec3(-2.0,1.12,0.9 ), vec3(-1.12,2.0,0.9 ), vec3(0.0,2.0,0.9 ), vec3(0.98,1.75,1.875 ), vec3(1.75,0.98,1.875 ), vec3(1.12,2.0,1.35 ), vec3(2.0,1.12,1.35 ), vec3(1.12,2.0,0.9 ), vec3(2.0,1.12,0.9 ), vec3(2.0,0.0,0.45 ), vec3(2.0,-1.12,0.45 ), vec3(1.12,-2.0,0.45 ), vec3(0.0,-2.0,0.45 ), vec3(1.5,0.0,0.225 ), vec3(1.5,-0.84,0.225 ), vec3(0.84,-1.5,0.225 ), vec3(0.0,-1.5,0.225 ), vec3(1.5,0.0,0.15 ), vec3(1.5,-0.84,0.15 ), vec3(0.84,-1.5,0.15 ), vec3(0.0,-1.5,0.15 ), vec3(-1.12,-2.0,0.45 ), vec3(-2.0,-1.12,0.45 ), vec3(-2.0,0.0,0.45 ), vec3(-0.84,-1.5,0.225 ), vec3(-1.5,-0.84,0.225 ), vec3(-1.5,0.0,0.225 ), vec3(-0.84,-1.5,0.15 ), vec3(-1.5,-0.84,0.15 ), vec3(-1.5,0.0,0.15 ), vec3(-2.0,1.12,0.45 ), vec3(-1.12,2.0,0.45 ), vec3(0.0,2.0,0.45 ), vec3(-1.5,0.84,0.225 ), vec3(-0.84,1.5,0.225 ), vec3(0.0,1.5,0.225 ), vec3(-1.5,0.84,0.15 ), vec3(-0.84,1.5,0.15 ), vec3(0.0,1.5,0.15 ), vec3(1.12,2.0,0.45 ), vec3(2.0,1.12,0.45 ), vec3(0.84,1.5,0.225 ), vec3(1.5,0.84,0.225 ), vec3(0.84,1.5,0.15 ), vec3(1.5,0.84,0.15 ), vec3(-1.6,0.0,2.025 ), vec3(-1.6,-0.3,2.025 ), vec3(-1.5,-0.3,2.25 ), vec3(-1.5,0.0,2.25 ), vec3(-2.3,0.0,2.025 ), vec3(-2.3,-0.3,2.025 ), vec3(-2.5,-0.3,2.25 ), vec3(-2.5,0.0,2.25 ), vec3(-2.7,0.0,2.025 ), vec3(-2.7,-0.3,2.025 ), vec3(-3.0,-0.3,2.25 ), vec3(-3.0,0.0,2.25 ), vec3(-2.7,0.0,1.8 ), vec3(-2.7,-0.3,1.8 ), vec3(-3.0,-0.3,1.8 ), vec3(-3.0,0.0,1.8 ), vec3(-1.5,0.3,2.25 ), vec3(-1.6,0.3,2.025 ), vec3(-2.5,0.3,2.25 ), vec3(-2.3,0.3,2.025 ), vec3(-3.0,0.3,2.25 ), vec3(-2.7,0.3,2.025 ), vec3(-3.0,0.3,1.8 ), vec3(-2.7,0.3,1.8 ), vec3(-2.7,0.0,1.575 ), vec3(-2.7,-0.3,1.575 ), vec3(-3.0,-0.3,1.35 ), vec3(-3.0,0.0,1.35 ), vec3(-2.5,0.0,1.125 ), vec3(-2.5,-0.3,1.125 ), vec3(-2.65,-0.3,0.9375 ), vec3(-2.65,0.0,0.9375 ), vec3(-2.0,-0.3,0.9 ), vec3(-1.9,-0.3,0.6 ), vec3(-1.9,0.0,0.6 ), vec3(-3.0,0.3,1.35 ), vec3(-2.7,0.3,1.575 ), vec3(-2.65,0.3,0.9375 ), vec3(-2.5,0.3,1.125 ), vec3(-1.9,0.3,0.6 ), vec3(-2.0,0.3,0.9 ), vec3(1.7,0.0,1.425 ), vec3(1.7,-0.66,1.425 ), vec3(1.7,-0.66,0.6 ), vec3(1.7,0.0,0.6 ), vec3(2.6,0.0,1.425 ), vec3(2.6,-0.66,1.425 ), vec3(3.1,-0.66,0.825 ), vec3(3.1,0.0,0.825 ), vec3(2.3,0.0,2.1 ), vec3(2.3,-0.25,2.1 ), vec3(2.4,-0.25,2.025 ), vec3(2.4,0.0,2.025 ), vec3(2.7,0.0,2.4 ), vec3(2.7,-0.25,2.4 ), vec3(3.3,-0.25,2.4 ), vec3(3.3,0.0,2.4 ), vec3(1.7,0.66,0.6 ), vec3(1.7,0.66,1.425 ), vec3(3.1,0.66,0.825 ), vec3(2.6,0.66,1.425 ), vec3(2.4,0.25,2.025 ), vec3(2.3,0.25,2.1 ), vec3(3.3,0.25,2.4 ), vec3(2.7,0.25,2.4 ), vec3(2.8,0.0,2.475 ), vec3(2.8,-0.25,2.475 ), vec3(3.525,-0.25,2.49375 ), vec3(3.525,0.0,2.49375 ), vec3(2.9,0.0,2.475 ), vec3(2.9,-0.15,2.475 ), vec3(3.45,-0.15,2.5125 ), vec3(3.45,0.0,2.5125 ), vec3(2.8,0.0,2.4 ), vec3(2.8,-0.15,2.4 ), vec3(3.2,-0.15,2.4 ), vec3(3.2,0.0,2.4 ), vec3(3.525,0.25,2.49375 ), vec3(2.8,0.25,2.475 ), vec3(3.45,0.15,2.5125 ), vec3(2.9,0.15,2.475 ), vec3(3.2,0.15,2.4 ), vec3(2.8,0.15,2.4 ), vec3(0.0,0.0,3.15 ), vec3(0.0,-0.002,3.15 ), vec3(0.002,0.0,3.15 ), vec3(0.8,0.0,3.15 ), vec3(0.8,-0.45,3.15 ), vec3(0.45,-0.8,3.15 ), vec3(0.0,-0.8,3.15 ), vec3(0.0,0.0,2.85 ), vec3(0.2,0.0,2.7 ), vec3(0.2,-0.112,2.7 ), vec3(0.112,-0.2,2.7 ), vec3(0.0,-0.2,2.7 ), vec3(-0.002,0.0,3.15 ), vec3(-0.45,-0.8,3.15 ), vec3(-0.8,-0.45,3.15 ), vec3(-0.8,0.0,3.15 ), vec3(-0.112,-0.2,2.7 ), vec3(-0.2,-0.112,2.7 ), vec3(-0.2,0.0,2.7 ), vec3(0.0,0.002,3.15 ), vec3(-0.8,0.45,3.15 ), vec3(-0.45,0.8,3.15 ), vec3(0.0,0.8,3.15 ), vec3(-0.2,0.112,2.7 ), vec3(-0.112,0.2,2.7 ), vec3(0.0,0.2,2.7 ), vec3(0.45,0.8,3.15 ), vec3(0.8,0.45,3.15 ), vec3(0.112,0.2,2.7 ), vec3(0.2,0.112,2.7 ), vec3(0.4,0.0,2.55 ), vec3(0.4,-0.224,2.55 ), vec3(0.224,-0.4,2.55 ), vec3(0.0,-0.4,2.55 ), vec3(1.3,0.0,2.55 ), vec3(1.3,-0.728,2.55 ), vec3(0.728,-1.3,2.55 ), vec3(0.0,-1.3,2.55 ), vec3(1.3,0.0,2.4 ), vec3(1.3,-0.728,2.4 ), vec3(0.728,-1.3,2.4 ), vec3(0.0,-1.3,2.4 ), vec3(-0.224,-0.4,2.55 ), vec3(-0.4,-0.224,2.55 ), vec3(-0.4,0.0,2.55 ), vec3(-0.728,-1.3,2.55 ), vec3(-1.3,-0.728,2.55 ), vec3(-1.3,0.0,2.55 ), vec3(-0.728,-1.3,2.4 ), vec3(-1.3,-0.728,2.4 ), vec3(-1.3,0.0,2.4 ), vec3(-0.4,0.224,2.55 ), vec3(-0.224,0.4,2.55 ), vec3(0.0,0.4,2.55 ), vec3(-1.3,0.728,2.55 ), vec3(-0.728,1.3,2.55 ), vec3(0.0,1.3,2.55 ), vec3(-1.3,0.728,2.4 ), vec3(-0.728,1.3,2.4 ), vec3(0.0,1.3,2.4 ), vec3(0.224,0.4,2.55 ), vec3(0.4,0.224,2.55 ), vec3(0.728,1.3,2.55 ), vec3(1.3,0.728,2.55 ), vec3(0.728,1.3,2.4 ), vec3(1.3,0.728,2.4 ), vec3(0.0,0.0,0.0 ), vec3(1.5,0.0,0.15 ), vec3(1.5,0.84,0.15 ), vec3(0.84,1.5,0.15 ), vec3(0.0,1.5,0.15 ), vec3(1.5,0.0,0.075 ), vec3(1.5,0.84,0.075 ), vec3(0.84,1.5,0.075 ), vec3(0.0,1.5,0.075 ), vec3(1.425,0.0,0.0 ), vec3(1.425,0.798,0.0 ), vec3(0.798,1.425,0.0 ), vec3(0.0,1.425,0.0 ), vec3(-0.84,1.5,0.15 ), vec3(-1.5,0.84,0.15 ), vec3(-1.5,0.0,0.15 ), vec3(-0.84,1.5,0.075 ), vec3(-1.5,0.84,0.075 ), vec3(-1.5,0.0,0.075 ), vec3(-0.798,1.425,0.0 ), vec3(-1.425,0.798,0.0 ), vec3(-1.425,0.0,0.0 ), vec3(-1.5,-0.84,0.15 ), vec3(-0.84,-1.5,0.15 ), vec3(0.0,-1.5,0.15 ), vec3(-1.5,-0.84,0.075 ), vec3(-0.84,-1.5,0.075 ), vec3(0.0,-1.5,0.075 ), vec3(-1.425,-0.798,0.0 ), vec3(-0.798,-1.425,0.0 ), vec3(0.0,-1.425,0.0 ), vec3(0.84,-1.5,0.15 ), vec3(1.5,-0.84,0.15 ), vec3(0.84,-1.5,0.075 ), vec3(1.5,-0.84,0.075 ), vec3(0.798,-1.425,0.0 ), vec3(1.425,-0.798,0.0 ) ]; //////////////////////////// // reinder's occlusion code parts from "Cubic space division #2" //////////////////////////// function drawPolygon(turtle, p, doDraw, doCull) { let vis = true; for (let j=0; j<polygonList.length; j++) { if(!p.boolean(polygonList[j])) { vis = false; break; } } if (vis) { if(doDraw) p.draw(turtle, 0); if(doCull) polygonList.push(p); return true; } return false; } // polygon functions function LineSegment(p1, p2) { this.p1 = p1; this.p2 = p2; } function Polygon() { this.cp = []; // clip path: array of [x,y] pairs this.dp = []; // 2d line to draw: array of linesegments } Polygon.prototype.addOutline = function(s=0,e=0) { for (let i=s, l=this.cp.length; i<l-e; i++) { this.dp.push(new LineSegment(this.cp[i], this.cp[(i+1)%l])); } } Polygon.prototype.createPoly = function(x,y,c,r,a) { this.cp = []; for (let i=0; i<c; i++) { this.cp.push( [x + Math.sin(i*Math.PI*2/c+a) * r, y + Math.cos(i*Math.PI*2/c+a) * r] ); } } Polygon.prototype.draw = function(t, inp=0) { if (this.dp.length ==0) { return; } for (let i=0, l=this.dp.length; i<l; i++) { const d = this.dp[i]; if (!vec2_equal(d.p1, t.pos())) { t.penup(); t.goto([d.p1[0]+inp*(Math.random()-.5), d.p1[1]+inp*(Math.random()-.5)]); t.pendown(); } t.goto([d.p2[0]+inp*(Math.random()-.5), d.p2[1]+inp*(Math.random()-.5)]); } } Polygon.prototype.inside = function(p) { // find number of i ntersection points from p to far away // if even your outside const p1 = [0.1, -1000]; let int = 0; for (let i=0, l=this.cp.length; i<l; i++) { if (vec2_find_segment_intersect(p, p1, this.cp[i], this.cp[(i+1)%l])) { int ++; } } return int & 1; } Polygon.prototype.boolean = function(p, diff = true) { // very naive polygon diff algorithm - made this up myself const ndp = []; for (let i=0, l=this.dp.length; i<l; i++) { const ls = this.dp[i]; // find all intersections with clip path const int = []; for (let j=0, cl=p.cp.length; j<cl; j++) { const pint = vec2_find_segment_intersect(ls.p1,ls.p2,p.cp[j],p.cp[(j+1)%cl]); if (pint) { int.push(pint); } } if (int.length == 0) { // 0 intersections, inside or outside? if (diff == !p.inside(ls.p1)) { ndp.push(ls); } } else { int.push(ls.p1); int.push(ls.p2); // order intersection points on line ls.p1 to ls.p2 const cmp = [ls.p2[0]-ls.p1[0], ls.p2[1]-ls.p1[1]]; int.sort( (a,b) => { const db = vec2_dot([b[0]-ls.p1[0], b[1]-ls.p1[1]], cmp); const da = vec2_dot([a[0]-ls.p1[0], a[1]-ls.p1[1]], cmp); return da - db; }); for (let j=0; j<int.length-1; j++) { if (!vec2_equal(int[j], int[j+1])) { if (diff == !p.inside([(int[j][0]+int[j+1][0])/2,(int[j][1]+int[j+1][1])/2])) { ndp.push(new LineSegment(int[j], int[j+1])); } } } } } this.dp = ndp; return this.dp.length > 0; } // vec functions const vec2_equal = (a,b) => vec2_dist_sqr(a,b) < 0.01; const vec2_dot = (a, b) => a[0]*b[0]+a[1]*b[1]; const vec2_dist_sqr = (a, b) => (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]); //port of http://paulbourke.net/geometry/pointlineplane/Helpers.cs function vec2_find_segment_intersect(l1p1, l1p2, l2p1, l2p2) { const d = (l2p2[1] - l2p1[1]) * (l1p2[0] - l1p1[0]) - (l2p2[0] - l2p1[0]) * (l1p2[1] - l1p1[1]); const n_a = (l2p2[0] - l2p1[0]) * (l1p1[1] - l2p1[1]) - (l2p2[1] - l2p1[1]) * (l1p1[0] - l2p1[0]); const n_b = (l1p2[0] - l1p1[0]) * (l1p1[1] - l2p1[1]) - (l1p2[1] - l1p1[1]) * (l1p1[0] - l2p1[0]); if (d == 0) { return false; } const ua = n_a / d; const ub = n_b / d; if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) { return [l1p1[0] + (ua * (l1p2[0] - l1p1[0])), l1p1[1] + (ua * (l1p2[1] - l1p1[1])) ]; } return false; }